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.

619 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. buttons.cpp
  5. Abstract:
  6. This module contains all the tablet pc button functions.
  7. Author:
  8. Michael Tsang (MikeTs) 29-Sep-2000
  9. Environment:
  10. User mode
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #define HOTKEY_TIMEOUT 200 //200msec
  15. #define REPEAT_DELAY 500 //500msec
  16. #define PAGEUPDOWN_TIMEOUT 200 //200msec
  17. #define ALTTAB_TIMEOUT 500 //500msec
  18. typedef struct _HOTKEYTIMER
  19. {
  20. UINT_PTR TimerID;
  21. BUTTON_ACTION Action;
  22. ULONG dwButtonTag;
  23. ULONG dwButtonState;
  24. } HOTKEYTIMER, *PHOTKEYTIMER;
  25. typedef struct _REPEATKEYTIMER
  26. {
  27. UINT_PTR TimerID;
  28. UINT uiRepeatInterval;
  29. INPUT KbdInput;
  30. } REPEATKEYTIMER, *PREPEATKEYTIMER;
  31. HOTKEYTIMER gHotKeyTimer = {0};
  32. REPEATKEYTIMER gPageUpDownTimer = {0};
  33. REPEATKEYTIMER gAltTabTimer = {0};
  34. /*++
  35. @doc INTERNAL
  36. @func VOID | ProcessButtonsReport | Process a button input report.
  37. @parm IN PCHAR | pBuff | Buffer containing report data.
  38. @rvalue None.
  39. --*/
  40. VOID
  41. ProcessButtonsReport(
  42. IN PCHAR pBuff
  43. )
  44. {
  45. TRACEPROC("ProcessButtonsReport", 3)
  46. static ULONG dwLastButtons = 0;
  47. static ULONG dwPendingUpButtons = 0;
  48. NTSTATUS status;
  49. ULONG ulLength;
  50. TRACEENTER(("(pBuff=%p)\n", pBuff));
  51. ulLength = gdevButtons.dwcButtons;
  52. status = HidP_GetButtons(HidP_Input,
  53. HID_USAGE_PAGE_BUTTON,
  54. 0,
  55. gdevButtons.pDownButtonUsages,
  56. &ulLength,
  57. gdevButtons.pPreParsedData,
  58. pBuff,
  59. gdevButtons.hidCaps.InputReportByteLength);
  60. if (status == HIDP_STATUS_SUCCESS)
  61. {
  62. ULONG i, dwMask;
  63. ULONG dwCurrentButtons = 0;
  64. ULONG dwChangedButtons, dwButtons;
  65. for (i = 0; i < ulLength; i++)
  66. {
  67. TRACEINFO(3, ("%d: %d\n", i, gdevButtons.pDownButtonUsages[i]));
  68. dwCurrentButtons |= 1 << (gdevButtons.pDownButtonUsages[i] - 1);
  69. }
  70. dwChangedButtons = dwCurrentButtons^dwLastButtons;
  71. TRACEINFO(1, ("LastButtons=%x,CurrentButtons=%x,ChangedButtons=%x,PendingUpButtons=%x\n",
  72. dwLastButtons, dwCurrentButtons, dwChangedButtons,
  73. dwPendingUpButtons));
  74. //
  75. // If there are any released buttons that are in the PendingUpButtons
  76. // list, eat them.
  77. //
  78. dwButtons = dwChangedButtons & dwPendingUpButtons & ~dwCurrentButtons;
  79. dwChangedButtons &= ~dwButtons;
  80. dwPendingUpButtons &= ~dwButtons;
  81. if (dwButtons)
  82. {
  83. TRACEINFO(1, ("Released PendingUpButtons=%x\n", dwButtons));
  84. }
  85. if ((gHotKeyTimer.TimerID != 0) &&
  86. (dwChangedButtons & gConfig.ButtonSettings.dwHotKeyButtons) &&
  87. (dwCurrentButtons == gConfig.ButtonSettings.dwHotKeyButtons))
  88. {
  89. //
  90. // One of the hotkey buttons changes state and both hotkey
  91. // buttons are down, so send the hotkey event.
  92. //
  93. TRACEINFO(1, ("HotKey buttons pressed, kill HotKey timer.\n"));
  94. KillTimer(NULL, gHotKeyTimer.TimerID);
  95. gHotKeyTimer.TimerID = 0;
  96. SetEvent(ghHotkeyEvent);
  97. dwPendingUpButtons |= dwCurrentButtons;
  98. TRACEINFO(1, ("Detected HotKey (PendingUpButtons=%x)\n",
  99. dwPendingUpButtons));
  100. }
  101. else
  102. {
  103. if ((dwCurrentButtons ^ -((long)dwCurrentButtons)) &
  104. dwCurrentButtons)
  105. {
  106. //
  107. // More than 1 buttons pressed, ignored the new buttons
  108. // pressed.
  109. //
  110. TRACEINFO(1, ("More than 1 buttons pressed (NewPressedButtons=%x)\n",
  111. dwChangedButtons & dwCurrentButtons));
  112. dwPendingUpButtons |= dwChangedButtons & dwCurrentButtons;
  113. dwChangedButtons &= ~(dwChangedButtons & dwCurrentButtons);
  114. }
  115. //
  116. // Determine which remaining buttons have changed states and do
  117. // corresponding actions.
  118. //
  119. for (i = 0, dwMask = 1; i < NUM_BUTTONS; i++, dwMask <<= 1)
  120. {
  121. dwButtons = dwChangedButtons & dwMask;
  122. if (dwButtons != 0)
  123. {
  124. if (dwButtons & gConfig.ButtonSettings.dwHotKeyButtons)
  125. {
  126. //
  127. // One of the hotkey buttons has changed state.
  128. //
  129. if (dwButtons & dwCurrentButtons)
  130. {
  131. //
  132. // It's a hotkey button down, we delay the
  133. // action for 200msec. If the second hotkey
  134. // button is pressed within the period, it is
  135. // a hotkey, otherwise the action will be
  136. // performed when the timer expires.
  137. //
  138. TRACEINFO(1, ("HotKey button is pressed (Button=%x)\n",
  139. dwButtons));
  140. gHotKeyTimer.Action =
  141. gConfig.ButtonSettings.ButtonMap[i];
  142. gHotKeyTimer.dwButtonTag = dwButtons;
  143. gHotKeyTimer.dwButtonState = dwCurrentButtons &
  144. dwButtons;
  145. gHotKeyTimer.TimerID = SetTimer(NULL,
  146. 0,
  147. HOTKEY_TIMEOUT,
  148. ButtonTimerProc);
  149. TRACEASSERT(gHotKeyTimer.TimerID);
  150. if (gHotKeyTimer.TimerID == 0)
  151. {
  152. TABSRVERR(("Failed to set hotkey timer (err=%d).\n",
  153. GetLastError()));
  154. }
  155. }
  156. else
  157. {
  158. //
  159. // The hotkey button is released.
  160. //
  161. if (gHotKeyTimer.TimerID != 0)
  162. {
  163. //
  164. // It is released before timeout, so kill
  165. // the timer and perform the delayed down
  166. // action.
  167. //
  168. KillTimer(NULL, gHotKeyTimer.TimerID);
  169. gHotKeyTimer.TimerID = 0;
  170. TRACEINFO(1, ("HotKey button released before timeout (Button=%x)\n",
  171. dwButtons));
  172. DoButtonAction(gHotKeyTimer.Action,
  173. gHotKeyTimer.dwButtonTag,
  174. gHotKeyTimer.dwButtonState != 0);
  175. }
  176. //
  177. // Do the HotKey button release.
  178. //
  179. TRACEINFO(1, ("HotKey button released (Button=%x)\n",
  180. dwButtons));
  181. DoButtonAction(gConfig.ButtonSettings.ButtonMap[i],
  182. dwButtons,
  183. FALSE);
  184. }
  185. }
  186. else
  187. {
  188. //
  189. // Not a hotkey button, do the normal press/release
  190. // action.
  191. //
  192. TRACEINFO(1, ("Non HotKey buttons (Button=%x,Current=%x)\n",
  193. dwButtons, dwCurrentButtons));
  194. DoButtonAction(gConfig.ButtonSettings.ButtonMap[i],
  195. dwButtons,
  196. (dwCurrentButtons & dwButtons) != 0);
  197. }
  198. }
  199. }
  200. }
  201. dwLastButtons = dwCurrentButtons;
  202. }
  203. else
  204. {
  205. TABSRVERR(("failed getting data (status=%d)\n", status));
  206. }
  207. TRACEEXIT(("!\n"));
  208. return;
  209. } //ProcessButtonsReport
  210. /*++
  211. @doc INTERNAL
  212. @func VOID | ButtonTimerProc | Button timer proc.
  213. @parm IN HWND | hwnd | Not used.
  214. @parm IN UINT | uMsg | WM_TIMER.
  215. @parm IN UINT_PTR | idEvent | Not used.
  216. @parm IN DWORD | dwTime | Not used.
  217. @rvalue None.
  218. --*/
  219. VOID
  220. CALLBACK
  221. ButtonTimerProc(
  222. IN HWND hwnd,
  223. IN UINT uMsg,
  224. IN UINT_PTR idEvent,
  225. IN DWORD dwTime
  226. )
  227. {
  228. TRACEPROC("ButtonTimerProc", 3)
  229. TRACEENTER(("hwnd=%x,Msg=%s,idEvent=%x,Time=%x)\n",
  230. hwnd, LookupName(uMsg, WMMsgNames), idEvent, dwTime));
  231. TRACEASSERT(idEvent != 0);
  232. KillTimer(NULL, idEvent);
  233. if (idEvent == gHotKeyTimer.TimerID)
  234. {
  235. //
  236. // HotKey timer times out. So we will do the pending action.
  237. //
  238. gHotKeyTimer.TimerID = 0;
  239. TRACEINFO(3, ("HotKey timer expired, do pending action (Action=%d,Button=%x,fDown=%x).\n",
  240. gHotKeyTimer.Action, gHotKeyTimer.dwButtonTag,
  241. gHotKeyTimer.dwButtonState != 0));
  242. DoButtonAction(gHotKeyTimer.Action,
  243. gHotKeyTimer.dwButtonTag,
  244. gHotKeyTimer.dwButtonState != 0);
  245. }
  246. else if (idEvent == gPageUpDownTimer.TimerID)
  247. {
  248. TRACEINFO(3, ("Page Up/Down timer expired, send another Page Up/Down.\n"));
  249. SendInput(1, &gPageUpDownTimer.KbdInput, sizeof(INPUT));
  250. gPageUpDownTimer.TimerID = SetTimer(NULL,
  251. 0,
  252. gPageUpDownTimer.uiRepeatInterval,
  253. ButtonTimerProc);
  254. }
  255. else if (idEvent == gAltTabTimer.TimerID)
  256. {
  257. TRACEINFO(3, ("Alt-tab timer expired, send another tab.\n"));
  258. SendInput(1, &gAltTabTimer.KbdInput, sizeof(INPUT));
  259. gAltTabTimer.TimerID = SetTimer(NULL,
  260. 0,
  261. gAltTabTimer.uiRepeatInterval,
  262. ButtonTimerProc);
  263. }
  264. else
  265. {
  266. TABSRVERR(("Unknown timer (TimerID=%x).\n", idEvent));
  267. }
  268. TRACEEXIT(("!\n"));
  269. return;
  270. } //ButtonTimerProc
  271. /*++
  272. @doc INTERNAL
  273. @func BOOL | DoButtonAction | Do the button action.
  274. @parm IN BUTTON_ACTION | Action | Button action to be performed.
  275. @parm IN DWORD | dwButtonTag | Specifies which button.
  276. @parm IN BOOL | fButtonDown | TRUE if the button is in down state.
  277. @rvalue SUCCESS | Return TRUE.
  278. @rvalue FAILURE | Return FALSE.
  279. --*/
  280. BOOL
  281. DoButtonAction(
  282. IN BUTTON_ACTION Action,
  283. IN DWORD dwButtonTag,
  284. IN BOOL fButtonDown
  285. )
  286. {
  287. TRACEPROC("DoButtonAction", 2)
  288. BOOL rc = TRUE;
  289. INPUT KbdInput[2];
  290. WORD wVk;
  291. TRACEENTER(("(Action=%d,ButtonTag=%x,fDown=%x)\n",
  292. Action, dwButtonTag, fButtonDown));
  293. memset(KbdInput, 0, sizeof(KbdInput));
  294. KbdInput[0].type = INPUT_KEYBOARD;
  295. KbdInput[1].type = INPUT_KEYBOARD;
  296. switch (Action)
  297. {
  298. case InvokeNoteBook:
  299. if (!fButtonDown)
  300. {
  301. TRACEINFO(1, ("Invoke NoteBook on button down (Button=%x)\n",
  302. dwButtonTag));
  303. rc = DoInvokeNoteBook();
  304. }
  305. break;
  306. case PageUp:
  307. wVk = VK_PRIOR;
  308. TRACEINFO(1, ("PageUp (Button=%x,fDown=%x)\n",
  309. dwButtonTag, fButtonDown));
  310. goto PageUpDownCommon;
  311. case PageDown:
  312. wVk = VK_NEXT;
  313. TRACEINFO(1, ("PageDown (Button=%x,fDown=%x)\n",
  314. dwButtonTag, fButtonDown));
  315. PageUpDownCommon:
  316. if (fButtonDown)
  317. {
  318. if (gPageUpDownTimer.TimerID != 0)
  319. {
  320. //
  321. // There is an existing Page Up/Down timer, cancel it.
  322. //
  323. KillTimer(NULL, gPageUpDownTimer.TimerID);
  324. gPageUpDownTimer.TimerID = 0;
  325. }
  326. //
  327. // Send PageUpDown-down.
  328. //
  329. memset(&gPageUpDownTimer, 0, sizeof(gPageUpDownTimer));
  330. gPageUpDownTimer.uiRepeatInterval = PAGEUPDOWN_TIMEOUT;
  331. gPageUpDownTimer.KbdInput.type = INPUT_KEYBOARD;
  332. gPageUpDownTimer.KbdInput.ki.wVk = wVk;
  333. SendInput(1, &gPageUpDownTimer.KbdInput, sizeof(INPUT));
  334. gPageUpDownTimer.TimerID = SetTimer(NULL,
  335. 0,
  336. REPEAT_DELAY,
  337. ButtonTimerProc);
  338. TRACEASSERT(gPageUpDownTimer.TimerID);
  339. if (gPageUpDownTimer.TimerID == 0)
  340. {
  341. TABSRVERR(("Failed to set Page Up/Down timer (err=%d).\n",
  342. GetLastError()));
  343. rc = FALSE;
  344. }
  345. }
  346. else
  347. {
  348. TRACEASSERT(gPageUpDownTimer.TimerID != 0);
  349. KillTimer(NULL, gPageUpDownTimer.TimerID);
  350. gPageUpDownTimer.TimerID = 0;
  351. //
  352. // Send PageUpDown-up.
  353. //
  354. KbdInput[0].ki.wVk = wVk;
  355. KbdInput[0].ki.dwFlags = KEYEVENTF_KEYUP;
  356. SendInput(1, KbdInput, sizeof(INPUT));
  357. }
  358. break;
  359. case AltTab:
  360. if (fButtonDown)
  361. {
  362. TRACEINFO(1, ("AltTab down (Button=%x)\n", dwButtonTag));
  363. TRACEASSERT(gAltTabTimer.TimerID == 0);
  364. //
  365. // Send Alt-down, Tab-down.
  366. //
  367. KbdInput[0].ki.wVk = VK_MENU;
  368. KbdInput[1].ki.wVk = VK_TAB;
  369. SendInput(2, KbdInput, sizeof(INPUT));
  370. memset(&gAltTabTimer, 0, sizeof(gAltTabTimer));
  371. gAltTabTimer.uiRepeatInterval = ALTTAB_TIMEOUT;
  372. gAltTabTimer.KbdInput.type = INPUT_KEYBOARD;
  373. gAltTabTimer.KbdInput.ki.wVk = VK_TAB;
  374. gAltTabTimer.TimerID = SetTimer(NULL,
  375. 0,
  376. REPEAT_DELAY,
  377. ButtonTimerProc);
  378. TRACEASSERT(gAltTabTimer.TimerID);
  379. if (gAltTabTimer.TimerID == 0)
  380. {
  381. TABSRVERR(("Failed to set Alt-Tab timer (err=%d).\n",
  382. GetLastError()));
  383. rc = FALSE;
  384. }
  385. }
  386. else
  387. {
  388. TRACEINFO(1, ("AltTab up (Button=%x)\n", dwButtonTag));
  389. TRACEASSERT(gAltTabTimer.TimerID != 0);
  390. KillTimer(NULL, gAltTabTimer.TimerID);
  391. gAltTabTimer.TimerID = 0;
  392. //
  393. // Send Tab-up, Alt-up.
  394. //
  395. KbdInput[0].ki.wVk = VK_TAB;
  396. KbdInput[0].ki.dwFlags = KEYEVENTF_KEYUP;
  397. KbdInput[1].ki.wVk = VK_MENU;
  398. KbdInput[1].ki.dwFlags = KEYEVENTF_KEYUP;
  399. SendInput(2, KbdInput, sizeof(INPUT));
  400. }
  401. break;
  402. case AltEsc:
  403. if (fButtonDown)
  404. {
  405. //
  406. // Send Alt-down, Esc-down.
  407. //
  408. TRACEINFO(1, ("AltEsc down (Button=%x)\n", dwButtonTag));
  409. KbdInput[0].ki.wVk = VK_MENU;
  410. KbdInput[1].ki.wVk = VK_ESCAPE;
  411. SendInput(2, KbdInput, sizeof(INPUT));
  412. }
  413. else
  414. {
  415. //
  416. // Send Esc-up, Alt-up.
  417. //
  418. TRACEINFO(1, ("AltEsc up (Button=%x)\n", dwButtonTag));
  419. KbdInput[0].ki.wVk = VK_ESCAPE;
  420. KbdInput[0].ki.dwFlags = KEYEVENTF_KEYUP;
  421. KbdInput[1].ki.wVk = VK_MENU;
  422. KbdInput[1].ki.dwFlags = KEYEVENTF_KEYUP;
  423. SendInput(2, KbdInput, sizeof(INPUT));
  424. }
  425. break;
  426. case Enter:
  427. if (fButtonDown)
  428. {
  429. //
  430. // Send Enter-down.
  431. //
  432. TRACEINFO(1, ("Return down (Button=%x)\n", dwButtonTag));
  433. KbdInput[0].ki.wVk = VK_RETURN;
  434. SendInput(1, KbdInput, sizeof(INPUT));
  435. }
  436. else
  437. {
  438. //
  439. // Send Enter-up.
  440. //
  441. TRACEINFO(1, ("Return up (Button=%x)\n", dwButtonTag));
  442. KbdInput[0].ki.wVk = VK_RETURN;
  443. KbdInput[0].ki.dwFlags = KEYEVENTF_KEYUP;
  444. SendInput(1, KbdInput, sizeof(INPUT));
  445. }
  446. break;
  447. case Esc:
  448. if (fButtonDown)
  449. {
  450. //
  451. // Send Esc-down.
  452. //
  453. TRACEINFO(1, ("Escape down (Button=%x)\n", dwButtonTag));
  454. KbdInput[0].ki.wVk = VK_ESCAPE;
  455. SendInput(1, KbdInput, sizeof(INPUT));
  456. }
  457. else
  458. {
  459. //
  460. // Send Esc-up.
  461. //
  462. TRACEINFO(1, ("Escape up (Button=%x)\n", dwButtonTag));
  463. KbdInput[0].ki.wVk = VK_ESCAPE;
  464. KbdInput[0].ki.dwFlags = KEYEVENTF_KEYUP;
  465. SendInput(1, KbdInput, sizeof(INPUT));
  466. }
  467. break;
  468. }
  469. TRACEEXIT(("=%x\n", rc));
  470. return rc;
  471. } //DoButtonAction
  472. /*++
  473. @doc INTERNAL
  474. @func BOOL | DoInvokeNoteBook | Invoke the Notebook app.
  475. @parm None.
  476. @rvalue SUCCESS | Returns TRUE.
  477. @rvalue FAILURE | Returns FALSE.
  478. --*/
  479. BOOL
  480. DoInvokeNoteBook(
  481. VOID
  482. )
  483. {
  484. TRACEPROC("DoInvokeNoteBook", 3)
  485. BOOL rc = FALSE;
  486. PTSTHREAD pThread = FindThread(TSF_BUTTONTHREAD);
  487. TRACEENTER(("()\n"));
  488. if (!(pThread->dwfThread & THREADF_DESKTOP_WINLOGON))
  489. {
  490. TCHAR szNoteBook[MAX_PATH];
  491. DWORD dwcb = sizeof(szNoteBook);
  492. HRESULT hr;
  493. hr = GetRegValueString(HKEY_LOCAL_MACHINE,
  494. TEXT("SOFTWARE\\Microsoft\\MSNotebook"),
  495. TEXT("InstallDir"),
  496. szNoteBook,
  497. &dwcb);
  498. if (SUCCEEDED(hr))
  499. {
  500. lstrcat(szNoteBook, "NoteBook.exe");
  501. rc = RunProcessAsUser(szNoteBook);
  502. }
  503. else
  504. {
  505. TABSRVERR(("Failed to read MSNoteBook install path from the registry (hr=%d).\n",
  506. hr));
  507. }
  508. }
  509. else
  510. {
  511. TRACEWARN(("Cannot run NoteBook app. in WinLogon desktop.\n"));
  512. }
  513. TRACEEXIT(("=%x\n", rc));
  514. return rc;
  515. } //DoInvokeNoteBook
  516. /*++
  517. @doc INTERNAL
  518. @func VOID | UpdateButtonRepeatRate | Update button repeat rate.
  519. @parm None.
  520. @rvalue None.
  521. --*/
  522. VOID
  523. UpdateButtonRepeatRate(
  524. VOID
  525. )
  526. {
  527. TRACEPROC("UpdateButtonRepeatRate", 3)
  528. static DWORD KbdDelayTime[] = {1000, 750, 500, 250};
  529. int iKbdDelay;
  530. int iKbdSpeed;
  531. TRACEENTER(("()\n"));
  532. #if 0
  533. if (!SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &iKbdDelay, 0))
  534. {
  535. TRACEWARN(("Get keyboard delay failed (err=%d).\n", GetLastError()));
  536. }
  537. else if (!SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &iKbdSpeed, 0))
  538. {
  539. TRACEWARN(("Get keyboard speed failed (err=%d).\n", GetLastError()));
  540. }
  541. else
  542. {
  543. TRACEASSERT((iKbdDelay >= 0) && (iKbdDelay <= 3));
  544. gdwKbdDelayTime = KbdDelayTime[iKbdDelay];
  545. gdwKbdRepeatTime =
  546. }
  547. #endif
  548. TRACEEXIT(("!\n"));
  549. return;
  550. } //UpdateButtonRepeatRate