Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1029 lines
32 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. digidev.cpp
  5. Abstract:
  6. This module contains all the digitizer functions.
  7. Author:
  8. Michael Tsang (MikeTs) 01-Jun-2000
  9. Environment:
  10. User mode
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. /*++
  15. @doc INTERNAL
  16. @func BOOL | GetMinMax | Get the logical min & max for a report values.
  17. @parm IN USAGE | UsagePage | Specifies the UsagePage of the report.
  18. @parm IN USAGE | Usage | Specifies the Usage of the report.
  19. @parm OUT PULONG | pulMin | To hold the min value.
  20. @parm OUT PULONG | pulMax | To hold the max value.
  21. @rvalue SUCCESS | Returns TRUE.
  22. @rvalue FAILURE | Returns FALSE.
  23. --*/
  24. BOOL
  25. GetMinMax(
  26. IN USAGE UsagePage,
  27. IN USAGE Usage,
  28. OUT PULONG pulMin,
  29. OUT PULONG pulMax
  30. )
  31. {
  32. TRACEPROC("GetMinMax", 3)
  33. BOOL rc = FALSE;
  34. NTSTATUS status;
  35. HIDP_VALUE_CAPS ValueCaps;
  36. USHORT cValueCaps = 1;
  37. TRACEENTER(("(UsagePage=%x,Usage=%x,pulMin=%p,pulMax=%p)\n",
  38. UsagePage, Usage, pulMin, pulMax));
  39. status = HidP_GetSpecificValueCaps(HidP_Input,
  40. UsagePage,
  41. 0,
  42. Usage,
  43. &ValueCaps,
  44. &cValueCaps,
  45. gdevDigitizer.pPreParsedData);
  46. if ((status == HIDP_STATUS_SUCCESS) && (cValueCaps == 1))
  47. {
  48. if ((ValueCaps.LogicalMin >= 0) &&
  49. (ValueCaps.LogicalMax > ValueCaps.LogicalMin))
  50. {
  51. *pulMin = ValueCaps.LogicalMin;
  52. *pulMax = ValueCaps.LogicalMax;
  53. rc = TRUE;
  54. }
  55. }
  56. TRACEEXIT(("=%x\n", rc));
  57. return rc;
  58. } //GetMinMax
  59. /*++
  60. @doc INTERNAL
  61. @func VOID | ProcessDigitizerReport | Process a digitizer input report.
  62. @parm IN PCHAR | pBuff | Buffer containing report data.
  63. @rvalue None.
  64. --*/
  65. VOID
  66. ProcessDigitizerReport(
  67. IN PCHAR pBuff
  68. )
  69. {
  70. TRACEPROC("ProcessDigitizerReport", 5)
  71. NTSTATUS StatusX, StatusY, StatusBtn;
  72. DWORD dwCurrentTime;
  73. ULONG x, y;
  74. ULONG ulLength;
  75. TRACEENTER(("(pBuff=%p)\n", pBuff));
  76. dwCurrentTime = GetTickCount();
  77. StatusX = HidP_GetUsageValue(HidP_Input,
  78. HID_USAGE_PAGE_GENERIC,
  79. 0,
  80. HID_USAGE_GENERIC_X,
  81. &x,
  82. gdevDigitizer.pPreParsedData,
  83. pBuff,
  84. gdevDigitizer.hidCaps.InputReportByteLength);
  85. StatusY = HidP_GetUsageValue(HidP_Input,
  86. HID_USAGE_PAGE_GENERIC,
  87. 0,
  88. HID_USAGE_GENERIC_Y,
  89. &y,
  90. gdevDigitizer.pPreParsedData,
  91. pBuff,
  92. gdevDigitizer.hidCaps.InputReportByteLength);
  93. ulLength = gdevDigitizer.dwcButtons;// ulLength == max # possible buttons
  94. StatusBtn = HidP_GetButtons(HidP_Input,
  95. HID_USAGE_PAGE_DIGITIZER,
  96. 0,
  97. gdevDigitizer.pDownButtonUsages,
  98. &ulLength,
  99. gdevDigitizer.pPreParsedData,
  100. pBuff,
  101. gdevDigitizer.hidCaps.InputReportByteLength);
  102. if ((StatusX == HIDP_STATUS_SUCCESS) &&
  103. (StatusY == HIDP_STATUS_SUCCESS) &&
  104. (StatusBtn == HIDP_STATUS_SUCCESS))
  105. {
  106. ULONG i;
  107. WORD wCurrentButtons = 0;
  108. for (i = 0; i < ulLength; i++)
  109. {
  110. if (gdevDigitizer.pDownButtonUsages[i] ==
  111. HID_USAGE_DIGITIZER_TIP_SWITCH)
  112. {
  113. wCurrentButtons |= TIP_SWITCH;
  114. }
  115. else if (gdevDigitizer.pDownButtonUsages[i] ==
  116. HID_USAGE_DIGITIZER_BARREL_SWITCH)
  117. {
  118. wCurrentButtons |= BARREL_SWITCH;
  119. }
  120. }
  121. if ((gdwPenState == PENSTATE_PENDOWN) &&
  122. (dwCurrentTime - gdwPenDownTime >
  123. (DWORD)gConfig.GestureSettings.iPressHoldTime))
  124. {
  125. //
  126. // PressHold timer has expired, simulate a right down.
  127. //
  128. PressHoldMode(TRUE);
  129. }
  130. else if ((gdwPenState == PENSTATE_PRESSHOLD) &&
  131. (dwCurrentTime - gdwPenDownTime >
  132. (DWORD)gConfig.GestureSettings.iPressHoldTime +
  133. gConfig.GestureSettings.iCancelPressHoldTime))
  134. {
  135. TRACEINFO(3, ("Simulate a left-down on CancelPressHold timeout.\n"));
  136. gdwPenState = PENSTATE_NORMAL;
  137. SetPressHoldCursor(FALSE);
  138. gInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE |
  139. MOUSEEVENTF_MOVE |
  140. SWAPBUTTONS(giButtonsSwapped,
  141. MOUSEEVENTF_LEFTDOWN,
  142. MOUSEEVENTF_RIGHTDOWN);
  143. gInput.mi.dx = glPenDownX;
  144. gInput.mi.dy = glPenDownY;
  145. SendInput(1, &gInput, sizeof(INPUT));
  146. }
  147. else if ((gdwPenState == PENSTATE_LEFTUP_PENDING) &&
  148. (dwCurrentTime - gdwPenUpTime > TIMEOUT_LEFTCLICK))
  149. {
  150. //
  151. // Left up timer has expired, simulate a left up.
  152. //
  153. TRACEINFO(3, ("Simulate a left-up on timeout.\n"));
  154. gdwPenState = PENSTATE_NORMAL;
  155. gInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE |
  156. MOUSEEVENTF_MOVE |
  157. SWAPBUTTONS(giButtonsSwapped,
  158. MOUSEEVENTF_LEFTUP,
  159. MOUSEEVENTF_RIGHTUP);
  160. gInput.mi.dx = glPenUpX;
  161. gInput.mi.dy = glPenUpY;
  162. SendInput(1, &gInput, sizeof(INPUT));
  163. }
  164. //
  165. // If the report is the same as last, skip it.
  166. //
  167. if ((x != gLastRawDigiReport.wX) ||
  168. (y != gLastRawDigiReport.wY) ||
  169. (wCurrentButtons != gLastRawDigiReport.wButtonState))
  170. {
  171. //
  172. // Generate mouse movement info.
  173. //
  174. if (gdwfTabSrv & TSF_HAS_LINEAR_MAP)
  175. {
  176. gInput.mi.dx = x;
  177. gInput.mi.dy = y;
  178. AdjustLinearity((PUSHORT)&gInput.mi.dx, (PUSHORT)&gInput.mi.dy);
  179. }
  180. else
  181. {
  182. ULONG t;
  183. // Since we treat the digitizer as an 'absolute' pointing
  184. // device, both the X/Y coordinates must be scaled to a range
  185. // of 0 - 65535.
  186. // (((t = x - gdwMinX) << 16) - t) == ((x - gdwMinX) * 65535)
  187. // In non-raw mode, the pen driver should already be scaled to
  188. // the range of 0-65535, but in raw mode, we still have to do
  189. // this work.
  190. gInput.mi.dx = (x >= gdwMaxX)?
  191. MAX_NORMALIZED_X: // too high
  192. ((x <= gdwMinX)?
  193. 0: // too low
  194. ((((t = x - gdwMinX) << 16) - t) / gdwRngX));
  195. gInput.mi.dy = (y >= gdwMaxY)?
  196. MAX_NORMALIZED_Y : // too high
  197. ((y <= gdwMinY)?
  198. 0: // too low
  199. ((((t = y - gdwMinY) << 16) - t) / gdwRngY));
  200. }
  201. gInput.mi.dx = (((gInput.mi.dx > glLongOffset)?
  202. gInput.mi.dx - glLongOffset: 0)*NUM_PIXELS_LONG)/
  203. max(gcxPrimary, gcyPrimary);
  204. gInput.mi.dy = (((gInput.mi.dy > glShortOffset)?
  205. gInput.mi.dy - glShortOffset: 0)*NUM_PIXELS_SHORT)/
  206. min(gcxPrimary, gcyPrimary);
  207. if (gdwfTabSrv & TSF_PORTRAIT_MODE)
  208. {
  209. LONG temp;
  210. if (gdwfTabSrv & TSF_PORTRAIT_MODE2)
  211. {
  212. temp = gInput.mi.dx;
  213. gInput.mi.dx = MAX_NORMALIZED_Y - gInput.mi.dy;
  214. }
  215. else
  216. {
  217. temp = MAX_NORMALIZED_X - gInput.mi.dx;
  218. gInput.mi.dx = gInput.mi.dy;
  219. }
  220. gInput.mi.dy = temp;
  221. }
  222. //
  223. // Pen tilt compensation.
  224. //
  225. gInput.mi.dx += gConfig.PenTilt.dx;
  226. gInput.mi.dy += gConfig.PenTilt.dy;
  227. NotifyClient(RawPtEvent,
  228. wCurrentButtons,
  229. (y << 16) | (x & 0xffff));
  230. ProcessMouseEvent(gInput.mi.dx,
  231. gInput.mi.dy,
  232. wCurrentButtons,
  233. dwCurrentTime,
  234. FALSE);
  235. #ifdef DRAW_INK
  236. if (ghwndDrawInk != NULL)
  237. {
  238. static BOOL fPenDown = FALSE;
  239. static POINT ptPrev = {0, 0};
  240. static HPEN hpen = NULL;
  241. HDC hdc;
  242. if (!(gwLastButtons & TIP_SWITCH) &&
  243. (wCurrentButtons & TIP_SWITCH))
  244. {
  245. hpen = CreatePen(PS_SOLID, 0, RGB(255, 255, 255));
  246. fPenDown = TRUE;
  247. ptPrev.x = NORMAL_TO_SCREEN_X(gInput.mi.dx);
  248. ptPrev.y = NORMAL_TO_SCREEN_Y(gInput.mi.dy);
  249. }
  250. else if ((gwLastButtons & TIP_SWITCH) &&
  251. !(wCurrentButtons & TIP_SWITCH))
  252. {
  253. DeleteObject(hpen);
  254. hpen = NULL;
  255. fPenDown = FALSE;
  256. }
  257. else if (fPenDown)
  258. {
  259. HPEN hpenOld;
  260. POINT pt;
  261. pt.x = NORMAL_TO_SCREEN_X(gInput.mi.dx);
  262. pt.y = NORMAL_TO_SCREEN_Y(gInput.mi.dy);
  263. hdc = GetDC(ghwndDrawInk);
  264. hpenOld = (HPEN)SelectObject(hdc, hpen);
  265. MoveToEx(hdc, ptPrev.x, ptPrev.y, NULL);
  266. LineTo(hdc, pt.x, pt.y);
  267. SelectObject(hdc, hpenOld);
  268. ReleaseDC(ghwndDrawInk, hdc);
  269. ptPrev = pt;
  270. }
  271. }
  272. #endif
  273. gwLastButtons = wCurrentButtons;
  274. gLastRawDigiReport.wX = (WORD)x;
  275. gLastRawDigiReport.wY = (WORD)y;
  276. gLastRawDigiReport.wButtonState = wCurrentButtons;
  277. gLastRawDigiReport.dwTime = dwCurrentTime;
  278. }
  279. }
  280. else
  281. {
  282. TABSRVERR(("failed getting data (StatusX=%d,StatusY=%d,StatusBtn=%d,Len=%d)\n",
  283. StatusX, StatusY, StatusBtn, ulLength));
  284. }
  285. TRACEEXIT(("!\n"));
  286. return;
  287. } //ProcessDigitizerReport
  288. /*++
  289. @doc INTERNAL
  290. @func VOID | AdjustLinearity | Adjust data according to the linearity map.
  291. @parm IN OUT PUSHORT | pwX | Points to the X data.
  292. @parm IN OUT PUSHORT | pwY | Points to the Y data.
  293. @rvalue None.
  294. --*/
  295. VOID
  296. AdjustLinearity(
  297. IN OUT PUSHORT pwX,
  298. IN OUT PUSHORT pwY
  299. )
  300. {
  301. TRACEPROC("AdjustLinearity", 5)
  302. int ix, iy, dix, diy, n;
  303. DIGIRECT Rect;
  304. LONG x, y;
  305. TRACEENTER(("(x=%d,y=%d)\n", *pwX, *pwY));
  306. for (n = 0, ix = gixIndex, iy = giyIndex; ; ix += dix, iy += diy, n++)
  307. {
  308. //
  309. // Safe guard from never-ending loop.
  310. //
  311. TRACEASSERT(n <= NUM_LINEAR_XPTS + NUM_LINEAR_YPTS);
  312. if (n > NUM_LINEAR_XPTS + NUM_LINEAR_YPTS)
  313. {
  314. TABSRVERR(("AdjustLinearity caught in a loop.\n"));
  315. break;
  316. }
  317. if ((*pwX < gConfig.LinearityMap.Data[iy][ix].wDigiPtX) &&
  318. (*pwX < gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX))
  319. {
  320. dix = ix? -1: 0;
  321. }
  322. else if ((*pwX >= gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX) &&
  323. (*pwX >= gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtX))
  324. {
  325. dix = (ix + 2 < NUM_LINEAR_XPTS)? 1: 0;
  326. }
  327. else
  328. {
  329. dix = 0;
  330. }
  331. if ((*pwY < gConfig.LinearityMap.Data[iy][ix].wDigiPtY) &&
  332. (*pwY < gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY))
  333. {
  334. diy = iy? -1: 0;
  335. }
  336. else if ((*pwY >= gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY) &&
  337. (*pwY >= gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtY))
  338. {
  339. diy = (iy + 2 < NUM_LINEAR_YPTS)? 1: 0;
  340. }
  341. else
  342. {
  343. diy = 0;
  344. }
  345. //
  346. // If delta-X and delta-Y are both zeros, we found the containing
  347. // rectangle.
  348. //
  349. if ((dix == 0) && (diy == 0))
  350. {
  351. break;
  352. }
  353. }
  354. TRACEASSERT(gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY -
  355. gConfig.LinearityMap.Data[iy][ix].wDigiPtY);
  356. TRACEASSERT(gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtY -
  357. gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY);
  358. Rect.wx0 = gConfig.LinearityMap.Data[iy][ix].wDigiPtX +
  359. ((*pwY - gConfig.LinearityMap.Data[iy][ix].wDigiPtY)*
  360. (gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX -
  361. gConfig.LinearityMap.Data[iy][ix].wDigiPtX))/
  362. (gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY -
  363. gConfig.LinearityMap.Data[iy][ix].wDigiPtY);
  364. Rect.wx1 = gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX +
  365. ((*pwY - gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY)*
  366. (gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtX -
  367. gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX))/
  368. (gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtY -
  369. gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY);
  370. TRACEASSERT(gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX -
  371. gConfig.LinearityMap.Data[iy][ix].wDigiPtX);
  372. TRACEASSERT(gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtX -
  373. gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX);
  374. Rect.wy0 = gConfig.LinearityMap.Data[iy][ix].wDigiPtY +
  375. ((*pwX - gConfig.LinearityMap.Data[iy][ix].wDigiPtX)*
  376. (gConfig.LinearityMap.Data[iy][ix+1].wDigiPtY -
  377. gConfig.LinearityMap.Data[iy][ix].wDigiPtY))/
  378. (gConfig.LinearityMap.Data[iy][ix+1].wDigiPtX -
  379. gConfig.LinearityMap.Data[iy][ix].wDigiPtX);
  380. Rect.wy1 = gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY +
  381. ((*pwX - gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX)*
  382. (gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtY -
  383. gConfig.LinearityMap.Data[iy+1][ix].wDigiPtY))/
  384. (gConfig.LinearityMap.Data[iy+1][ix+1].wDigiPtX -
  385. gConfig.LinearityMap.Data[iy+1][ix].wDigiPtX);
  386. //
  387. // Remember the upper-left corner of the containing rectangle so that
  388. // we will start with this rectangle the next time.
  389. //
  390. gixIndex = ix;
  391. giyIndex = iy;
  392. //
  393. // Calculate the adjustment:
  394. // x = x0Ref + (xDigi - x0Digi)*(x1Ref - x0Ref)/(x1Digi - x0Digi)
  395. // y = y0Ref + (yDigi - y0Digi)*(y1Ref - y0Ref)/(y1Digi - y1Digi)
  396. //
  397. TRACEASSERT((Rect.wx1 - Rect.wx0) != 0);
  398. TRACEASSERT((Rect.wy1 - Rect.wy0) != 0);
  399. x = gConfig.LinearityMap.Data[iy][ix].wRefPtX +
  400. ((*pwX - Rect.wx0)*
  401. (gConfig.LinearityMap.Data[iy][ix + 1].wRefPtX -
  402. gConfig.LinearityMap.Data[iy][ix].wRefPtX))/
  403. (Rect.wx1 - Rect.wx0);
  404. *pwX = (USHORT)((x < 0)? 0:
  405. (x > MAX_NORMALIZED_X)? MAX_NORMALIZED_X: x);
  406. y = gConfig.LinearityMap.Data[iy][ix].wRefPtY +
  407. ((*pwY - Rect.wy0)*
  408. (gConfig.LinearityMap.Data[iy + 1][ix].wRefPtY -
  409. gConfig.LinearityMap.Data[iy][ix].wRefPtY))/
  410. (Rect.wy1 - Rect.wy0);
  411. *pwY = (USHORT)((y < 0)? 0:
  412. (y > MAX_NORMALIZED_Y)? MAX_NORMALIZED_Y: y);
  413. TRACEEXIT(("!(x=%d,y=%d)\n", *pwX, *pwY));
  414. return;
  415. } //AdjustLinearity
  416. /*++
  417. @doc INTERNAL
  418. @func LRESULT | ProcessMouseEvent | Process the mouse event.
  419. @parm IN LONG | x | Current X.
  420. @parm IN LONG | y | Current Y.
  421. @parm IN WORD | wButtons | Current buttons state.
  422. @parm IN DWORD | dwTime | Current time.
  423. @parm IN BOOL | fLowLevelMouse | TRUE if called by LowLevelMouseProc.
  424. @rvalue SUCCESS | Returns non-zero to eat the mouse event.
  425. @rvalue FAILURE | Returns 0 to pass along the event to next handler.
  426. --*/
  427. LRESULT
  428. ProcessMouseEvent(
  429. IN LONG x,
  430. IN LONG y,
  431. IN WORD wButtons,
  432. IN DWORD dwTime,
  433. IN BOOL fLowLevelMouse
  434. )
  435. {
  436. TRACEPROC("ProcessMouseEvent", 5)
  437. LRESULT rc = 0;
  438. DWORD dwEvent;
  439. TRACEENTER(("(x=%d,y=%d,Buttons=%x,Time=%d,fLLMouse=%x)\n",
  440. x, y, wButtons, dwTime, fLowLevelMouse));
  441. gInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
  442. if (fLowLevelMouse)
  443. {
  444. gInput.mi.dwFlags |= MOUSEEVENTF_VIRTUALDESK;
  445. }
  446. // Has the tip switch changed state?
  447. if (((gwLastButtons ^ wButtons) & TIP_SWITCH) != 0)
  448. {
  449. if (wButtons & TIP_SWITCH)
  450. {
  451. //
  452. // Tip switch is down.
  453. //
  454. if (gdwPenState == PENSTATE_LEFTUP_PENDING)
  455. {
  456. if (fLowLevelMouse)
  457. {
  458. KillTimer(ghwndMouse, TIMERID_PRESSHOLD);
  459. }
  460. TRACEINFO(3, ("Simulate a left up on pen down.\n"));
  461. gdwPenState = PENSTATE_NORMAL;
  462. dwEvent = SWAPBUTTONS(giButtonsSwapped,
  463. MOUSEEVENTF_LEFTUP,
  464. MOUSEEVENTF_RIGHTUP);
  465. gInput.mi.dwFlags |= dwEvent;
  466. gInput.mi.dx = glPenUpX;
  467. gInput.mi.dy = glPenUpY;
  468. SendInput(1, &gInput, sizeof(INPUT));
  469. gInput.mi.dwFlags &= ~dwEvent;
  470. gInput.mi.dx = x;
  471. gInput.mi.dy = y;
  472. }
  473. if (gConfig.GestureSettings.dwfFeatures &
  474. GESTURE_FEATURE_PRESSHOLD_ENABLED)
  475. {
  476. if (CanDoPressHold(x, y))
  477. {
  478. TRACEINFO(3, ("Pendown.\n"));
  479. //
  480. // Press and Hold is enabled, so hold back the left down event.
  481. //
  482. gdwPenDownTime = dwTime;
  483. glPenDownX = x;
  484. glPenDownY = y;
  485. gdwPenState = PENSTATE_PENDOWN;
  486. if (fLowLevelMouse)
  487. {
  488. SetTimer(ghwndMouse,
  489. TIMERID_PRESSHOLD,
  490. gConfig.GestureSettings.iPressHoldTime,
  491. NULL);
  492. }
  493. rc = 1;
  494. }
  495. else
  496. {
  497. gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped,
  498. MOUSEEVENTF_LEFTDOWN,
  499. MOUSEEVENTF_RIGHTDOWN);
  500. }
  501. }
  502. else
  503. {
  504. gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped,
  505. MOUSEEVENTF_LEFTDOWN,
  506. MOUSEEVENTF_RIGHTDOWN);
  507. }
  508. }
  509. else
  510. {
  511. //
  512. // Tip switch is up.
  513. //
  514. if (gdwPenState == PENSTATE_PENDOWN)
  515. {
  516. //
  517. // If we still have pendown pending, it means presshold timer
  518. // has not expired, so we must cancel pendown pending and
  519. // simulate a left click.
  520. //
  521. TRACEINFO(3, ("Simulate a left-down.\n"));
  522. if (fLowLevelMouse)
  523. {
  524. KillTimer(ghwndMouse, TIMERID_PRESSHOLD);
  525. }
  526. gdwPenState = PENSTATE_LEFTUP_PENDING;
  527. //
  528. // Simulate a left down.
  529. //
  530. gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped,
  531. MOUSEEVENTF_LEFTDOWN,
  532. MOUSEEVENTF_RIGHTDOWN);
  533. gInput.mi.dx = glPenDownX;
  534. gInput.mi.dy = glPenDownY;
  535. SendInput(1, &gInput, sizeof(INPUT));
  536. gdwPenUpTime = dwTime;
  537. glPenUpX = x;
  538. glPenUpY = y;
  539. rc = 1;
  540. if (fLowLevelMouse)
  541. {
  542. SetTimer(ghwndMouse,
  543. TIMERID_PRESSHOLD,
  544. TIMEOUT_LEFTCLICK,
  545. NULL);
  546. }
  547. }
  548. else if ((gdwPenState == PENSTATE_PRESSHOLD) ||
  549. (gdwPenState == PENSTATE_RIGHTDRAG))
  550. {
  551. if (gdwPenState == PENSTATE_PRESSHOLD)
  552. {
  553. TRACEINFO(3, ("Simulate a right click.\n"));
  554. SetPressHoldCursor(FALSE);
  555. dwEvent = SWAPBUTTONS(giButtonsSwapped,
  556. MOUSEEVENTF_RIGHTDOWN,
  557. MOUSEEVENTF_LEFTDOWN);
  558. gInput.mi.dwFlags |= dwEvent;
  559. gInput.mi.dx = glPenDownX;
  560. gInput.mi.dy = glPenDownY;
  561. SendInput(1, &gInput, sizeof(INPUT));
  562. gInput.mi.dwFlags &= ~dwEvent;
  563. gInput.mi.dx = x;
  564. gInput.mi.dy = y;
  565. }
  566. else
  567. {
  568. TRACEINFO(3, ("Simulate a right up.\n"));
  569. }
  570. gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped,
  571. MOUSEEVENTF_RIGHTUP,
  572. MOUSEEVENTF_LEFTUP);
  573. if (fLowLevelMouse)
  574. {
  575. SendInput(1, &gInput, sizeof(INPUT));
  576. rc = 1;
  577. }
  578. PressHoldMode(FALSE);
  579. }
  580. else
  581. {
  582. TRACEINFO(3, ("Do a left up.\n"));
  583. gInput.mi.dwFlags |= SWAPBUTTONS(giButtonsSwapped,
  584. MOUSEEVENTF_LEFTUP,
  585. MOUSEEVENTF_RIGHTUP);
  586. }
  587. }
  588. }
  589. else if (gdwPenState == PENSTATE_PENDOWN)
  590. {
  591. int cxScreen = fLowLevelMouse? gcxScreen: gcxPrimary,
  592. cyScreen = fLowLevelMouse? gcyScreen: gcyPrimary;
  593. if ((((abs(x - glPenDownX)*cxScreen) >> 16) >
  594. gConfig.GestureSettings.iHoldTolerance) ||
  595. (((abs(y - glPenDownY)*cyScreen) >> 16) >
  596. gConfig.GestureSettings.iHoldTolerance))
  597. {
  598. TRACEINFO(3, ("Cancel pen down pending, simulate a left down.\n"));
  599. if (fLowLevelMouse)
  600. {
  601. KillTimer(ghwndMouse, 1);
  602. }
  603. gdwPenState = PENSTATE_NORMAL;
  604. dwEvent = SWAPBUTTONS(giButtonsSwapped,
  605. MOUSEEVENTF_LEFTDOWN,
  606. MOUSEEVENTF_RIGHTDOWN);
  607. gInput.mi.dwFlags |= dwEvent;
  608. gInput.mi.dx = glPenDownX;
  609. gInput.mi.dy = glPenDownY;
  610. SendInput(1, &gInput, sizeof(INPUT));
  611. gInput.mi.dwFlags &= ~dwEvent;
  612. gInput.mi.dx = x;
  613. gInput.mi.dy = y;
  614. }
  615. }
  616. else if (gdwPenState == PENSTATE_PRESSHOLD)
  617. {
  618. int cxScreen = fLowLevelMouse? gcxScreen: gcxPrimary,
  619. cyScreen = fLowLevelMouse? gcyScreen: gcyPrimary;
  620. if ((((abs(x - glPenDownX)*cxScreen) >> 16) >
  621. gConfig.GestureSettings.iHoldTolerance) ||
  622. (((abs(y - glPenDownY)*cyScreen) >> 16) >
  623. gConfig.GestureSettings.iHoldTolerance))
  624. {
  625. KillTimer(ghwndMouse, TIMERID_PRESSHOLD);
  626. TRACEINFO(3, ("Simulate a right drag.\n"));
  627. SetPressHoldCursor(FALSE);
  628. gdwPenState = PENSTATE_RIGHTDRAG;
  629. dwEvent = SWAPBUTTONS(giButtonsSwapped,
  630. MOUSEEVENTF_RIGHTDOWN,
  631. MOUSEEVENTF_LEFTDOWN);
  632. gInput.mi.dwFlags |= dwEvent;
  633. gInput.mi.dx = glPenDownX;
  634. gInput.mi.dy = glPenDownY;
  635. SendInput(1, &gInput, sizeof(INPUT));
  636. gInput.mi.dwFlags &= ~dwEvent;
  637. gInput.mi.dx = x;
  638. gInput.mi.dy = y;
  639. }
  640. }
  641. else if (gdwPenState == PENSTATE_LEFTUP_PENDING)
  642. {
  643. //
  644. // Eat any movement before left-up timer expires.
  645. //
  646. rc = 1;
  647. }
  648. if (gConfig.GestureSettings.dwfFeatures & GESTURE_FEATURE_RECOG_ENABLED)
  649. {
  650. RecognizeGesture(gInput.mi.dx,
  651. gInput.mi.dy,
  652. wButtons,
  653. dwTime,
  654. fLowLevelMouse);
  655. }
  656. if (gdwfTabSrv & TSF_SUPERTIP_SENDINK)
  657. {
  658. LONG x, y;
  659. x = NORMAL_TO_SCREEN_X(gInput.mi.dx);
  660. y = NORMAL_TO_SCREEN_Y(gInput.mi.dy);
  661. PostMessage(ghwndSuperTIPInk,
  662. guimsgSuperTIPInk,
  663. gInput.mi.dwFlags,
  664. (LPARAM)((y << 16) | (x & 0xffff)));
  665. if (gInput.mi.dwFlags & MOUSEEVENTF_LEFTUP)
  666. {
  667. gdwfTabSrv &= ~TSF_SUPERTIP_SENDINK;
  668. }
  669. rc = 1;
  670. }
  671. else if (!fLowLevelMouse && (rc == 0))
  672. {
  673. // Convert digitizer input to mouse input
  674. SendInput(1, &gInput, sizeof(INPUT));
  675. }
  676. TRACEEXIT(("=%x\n", rc));
  677. return rc;
  678. } //ProcessMouseEvent
  679. /*++
  680. @doc INTERNAL
  681. @func VOID | PressHoldMode | Enable or disable Press and Hold mode.
  682. @parm IN BOOL | fEnable | TRUE if entering Press and Hold mode.
  683. @rvalue None.
  684. --*/
  685. VOID
  686. PressHoldMode(
  687. IN BOOL fEnable
  688. )
  689. {
  690. TRACEPROC("PressHold", 3)
  691. TRACEENTER(("(fEnable=%x)\n", fEnable));
  692. if (fEnable)
  693. {
  694. TRACEINFO(3, ("Entering Press and Hold mode.\n"));
  695. SetPressHoldCursor(TRUE);
  696. gdwPenState = PENSTATE_PRESSHOLD;
  697. }
  698. else
  699. {
  700. TRACEINFO(3, ("Exiting Press and Hold mode.\n"));
  701. gdwPenState = PENSTATE_NORMAL;
  702. }
  703. TRACEEXIT(("!\n"));
  704. return;
  705. } //PressHoldMode
  706. /*++
  707. @doc INTERNAL
  708. @func VOID | SetPressHoldCursor | Set Press and Hold cursor.
  709. @parm IN BOOL | fPressHold | TRUE to set press and hold cursor.
  710. @rvalue None.
  711. --*/
  712. VOID
  713. SetPressHoldCursor(
  714. IN BOOL fPressHold
  715. )
  716. {
  717. TRACEPROC("SetPressHoldCursor", 3)
  718. // BOOL rc = FALSE;
  719. // static HCURSOR hcurPrev = NULL;
  720. static POINT pt = {0, 0};
  721. HDC hDC;
  722. HRGN hrgn;
  723. TRACEENTER(("(fPressHold=%x)\n", fPressHold));
  724. if (fPressHold)
  725. {
  726. GetCursorPos(&pt);
  727. }
  728. hDC = GetDC(NULL);
  729. TRACEASSERT(hDC != NULL);
  730. if (hDC != NULL)
  731. {
  732. hrgn = CreateEllipticRgn(pt.x - 10, pt.y - 10, pt.x + 10, pt.y + 10);
  733. TRACEASSERT(hrgn != NULL);
  734. if (hrgn != NULL)
  735. {
  736. InvertRgn(hDC, hrgn);
  737. DeleteObject(hrgn);
  738. }
  739. ReleaseDC(NULL, hDC);
  740. }
  741. #if 0
  742. if (fPressHold)
  743. {
  744. #if 0
  745. hcurPrev = (HCURSOR)LoadImage(NULL,
  746. MAKEINTRESOURCE(OCR_NORMAL),
  747. IMAGE_CURSOR,
  748. 0,
  749. 0,
  750. LR_SHARED | LR_DEFAULTSIZE);
  751. TRACEASSERT(hcurPrev != NULL);
  752. #endif
  753. rc = SetSystemCursor(CopyCursor(ghcurPressHold), OCR_NORMAL);
  754. TRACEASSERT(rc == TRUE);
  755. }
  756. else
  757. {
  758. #if 0
  759. if (hcurPrev != NULL)
  760. {
  761. SetCursor(hcurPrev);
  762. rc = SetSystemCursor(CopyCursor(hcurPrev), OCR_NORMAL);
  763. TRACEASSERT(rc == TRUE);
  764. hcurPrev = NULL;
  765. }
  766. else
  767. {
  768. TABSRVERR(("Failed to restore normal cursor (err=%d.\n",
  769. GetLastError()));
  770. }
  771. #endif
  772. //#if 0
  773. LONG rcReg;
  774. HKEY hkUser, hkey;
  775. HCURSOR hcursor = NULL;
  776. rcReg = RegOpenCurrentUser(KEY_READ, &hkUser);
  777. if (rcReg == ERROR_SUCCESS)
  778. {
  779. rcReg = RegOpenKey(hkUser, REGSTR_PATH_CURSORS, &hkey);
  780. if (rcReg == ERROR_SUCCESS)
  781. {
  782. TCHAR szFile[MAX_PATH];
  783. DWORD dwcb = sizeof(szFile);
  784. rcReg = RegQueryValueEx(hkey,
  785. TEXT("Arrow"),
  786. NULL,
  787. NULL,
  788. (LPBYTE)szFile,
  789. &dwcb);
  790. if (rcReg == ERROR_SUCCESS)
  791. {
  792. TRACEINFO(1, ("CursorArrow=%s\n", szFile));
  793. hcursor = (HCURSOR)LoadImage(NULL,
  794. MakeFileName(szFile),
  795. IMAGE_CURSOR,
  796. 0,
  797. 0,
  798. LR_LOADFROMFILE | LR_DEFAULTSIZE);
  799. }
  800. else
  801. {
  802. TRACEWARN(("Failed to read Arrow registry value (rcReg=%x)\n",
  803. rcReg));
  804. }
  805. RegCloseKey(hkey);
  806. }
  807. else
  808. {
  809. TRACEWARN(("Failed to open cursor registry key (rcReg=%x).\n",
  810. rcReg));
  811. }
  812. RegCloseKey(hkUser);
  813. }
  814. else
  815. {
  816. TRACEWARN(("Failed to open current user (rcReg=%x).\n", rcReg));
  817. }
  818. if (hcursor == NULL)
  819. {
  820. hcursor = CopyCursor(ghcurNormal);
  821. }
  822. TRACEASSERT(hcursor != NULL);
  823. if (hcursor != NULL)
  824. {
  825. rc = SetSystemCursor(hcursor, OCR_NORMAL);
  826. }
  827. else
  828. {
  829. TABSRVERR(("Failed to restore system cursor.\n"));
  830. }
  831. //#endif
  832. }
  833. #endif
  834. TRACEEXIT(("!\n"));
  835. return;
  836. } //SetPressHoldCursor
  837. /*++
  838. @doc INTERNAL
  839. @func LPTSTR | MakeFileName | Make a valid path by doing environment
  840. substitution.
  841. @parm IN OUT LPTSTR | szFile | Points to the file name string.
  842. @rvalue returns szFile.
  843. --*/
  844. LPTSTR
  845. MakeFileName(
  846. IN OUT LPTSTR pszFile
  847. )
  848. {
  849. TRACEPROC("MakeFileName", 3)
  850. TCHAR szTmp[MAX_PATH];
  851. TRACEENTER(("(File=%s)\n", pszFile));
  852. ExpandEnvironmentStrings(pszFile, szTmp, ARRAYSIZE(szTmp));
  853. if ((szTmp[0] == TEXT('\\')) || (szTmp[1] == TEXT(':')))
  854. {
  855. lstrcpy(pszFile, szTmp);
  856. }
  857. else
  858. {
  859. GetSystemDirectory(pszFile, MAX_PATH);
  860. lstrcat(pszFile, TEXT("\\"));
  861. lstrcat(pszFile, szTmp);
  862. }
  863. TRACEEXIT(("! (File=%s)\n", pszFile));
  864. return pszFile;
  865. } //MakeFileName
  866. /*++
  867. @doc INTERNAL
  868. @func BOOL | CanDoPressHold | Check if we can do press and hold.
  869. @parm IN LONG | x | Cursor X.
  870. @parm IN LONG | y | Cursor Y.
  871. @rvalue SUCCESS | Returns TRUE.
  872. @rvalue FAILURE | Returns FALSE.
  873. --*/
  874. BOOL
  875. CanDoPressHold(
  876. IN LONG x,
  877. IN LONG y
  878. )
  879. {
  880. TRACEPROC("CanDoPressHold", 3)
  881. BOOL rc = TRUE;
  882. TRACEENTER(("(x=%d,y=%d)\n", x, y));
  883. if (gpISuperTip != NULL)
  884. {
  885. __try
  886. {
  887. TIP_HIT_TEST_TYPE HitType;
  888. POINT pt;
  889. pt.x = NORMAL_TO_SCREEN_X(x);
  890. pt.y = NORMAL_TO_SCREEN_Y(y);
  891. if (SUCCEEDED(gpISuperTip->HitTest(pt, &HitType)) &&
  892. (HitType != TIP_HT_NONE) && (HitType != TIP_HT_STAGE))
  893. {
  894. TRACEINFO(3, ("Cursor is on HitType=%x\n", HitType));
  895. rc = FALSE;
  896. if ((HitType == TIP_HT_INK_AREA) && (ghwndSuperTIPInk != NULL))
  897. {
  898. gdwfTabSrv |= TSF_SUPERTIP_SENDINK;
  899. }
  900. }
  901. }
  902. __except(EXCEPTION_EXECUTE_HANDLER)
  903. {
  904. TABSRVERR(("Exception in SuperTIP HitTest (%x).\n",
  905. _exception_code()));
  906. }
  907. }
  908. TRACEEXIT(("=%x\n", rc));
  909. return rc;
  910. } //CanDoPressHold