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.

1681 lines
53 KiB

  1. /*++
  2. *
  3. * Component: hidserv.dll
  4. * File: appcmd.c
  5. * Purpose: routines to run the HID Audio server.
  6. *
  7. * Copyright (C) Microsoft Corporation 1997,1998. All rights reserved.
  8. *
  9. * WGJ
  10. --*/
  11. #define GLOBALS
  12. #include "hidserv.h"
  13. #define HIDSERV_FROM_SPEAKER 0x8000
  14. /*++
  15. * IMPORTANT - All work within this service is synchronized by the
  16. * message procedure HidServProc() except the per device work thread
  17. * HidThreadProc(). All concurrent access to shared data is within the
  18. * message procedure thread and therefore is serialized. For example,
  19. * HidThreadProc() posts messages to the message thread when it needs
  20. * to perform a serialized action. Any deviation from this scheme must
  21. * be protected by critical section.
  22. --*/
  23. DWORD
  24. WINAPI
  25. HidServMain(
  26. HANDLE InitDoneEvent
  27. )
  28. /*++
  29. Routine Description:
  30. Creates the main message loop and executes the
  31. Hid Audio server.
  32. --*/
  33. {
  34. MSG msg;
  35. // Some controls have Auto Repeat timers. This mutex prevents
  36. // concurrent access to data by these async timers.
  37. hMutexOOC = CreateMutex(NULL, FALSE, TEXT("OOC State Mutex"));
  38. // Use CreateMutex to detect previous instances of the app.
  39. if (GetLastError() == ERROR_ALREADY_EXISTS){
  40. WARN(("Exiting multiple HidAudio instance."));
  41. CloseHandle(hMutexOOC);
  42. return 0;
  43. }
  44. hInputEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  45. hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  46. hDesktopSwitch = OpenEvent(SYNCHRONIZE, FALSE, TEXT("WinSta0_DesktopSwitch"));
  47. InputThreadEnabled = TRUE;
  48. // Register the window class
  49. {
  50. WNDCLASSEX wce;
  51. wce.cbSize = sizeof(WNDCLASSEX);
  52. wce.style = 0;
  53. wce.lpfnWndProc = (WNDPROC) HidServProc;
  54. wce.cbClsExtra = 0;
  55. wce.cbWndExtra = 0;
  56. wce.hInstance = hInstance;
  57. wce.hIcon = NULL;
  58. wce.hIconSm = NULL;
  59. wce.hCursor = NULL;
  60. wce.hbrBackground = NULL;
  61. wce.lpszMenuName = NULL;
  62. wce.lpszClassName = TEXT("HidServClass");
  63. if (!RegisterClassEx(&wce)){
  64. WARN(("Cannot register thread window class: 0x%.8x\n", GetLastError()));
  65. SET_SERVICE_STATE(SERVICE_STOPPED);
  66. return 0;
  67. }
  68. }
  69. // Create the app window.
  70. // Most events will be processed through this hidden window. Look at HidServProc() to see
  71. // what work this window message loop does.
  72. hWndHidServ = CreateWindow(TEXT("HidServClass"),
  73. TEXT("HID Input Service"),
  74. WS_OVERLAPPEDWINDOW,
  75. 0,
  76. 0,
  77. 0,
  78. 0,
  79. (HWND) NULL,
  80. (HMENU) NULL,
  81. hInstance,
  82. (LPVOID) NULL);
  83. TRACE(("hWndHidServ == %x", hWndHidServ));
  84. // If the window cannot be created, terminate
  85. if (!hWndHidServ){
  86. WARN(("Window creation failed."));
  87. CloseHandle(hMutexOOC);
  88. CloseHandle(hInputEvent);
  89. CloseHandle(hInputDoneEvent);
  90. CloseHandle(hDesktopSwitch);
  91. SET_SERVICE_STATE(SERVICE_STOPPED);
  92. return 0;
  93. }
  94. // Register for selective device nofication
  95. // This only required for NT5
  96. {
  97. DEV_BROADCAST_DEVICEINTERFACE DevHdr;
  98. ZeroMemory(&DevHdr, sizeof(DevHdr));
  99. DevHdr.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  100. DevHdr.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  101. HidD_GetHidGuid (&DevHdr.dbcc_classguid);
  102. hNotifyArrival =
  103. RegisterDeviceNotification( hWndHidServ,
  104. &DevHdr,
  105. DEVICE_NOTIFY_WINDOW_HANDLE);
  106. if (!hNotifyArrival){
  107. WARN(("RegisterDeviceNotification failure (%x).", GetLastError()));
  108. }
  109. }
  110. // We do this here, not in WM_CREATE handler, because the init routines need
  111. // to know the new window handle.
  112. HidServInit();
  113. InputSessionId = 0;
  114. InputSessionLocked = FALSE;
  115. WinStaDll = NULL;
  116. WinStaDll = LoadLibrary(TEXT("winsta.dll"));
  117. if (WinStaDll) {
  118. WinStaProc = (WINSTATIONSENDWINDOWMESSAGE)
  119. GetProcAddress(WinStaDll, "WinStationSendWindowMessage");
  120. }
  121. CreateThread(
  122. NULL, // pointer to thread security attributes
  123. 0, // initial thread stack size, in bytes (0 = default)
  124. HidThreadInputProc, // pointer to thread function
  125. NULL, // argument for new thread
  126. 0, // creation flags
  127. &InputThreadId // pointer to returned thread identifier
  128. );
  129. if (InitDoneEvent) {
  130. SetEvent(InitDoneEvent);
  131. }
  132. // Start the message loop. This is terminated by system shutdown
  133. // or End Task. There is no UI to close the app.
  134. while (GetMessage(&msg, (HWND) NULL, 0, 0)) {
  135. TranslateMessage(&msg);
  136. DispatchMessage(&msg);
  137. }
  138. // To terminate, we only need to destroy the window. MmHidExit() was
  139. // already called on WM_CLOSE.
  140. DestroyWindow(hWndHidServ);
  141. INFO(("UnRegistering window class"));
  142. UnregisterClass(TEXT("HidServClass"),
  143. hInstance);
  144. // Don't let this process go until all HidThreadProc() threads are complete.
  145. while (cThreadRef) SleepEx(1000, FALSE);
  146. return 0;
  147. }
  148. void
  149. HidservSetPnP(
  150. BOOL Enable
  151. )
  152. {
  153. if (Enable) {
  154. if (!PnpEnabled){
  155. // Enable device refresh.
  156. PnpEnabled = TRUE;
  157. PostMessage(hWndHidServ, WM_HIDSERV_PNP_HID, 0, 0);
  158. }
  159. } else {
  160. // Prevent any device refresh.
  161. PnpEnabled = FALSE;
  162. DestroyHidDeviceList();
  163. }
  164. }
  165. void
  166. HidServStart(
  167. void
  168. )
  169. /*++
  170. Routine Description:
  171. Restart the Hid Audio server if it has been stopped.
  172. --*/
  173. {
  174. HidservSetPnP(TRUE);
  175. SET_SERVICE_STATE(SERVICE_RUNNING);
  176. }
  177. void
  178. HidServStop(
  179. void
  180. )
  181. /*++
  182. Routine Description:
  183. Stop all activity, but keep static data, and keep
  184. the message queue running.
  185. --*/
  186. {
  187. // Prevent any device refresh.
  188. HidservSetPnP(FALSE);
  189. SET_SERVICE_STATE(SERVICE_STOPPED);
  190. }
  191. BOOL
  192. HidServInit(
  193. void
  194. )
  195. /*++
  196. Routine Description:
  197. Setup all data structures and open system handles.
  198. --*/
  199. {
  200. HidServStart();
  201. return TRUE;
  202. }
  203. void
  204. HidServExit(
  205. void
  206. )
  207. /*++
  208. Routine Description:
  209. Close all system handles.
  210. --*/
  211. {
  212. if (WinStaDll) {
  213. FreeLibrary(WinStaDll);
  214. }
  215. UnregisterDeviceNotification(hNotifyArrival);
  216. HidServStop();
  217. CloseHandle(hMutexOOC);
  218. if (InputThreadEnabled) {
  219. InputThreadEnabled = FALSE;
  220. SetEvent(hInputEvent);
  221. }
  222. }
  223. VOID
  224. HidThreadChangeDesktop (
  225. )
  226. {
  227. HDESK hDesk, hPrevDesk;
  228. BOOL result;
  229. HWINSTA prevWinSta, winSta = NULL;
  230. hPrevDesk = GetThreadDesktop(GetCurrentThreadId());
  231. prevWinSta = GetProcessWindowStation();
  232. INFO(("Setting the input thread's desktop"));
  233. winSta = OpenWindowStation(TEXT("WinSta0"), FALSE, MAXIMUM_ALLOWED);
  234. if (!winSta) {
  235. WARN(("Couldn't get the window station! Error: 0x%x", GetLastError()));
  236. goto HidThreadChangeDesktopError;
  237. }
  238. if (!SetProcessWindowStation(winSta)) {
  239. WARN(("Couldn't set the window station! Error: 0x%x", GetLastError()));
  240. goto HidThreadChangeDesktopError;
  241. }
  242. hDesk = OpenInputDesktop(0,
  243. FALSE,
  244. MAXIMUM_ALLOWED);
  245. if (!hDesk) {
  246. WARN(("Couldn't get the input desktop! Error: 0x%x", GetLastError()));
  247. goto HidThreadChangeDesktopError;
  248. }
  249. if (!SetThreadDesktop(hDesk)) {
  250. WARN(("Couldn't set the thread's desktop to the input desktop! Error: 0x%x", GetLastError()));
  251. }
  252. HidThreadChangeDesktopError:
  253. if (hPrevDesk) {
  254. CloseDesktop(hPrevDesk);
  255. }
  256. if (prevWinSta) {
  257. CloseWindowStation(prevWinSta);
  258. }
  259. }
  260. DWORD
  261. WINAPI
  262. HidThreadInputProc(
  263. PVOID Ignore
  264. )
  265. {
  266. GUITHREADINFO threadInfo;
  267. HWND hWndForeground;
  268. INPUT input;
  269. HANDLE events[2];
  270. DWORD ret;
  271. DWORD nEvents = 0;
  272. InterlockedIncrement(&cThreadRef);
  273. events[nEvents++] = hDesktopSwitch;
  274. events[nEvents++] = hInputEvent;
  275. //
  276. // This thread needs to run on the input desktop.
  277. //
  278. HidThreadChangeDesktop();
  279. while (TRUE) {
  280. ret = WaitForMultipleObjects(nEvents, events, FALSE, INFINITE);
  281. if (!InputThreadEnabled) {
  282. break;
  283. }
  284. if (0 == (ret - WAIT_OBJECT_0)) {
  285. HidThreadChangeDesktop();
  286. continue;
  287. }
  288. if (InputIsAppCommand) {
  289. threadInfo.cbSize = sizeof(GUITHREADINFO);
  290. if (GetGUIThreadInfo(0, &threadInfo)) {
  291. hWndForeground = threadInfo.hwndFocus ? threadInfo.hwndFocus : threadInfo.hwndActive;
  292. if (hWndForeground) {
  293. INFO(("Sending app command 0x%x", InputAppCommand));
  294. SendNotifyMessage(hWndForeground,
  295. WM_APPCOMMAND,
  296. (WPARAM)hWndForeground,
  297. ((InputAppCommand | FAPPCOMMAND_OEM)<<16));
  298. } else {
  299. WARN(("No window available to send to, error %x", GetLastError()));
  300. }
  301. } else {
  302. WARN(("Unable to get the focus window, error %x", GetLastError()));
  303. }
  304. } else {
  305. ZeroMemory(&input, sizeof(INPUT));
  306. input.type = INPUT_KEYBOARD;
  307. input.ki.dwFlags = InputDown ? 0 : KEYEVENTF_KEYUP;
  308. if (InputIsChar) {
  309. input.ki.wScan = InputVKey;
  310. input.ki.dwFlags |= KEYEVENTF_UNICODE;
  311. INFO(("Sending character %c %s", InputVKey, InputDown ? "down" : "up"));
  312. } else {
  313. input.ki.wVk = InputVKey;
  314. input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
  315. INFO(("Sending VK 0x%x %s", InputVKey, InputDown ? "down" : "up"));
  316. }
  317. SendInput(1, &input, sizeof(INPUT));
  318. }
  319. SetEvent(hInputDoneEvent);
  320. }
  321. CloseHandle(hDesktopSwitch);
  322. CloseHandle(hInputEvent);
  323. CloseHandle(hInputDoneEvent);
  324. InterlockedDecrement(&cThreadRef);
  325. return 0;
  326. }
  327. DWORD
  328. WINAPI
  329. HidThreadProc(
  330. PHID_DEVICE HidDevice
  331. )
  332. /*++
  333. Routine Description:
  334. Create this I/O thread for each Consumer Collection we have
  335. open. The thread dies when we close our handle on the HID device.
  336. --*/
  337. {
  338. DWORD Ret;
  339. DWORD bytesRead;
  340. BOOL bRet;
  341. DWORD dwError;
  342. USAGE_AND_PAGE *pPrevious;
  343. PHID_DATA data = HidDevice->InputData;
  344. TRACE(("Entering HidThreadProc. Device(%x)", HidDevice));
  345. InterlockedIncrement(&cThreadRef);
  346. // wait for an async read
  347. INFO(("HidThreadProc waiting for read event..."));
  348. WaitForSingleObject(HidDevice->ReadEvent, INFINITE);
  349. while (HidDevice->fThreadEnabled){
  350. TRACE(("Reading from Handle(%x)", HidDevice->HidDevice));
  351. bRet = ReadFile (HidDevice->HidDevice,
  352. HidDevice->InputReportBuffer,
  353. HidDevice->Caps.InputReportByteLength,
  354. &bytesRead,
  355. &HidDevice->Overlap);
  356. dwError = GetLastError();
  357. // wait for read to complete
  358. TRACE(("HidThreadProc waiting for completion."));
  359. if(bRet){
  360. TRACE(("Read completed synchronous."));
  361. }else{
  362. if (dwError == ERROR_IO_PENDING) {
  363. TRACE(("Read pending."));
  364. // work thread waits for completion
  365. while (TRUE) {
  366. Ret = WaitForSingleObject(HidDevice->CompletionEvent, 5000);
  367. if (Ret == WAIT_OBJECT_0) {
  368. TRACE(("Read completed on device (%x).", HidDevice));
  369. break;
  370. }
  371. if (!HidDevice->fThreadEnabled) {
  372. if (CancelIo(HidDevice->HidDevice)) {
  373. TRACE(("CancelIo succeeded for device (%x).", HidDevice));
  374. break;
  375. }
  376. }
  377. }
  378. TRACE(("Read complete async."));
  379. } else {
  380. WARN(("Read Failed with error %x. device = %x, handle = %x", dwError, HidDevice, HidDevice->HidDevice));
  381. INFO(("Device may no longer be connected. Waiting for device notification from pnp..."));
  382. // Just wait for the device notification to come thru from PnP.
  383. // Then we'll remove the device.
  384. WaitForSingleObject(HidDevice->ReadEvent, INFINITE);
  385. break;
  386. }
  387. }
  388. // don't parse data if we are exiting.
  389. if (!HidDevice->fThreadEnabled) {
  390. WaitForSingleObject(HidDevice->ReadEvent, INFINITE);
  391. break;
  392. }
  393. // parse the hid report
  394. ParseReadReport(HidDevice);
  395. // post message to dispatch this report
  396. HidServReportDispatch(HidDevice);
  397. }
  398. // Exit Thread means completely clean up this device instance
  399. TRACE(("HidThreadProc (%x) Exiting...", HidDevice));
  400. //
  401. // Send any leftover button up events
  402. //
  403. if (data->IsButtonData) {
  404. pPrevious = data->ButtonData.PrevUsages;
  405. while (pPrevious->Usage){
  406. int j;
  407. // find the client that handled the button down.
  408. for(j=0; j<MAX_PENDING_BUTTONS; j++){
  409. if ( PendingButtonList[j].Collection == data->LinkUsage &&
  410. PendingButtonList[j].Page == pPrevious->UsagePage &&
  411. PendingButtonList[j].Usage == pPrevious->Usage){
  412. PendingButtonList[j].Collection = 0;
  413. PendingButtonList[j].Page = 0;
  414. PendingButtonList[j].Usage = 0;
  415. break;
  416. }
  417. }
  418. PostMessage(hWndHidServ,
  419. WM_CI_USAGE,
  420. (WPARAM)MakeLongUsage(data->LinkUsage,pPrevious->Usage),
  421. (LPARAM)MakeLongUsage(pPrevious->UsagePage, 0));
  422. pPrevious++;
  423. }
  424. }
  425. CloseHandle(HidDevice->HidDevice);
  426. CloseHandle(HidDevice->ReadEvent);
  427. CloseHandle(HidDevice->CompletionEvent);
  428. INFO(("Free device data. (%x)", HidDevice));
  429. HidFreeDevice (HidDevice);
  430. InterlockedDecrement(&cThreadRef);
  431. TRACE(("HidThreadProc Exit complete."));
  432. return 0;
  433. }
  434. BOOL
  435. UsageInList(
  436. PUSAGE_AND_PAGE pUsage,
  437. PUSAGE_AND_PAGE pUsageList
  438. )
  439. /*++
  440. Routine Description:
  441. This utility function returns TRUE if the usage is found in the array.
  442. --*/
  443. {
  444. while (pUsageList->Usage){
  445. if ( (pUsage->Usage == pUsageList->Usage) &&
  446. (pUsage->UsagePage == pUsageList->UsagePage))
  447. return TRUE;
  448. pUsageList++;
  449. }
  450. return FALSE;
  451. }
  452. void
  453. HidServReportDispatch(
  454. PHID_DEVICE HidDevice
  455. )
  456. /*++
  457. Routine Description:
  458. Look at the HID input structure and determine what button down,
  459. button up, or value data events have occurred. We send info about these events
  460. to the most appropriate client.
  461. --*/
  462. {
  463. USAGE_AND_PAGE * pUsage;
  464. USAGE_AND_PAGE * pPrevious;
  465. DWORD i;
  466. PHID_DATA data = HidDevice->InputData;
  467. TRACE(("Input data length = %d", HidDevice->InputDataLength));
  468. TRACE(("Input data -> %.8x", HidDevice->InputData));
  469. for (i = 0;
  470. i < HidDevice->InputDataLength;
  471. i++, data++) {
  472. // If Collection is 0, then make it default
  473. if (!data->LinkUsage)
  474. data->LinkUsage = CInputCollection_Consumer_Control;
  475. if (data->Status != HIDP_STATUS_SUCCESS){
  476. // never try to process errored data
  477. //TRACE(("Input data is invalid. Status = %x", data->Status));
  478. }else if (data->IsButtonData){
  479. TRACE(("Input data is button data:"));
  480. TRACE((" Input Usage Page = %x, Collection = %x", data->UsagePage, data->LinkUsage));
  481. pUsage = data->ButtonData.Usages;
  482. pPrevious = data->ButtonData.PrevUsages;
  483. /// Notify clients of any button down events
  484. //
  485. while (pUsage->Usage){
  486. int j;
  487. TRACE((" Button Usage Page = %x", pUsage->UsagePage));
  488. TRACE((" Button Usage = %x", pUsage->Usage));
  489. if (HidDevice->Speakers) {
  490. pUsage->Usage |= HIDSERV_FROM_SPEAKER;
  491. }
  492. // is this button already down?
  493. for(j=0; j<MAX_PENDING_BUTTONS; j++)
  494. // The Pending Button List is used to keep state for all
  495. // currently pressed buttons.
  496. if ( PendingButtonList[j].Collection == data->LinkUsage &&
  497. PendingButtonList[j].Page == pUsage->UsagePage &&
  498. PendingButtonList[j].Usage == pUsage->Usage)
  499. break;
  500. // discard successive button downs
  501. if (j<MAX_PENDING_BUTTONS){
  502. pUsage++;
  503. continue;
  504. }
  505. // post the message
  506. PostMessage(hWndHidServ,
  507. WM_CI_USAGE,
  508. (WPARAM)MakeLongUsage(data->LinkUsage,pUsage->Usage),
  509. (LPARAM)MakeLongUsage(pUsage->UsagePage, 1)
  510. );
  511. // Add to the pending button list
  512. for(j=0; j<MAX_PENDING_BUTTONS; j++){
  513. if (!PendingButtonList[j].Collection &&
  514. !PendingButtonList[j].Page &&
  515. !PendingButtonList[j].Usage){
  516. PendingButtonList[j].Collection = data->LinkUsage;
  517. PendingButtonList[j].Page = pUsage->UsagePage;
  518. PendingButtonList[j].Usage = pUsage->Usage;
  519. break;
  520. }
  521. }
  522. // if it didn't make the list, send button up now.
  523. if (j==MAX_PENDING_BUTTONS){
  524. PostMessage( hWndHidServ,
  525. WM_CI_USAGE,
  526. (WPARAM)MakeLongUsage(data->LinkUsage,pUsage->Usage),
  527. (LPARAM)MakeLongUsage(pUsage->UsagePage, 0)
  528. );
  529. WARN(("Emitting immediate button up (C=%.2x,U=%.2x,P=%.2x)", data->LinkUsage, pUsage->Usage, pUsage->UsagePage));
  530. }
  531. pUsage++;
  532. }
  533. /// Notify clients of any button up events
  534. //
  535. while (pPrevious->Usage){
  536. int j;
  537. if (!UsageInList(pPrevious, pUsage)){
  538. // we have a button up.
  539. //
  540. TRACE((" Button Up (C=%.2x,U=%.2x,P=%.2x)", data->LinkUsage, pPrevious->Usage, pPrevious->UsagePage));
  541. // find the client that handled the button down.
  542. for(j=0; j<MAX_PENDING_BUTTONS; j++){
  543. if ( PendingButtonList[j].Collection == data->LinkUsage &&
  544. PendingButtonList[j].Page == pPrevious->UsagePage &&
  545. PendingButtonList[j].Usage == pPrevious->Usage){
  546. PendingButtonList[j].Collection = 0;
  547. PendingButtonList[j].Page = 0;
  548. PendingButtonList[j].Usage = 0;
  549. break;
  550. }
  551. }
  552. // post the message if client found
  553. if (j<MAX_PENDING_BUTTONS){
  554. PostMessage( hWndHidServ,
  555. WM_CI_USAGE,
  556. (WPARAM)MakeLongUsage(data->LinkUsage,pPrevious->Usage),
  557. (LPARAM)MakeLongUsage(pPrevious->UsagePage, 0)
  558. );
  559. } else {
  560. WARN(("Button Up client not found (C=%.2x,U=%.2x,P=%.2x)", data->LinkUsage, pPrevious->Usage, pPrevious->UsagePage));
  561. }
  562. }
  563. pPrevious++;
  564. }
  565. // Remember what buttons were down, so next time we can
  566. // detect if they come up.
  567. pPrevious = data->ButtonData.Usages;
  568. data->ButtonData.Usages = data->ButtonData.PrevUsages;
  569. data->ButtonData.PrevUsages = pPrevious;
  570. } else {
  571. TRACE(("Input data is value data:"));
  572. TRACE((" Input Usage Page = %x, Collection = %x", data->UsagePage, data->LinkUsage));
  573. TRACE((" Input Usage = %x", data->ValueData.Usage));
  574. // don't send zeroes or invalid range.
  575. if ( data->ValueData.ScaledValue &&
  576. data->ValueData.LogicalRange){
  577. // post the message
  578. // rescale the data to a standard range
  579. PostMessage(hWndHidServ,
  580. WM_CI_USAGE,
  581. (WPARAM)MakeLongUsage(data->LinkUsage,data->ValueData.Usage),
  582. (LPARAM)MakeLongUsage(data->UsagePage,(USHORT)(((double)data->ValueData.ScaledValue/data->ValueData.LogicalRange)*65536)));
  583. }
  584. }
  585. }
  586. }
  587. void
  588. SendVK(
  589. UCHAR VKey,
  590. SHORT Down
  591. )
  592. {
  593. if (InputThreadEnabled && !InputSessionLocked) {
  594. if (InputSessionId == 0) {
  595. InputVKey = VKey;
  596. InputDown = Down;
  597. InputIsAppCommand = FALSE;
  598. InputIsChar = FALSE;
  599. SetEvent(hInputEvent);
  600. WaitForSingleObject(hInputDoneEvent, INFINITE);
  601. } else {
  602. CrossSessionWindowMessage(Down ? WM_KEYDOWN : WM_KEYUP, VKey, 0);
  603. }
  604. }
  605. }
  606. void
  607. SendChar(
  608. UCHAR wScan,
  609. SHORT Down
  610. )
  611. {
  612. if (InputThreadEnabled && !InputSessionLocked) {
  613. if (InputSessionId == 0) {
  614. InputVKey = wScan;
  615. InputDown = Down;
  616. InputIsAppCommand = FALSE;
  617. InputIsChar = TRUE;
  618. SetEvent(hInputEvent);
  619. WaitForSingleObject(hInputDoneEvent, INFINITE);
  620. } else {
  621. CrossSessionWindowMessage(Down ? WM_KEYDOWN : WM_KEYUP, 0, wScan);
  622. }
  623. }
  624. }
  625. void
  626. SendAppCommand(
  627. USHORT AppCommand
  628. )
  629. {
  630. if (InputThreadEnabled && !InputSessionLocked) {
  631. if (InputSessionId == 0) {
  632. InputAppCommand = AppCommand;
  633. InputIsAppCommand = TRUE;
  634. InputIsChar = FALSE;
  635. SetEvent(hInputEvent);
  636. WaitForSingleObject(hInputDoneEvent, INFINITE);
  637. } else {
  638. CrossSessionWindowMessage(WM_APPCOMMAND, AppCommand, 0);
  639. }
  640. }
  641. }
  642. VOID
  643. VolumeTimerHandler(
  644. WPARAM TimerID
  645. )
  646. /*++
  647. Routine Description:
  648. This timer handler routine is called for all timeouts on auto-repeat capable
  649. contols.
  650. --*/
  651. {
  652. INFO(("Timer triggered, TimerId = %d", TimerID));
  653. WaitForSingleObject(hMutexOOC, INFINITE);
  654. switch (TimerID){
  655. case TIMERID_VOLUMEUP_VK:
  656. if (OOC(TIMERID_VOLUMEUP_VK)){
  657. SendVK(VK_VOLUME_UP, 0x1);
  658. OOC(TIMERID_VOLUMEUP_VK) = SetTimer(hWndHidServ, TIMERID_VOLUMEUP_VK, REPEAT_INTERVAL, NULL);
  659. }
  660. break;
  661. case TIMERID_VOLUMEDN_VK:
  662. if (OOC(TIMERID_VOLUMEDN_VK)){
  663. SendVK(VK_VOLUME_DOWN, 0x1);
  664. OOC(TIMERID_VOLUMEDN_VK) = SetTimer(hWndHidServ, TIMERID_VOLUMEDN_VK, REPEAT_INTERVAL, NULL);
  665. }
  666. break;
  667. case TIMERID_CHANNELUP:
  668. if (OOC(TIMERID_CHANNELUP)){
  669. SendAppCommand(APPCOMMAND_MEDIA_CHANNEL_UP);
  670. OOC(TIMERID_CHANNELUP) = SetTimer(hWndHidServ, TIMERID_CHANNELUP, REPEAT_INTERVAL, NULL);
  671. }
  672. break;
  673. case TIMERID_CHANNELDOWN:
  674. if (OOC(TIMERID_CHANNELDOWN)){
  675. SendAppCommand(APPCOMMAND_MEDIA_CHANNEL_DOWN);
  676. OOC(TIMERID_CHANNELDOWN) = SetTimer(hWndHidServ, TIMERID_CHANNELDOWN, REPEAT_INTERVAL, NULL);
  677. }
  678. break;
  679. case TIMERID_RW:
  680. if (OOC(TIMERID_RW)){
  681. SendAppCommand(APPCOMMAND_MEDIA_REWIND);
  682. OOC(TIMERID_RW) = SetTimer(hWndHidServ, TIMERID_RW, REPEAT_INTERVAL, NULL);
  683. }
  684. break;
  685. case TIMERID_FF:
  686. if (OOC(TIMERID_FF)){
  687. SendAppCommand(APPCOMMAND_MEDIA_FAST_FORWARD);
  688. OOC(TIMERID_FF) = SetTimer(hWndHidServ, TIMERID_FF, REPEAT_INTERVAL, NULL);
  689. }
  690. break;
  691. case TIMERID_VOLUMEUP:
  692. if (OOC(TIMERID_VOLUMEUP)){
  693. SendAppCommand(APPCOMMAND_VOLUME_UP);
  694. OOC(TIMERID_VOLUMEUP) = SetTimer(hWndHidServ, TIMERID_VOLUMEUP, REPEAT_INTERVAL, NULL);
  695. }
  696. break;
  697. case TIMERID_VOLUMEDN:
  698. if (OOC(TIMERID_VOLUMEDN)){
  699. SendAppCommand(APPCOMMAND_VOLUME_DOWN);
  700. OOC(TIMERID_VOLUMEDN) = SetTimer(hWndHidServ, TIMERID_VOLUMEDN, REPEAT_INTERVAL, NULL);
  701. }
  702. break;
  703. case TIMERID_BASSUP:
  704. if (OOC(TIMERID_BASSUP)){
  705. SendAppCommand(APPCOMMAND_BASS_UP);
  706. OOC(TIMERID_BASSUP) = SetTimer(hWndHidServ, TIMERID_BASSUP, REPEAT_INTERVAL, NULL);
  707. }
  708. break;
  709. case TIMERID_BASSDN:
  710. if (OOC(TIMERID_BASSDN)){
  711. SendAppCommand(APPCOMMAND_BASS_DOWN);
  712. OOC(TIMERID_BASSDN) = SetTimer(hWndHidServ, TIMERID_BASSDN, REPEAT_INTERVAL, NULL);
  713. }
  714. break;
  715. case TIMERID_TREBLEUP:
  716. if (OOC(TIMERID_TREBLEUP)){
  717. SendAppCommand(APPCOMMAND_TREBLE_UP);
  718. OOC(TIMERID_TREBLEUP) = SetTimer(hWndHidServ, TIMERID_TREBLEUP, REPEAT_INTERVAL, NULL);
  719. }
  720. break;
  721. case TIMERID_TREBLEDN:
  722. if (OOC(TIMERID_TREBLEDN)){
  723. SendAppCommand(APPCOMMAND_TREBLE_DOWN);
  724. OOC(TIMERID_TREBLEDN) = SetTimer(hWndHidServ, TIMERID_TREBLEDN, REPEAT_INTERVAL, NULL);
  725. }
  726. break;
  727. case TIMERID_APPBACK:
  728. if (OOC(TIMERID_APPBACK)){
  729. SendVK(VK_BROWSER_BACK, 0x1);
  730. OOC(TIMERID_APPBACK) = SetTimer(hWndHidServ, TIMERID_APPBACK, REPEAT_INTERVAL, NULL);
  731. }
  732. break;
  733. case TIMERID_APPFORWARD:
  734. if (OOC(TIMERID_APPFORWARD)){
  735. SendVK(VK_BROWSER_FORWARD, 0x1);
  736. OOC(TIMERID_APPFORWARD) = SetTimer(hWndHidServ, TIMERID_APPFORWARD, REPEAT_INTERVAL, NULL);
  737. }
  738. break;
  739. case TIMERID_PREVTRACK:
  740. if (OOC(TIMERID_PREVTRACK)){
  741. SendVK(VK_MEDIA_PREV_TRACK, 0x1);
  742. OOC(TIMERID_PREVTRACK) = SetTimer(hWndHidServ, TIMERID_PREVTRACK, REPEAT_INTERVAL, NULL);
  743. }
  744. break;
  745. case TIMERID_NEXTTRACK:
  746. if (OOC(TIMERID_NEXTTRACK)){
  747. SendVK(VK_MEDIA_NEXT_TRACK, 0x1);
  748. OOC(TIMERID_NEXTTRACK) = SetTimer(hWndHidServ, TIMERID_NEXTTRACK, REPEAT_INTERVAL, NULL);
  749. }
  750. break;
  751. case TIMERID_KEYPAD_LPAREN:
  752. if (OOC(TIMERID_KEYPAD_LPAREN)) {
  753. SendChar(L'(', 0x1);
  754. OOC(TIMERID_KEYPAD_LPAREN) = SetTimer(hWndHidServ, TIMERID_KEYPAD_LPAREN, REPEAT_INTERVAL, NULL);
  755. }
  756. break;
  757. case TIMERID_KEYPAD_RPAREN:
  758. if (OOC(TIMERID_KEYPAD_RPAREN)) {
  759. SendChar(L')', 0x1);
  760. OOC(TIMERID_KEYPAD_RPAREN) = SetTimer(hWndHidServ, TIMERID_KEYPAD_RPAREN, REPEAT_INTERVAL, NULL);
  761. }
  762. break;
  763. case TIMERID_KEYPAD_AT:
  764. if (OOC(TIMERID_KEYPAD_AT)) {
  765. SendChar(L'@', 0x1);
  766. OOC(TIMERID_KEYPAD_AT) = SetTimer(hWndHidServ, TIMERID_KEYPAD_AT, REPEAT_INTERVAL, NULL);
  767. }
  768. break;
  769. case TIMERID_KEYPAD_EQUAL:
  770. if (OOC(TIMERID_KEYPAD_EQUAL)) {
  771. SendChar(L'=', 0x1);
  772. OOC(TIMERID_KEYPAD_EQUAL) = SetTimer(hWndHidServ, TIMERID_KEYPAD_EQUAL, REPEAT_INTERVAL, NULL);
  773. }
  774. break;
  775. }
  776. ReleaseMutex(hMutexOOC);
  777. }
  778. void
  779. HidRepeaterCharButtonDown(
  780. UINT TimerId,
  781. SHORT Value,
  782. UCHAR WScan
  783. )
  784. {
  785. INFO(("Received update char,value = %d, TimerId = %d", Value, TimerId));
  786. WaitForSingleObject(hMutexOOC, INFINITE);
  787. if (Value){
  788. if (!OOC(TimerId)){
  789. SendChar(WScan, 0x1);
  790. OOC(TimerId) = SetTimer(hWndHidServ, TimerId, INITIAL_WAIT, NULL);
  791. }
  792. } else {
  793. KillTimer(hWndHidServ, TimerId);
  794. OOC(TimerId) = 0;
  795. SendChar(WScan, 0x0);
  796. }
  797. ReleaseMutex(hMutexOOC);
  798. }
  799. void
  800. HidRepeaterVKButtonDown(
  801. UINT TimerId,
  802. SHORT Value,
  803. UCHAR VKey
  804. )
  805. {
  806. INFO(("Received update vk,value = %d, TimerId = %d", Value, TimerId));
  807. WaitForSingleObject(hMutexOOC, INFINITE);
  808. if (Value){
  809. if (!OOC(TimerId)){
  810. SendVK(VKey, 0x1);
  811. OOC(TimerId) = SetTimer(hWndHidServ, TimerId, INITIAL_WAIT, NULL);
  812. }
  813. } else {
  814. KillTimer(hWndHidServ, TimerId);
  815. OOC(TimerId) = 0;
  816. SendVK(VKey, 0x0);
  817. }
  818. ReleaseMutex(hMutexOOC);
  819. }
  820. void
  821. HidServUpdate(
  822. DWORD LongUsage,
  823. DWORD LongValue
  824. )
  825. /*++
  826. Routine Description:
  827. This is the client routine for the default handler. This client attempts to satisfy
  828. input events by injecting appcommands or keypresses to the current input window.
  829. --*/
  830. {
  831. USAGE Collection = (USAGE)HIWORD(LongUsage);
  832. USAGE Usage = (USAGE)LOWORD(LongUsage);
  833. USAGE Page = (USAGE)HIWORD(LongValue);
  834. SHORT Value = (SHORT)LOWORD(LongValue);
  835. BOOLEAN fromSpeaker = ((Usage & HIDSERV_FROM_SPEAKER) == HIDSERV_FROM_SPEAKER);
  836. Usage &= ~HIDSERV_FROM_SPEAKER;
  837. INFO(("Update collection = %x", Collection));
  838. INFO(("Update page = %x", Page));
  839. INFO(("Update usage = %x", Usage));
  840. INFO(("Update data = %d", Value));
  841. if (Collection == CInputCollection_Consumer_Control){
  842. // NOTE: If we ever choose to support this page thing, keep in mind
  843. // that the Altec Lansing ADA 70s report page zero. Should take out
  844. // the consumer page and make it the default.
  845. switch (Page) {
  846. case HID_USAGE_PAGE_UNDEFINED:
  847. case HID_USAGE_PAGE_CONSUMER:
  848. switch (Usage){
  849. /// Button Usages
  850. //
  851. //
  852. // These buttons have auto repeat capability...
  853. // delay for .5 sec before auto repeat kicks in.
  854. //
  855. case CInputUsage_Volume_Increment:
  856. INFO(("Volume increment."));
  857. if (fromSpeaker) {
  858. INFO(("From speaker."));
  859. WaitForSingleObject(hMutexOOC, INFINITE);
  860. if (Value){
  861. if (!OOC(TIMERID_VOLUMEUP)){
  862. SendAppCommand(APPCOMMAND_VOLUME_UP);
  863. OOC(TIMERID_VOLUMEUP) = SetTimer(hWndHidServ, TIMERID_VOLUMEUP, INITIAL_WAIT, NULL);
  864. }
  865. } else {
  866. KillTimer(hWndHidServ, TIMERID_VOLUMEUP);
  867. OOC(TIMERID_VOLUMEUP) = 0;
  868. }
  869. ReleaseMutex(hMutexOOC);
  870. } else {
  871. INFO(("From keyboard."));
  872. HidRepeaterVKButtonDown(TIMERID_VOLUMEUP_VK, Value, VK_VOLUME_UP);
  873. }
  874. break;
  875. case CInputUsage_Volume_Decrement:
  876. INFO(("Volume decrement."));
  877. if (fromSpeaker) {
  878. INFO(("From speaker."));
  879. WaitForSingleObject(hMutexOOC, INFINITE);
  880. if (Value){
  881. if (!OOC(TIMERID_VOLUMEDN)){
  882. SendAppCommand(APPCOMMAND_VOLUME_DOWN);
  883. OOC(TIMERID_VOLUMEDN) = SetTimer(hWndHidServ, TIMERID_VOLUMEDN, INITIAL_WAIT, NULL);
  884. }
  885. } else {
  886. KillTimer(hWndHidServ, TIMERID_VOLUMEDN);
  887. OOC(TIMERID_VOLUMEDN) = 0;
  888. }
  889. ReleaseMutex(hMutexOOC);
  890. } else {
  891. INFO(("From keyboard."));
  892. HidRepeaterVKButtonDown(TIMERID_VOLUMEDN_VK, Value, VK_VOLUME_DOWN);
  893. }
  894. break;
  895. case CInputUsage_App_Back:
  896. INFO(("App Back."));
  897. HidRepeaterVKButtonDown(TIMERID_APPBACK, Value, VK_BROWSER_BACK);
  898. break;
  899. case CInputUsage_App_Forward:
  900. INFO(("App Forward."));
  901. HidRepeaterVKButtonDown(TIMERID_APPFORWARD, Value, VK_BROWSER_FORWARD);
  902. break;
  903. case CInputUsage_Scan_Previous_Track:
  904. INFO(("Media Previous Track."));
  905. HidRepeaterVKButtonDown(TIMERID_PREVTRACK, Value, VK_MEDIA_PREV_TRACK);
  906. break;
  907. case CInputUsage_Scan_Next_Track:
  908. INFO(("Media Next Track."));
  909. HidRepeaterVKButtonDown(TIMERID_NEXTTRACK, Value, VK_MEDIA_NEXT_TRACK);
  910. break;
  911. case CInputUsage_Bass_Increment:
  912. INFO(("Bass increment."));
  913. WaitForSingleObject(hMutexOOC, INFINITE);
  914. if (Value){
  915. if (!OOC(TIMERID_BASSUP)){
  916. SendAppCommand(APPCOMMAND_BASS_UP);
  917. OOC(TIMERID_BASSUP) = SetTimer(hWndHidServ, TIMERID_BASSUP, INITIAL_WAIT, NULL);
  918. }
  919. } else {
  920. KillTimer(hWndHidServ, TIMERID_BASSUP);
  921. OOC(TIMERID_BASSUP) = 0;
  922. }
  923. ReleaseMutex(hMutexOOC);
  924. break;
  925. case CInputUsage_Bass_Decrement:
  926. INFO(("Bass decrement."));
  927. WaitForSingleObject(hMutexOOC, INFINITE);
  928. if (Value){
  929. if (!OOC(TIMERID_BASSDN)){
  930. SendAppCommand(APPCOMMAND_BASS_DOWN);
  931. OOC(TIMERID_BASSDN) = SetTimer(hWndHidServ, TIMERID_BASSDN, INITIAL_WAIT, NULL);
  932. }
  933. } else {
  934. KillTimer(hWndHidServ, TIMERID_BASSDN);
  935. OOC(TIMERID_BASSDN) = 0;
  936. }
  937. ReleaseMutex(hMutexOOC);
  938. break;
  939. case CInputUsage_Treble_Increment:
  940. INFO(("Treble increment."));
  941. WaitForSingleObject(hMutexOOC, INFINITE);
  942. if (Value){
  943. if (!OOC(TIMERID_TREBLEUP)){
  944. SendAppCommand(APPCOMMAND_TREBLE_UP);
  945. OOC(TIMERID_TREBLEUP) = SetTimer(hWndHidServ, TIMERID_TREBLEUP, INITIAL_WAIT, NULL);
  946. }
  947. } else {
  948. KillTimer(hWndHidServ, TIMERID_TREBLEUP);
  949. OOC(TIMERID_TREBLEUP) = 0;
  950. }
  951. ReleaseMutex(hMutexOOC);
  952. break;
  953. case CInputUsage_Treble_Decrement:
  954. INFO(("Treble decrement."));
  955. WaitForSingleObject(hMutexOOC, INFINITE);
  956. if (Value){
  957. if (!OOC(TIMERID_TREBLEDN)){
  958. SendAppCommand(APPCOMMAND_TREBLE_DOWN);
  959. OOC(TIMERID_TREBLEDN) = SetTimer(hWndHidServ, TIMERID_TREBLEDN, INITIAL_WAIT, NULL);
  960. }
  961. } else {
  962. KillTimer(hWndHidServ, TIMERID_TREBLEDN);
  963. OOC(TIMERID_TREBLEDN) = 0;
  964. }
  965. ReleaseMutex(hMutexOOC);
  966. break;
  967. // eHome remote control buttons
  968. case CInputUsage_Fast_Forward:
  969. INFO(("Fast Forward."));
  970. WaitForSingleObject(hMutexOOC, INFINITE);
  971. if (Value){
  972. if (!OOC(TIMERID_FF)){
  973. SendAppCommand(APPCOMMAND_MEDIA_FAST_FORWARD);
  974. OOC(TIMERID_FF) = SetTimer(hWndHidServ, TIMERID_FF, INITIAL_WAIT, NULL);
  975. }
  976. } else {
  977. KillTimer(hWndHidServ, TIMERID_FF);
  978. OOC(TIMERID_FF) = 0;
  979. }
  980. ReleaseMutex(hMutexOOC);
  981. break;
  982. case CInputUsage_Rewind:
  983. INFO(("Fast Forward."));
  984. WaitForSingleObject(hMutexOOC, INFINITE);
  985. if (Value){
  986. if (!OOC(TIMERID_RW)){
  987. SendAppCommand(APPCOMMAND_MEDIA_REWIND);
  988. OOC(TIMERID_RW) = SetTimer(hWndHidServ, TIMERID_RW, INITIAL_WAIT, NULL);
  989. }
  990. } else {
  991. KillTimer(hWndHidServ, TIMERID_RW);
  992. OOC(TIMERID_RW) = 0;
  993. }
  994. ReleaseMutex(hMutexOOC);
  995. break;
  996. case CInputUsage_Channel_Increment:
  997. INFO(("Fast Forward."));
  998. WaitForSingleObject(hMutexOOC, INFINITE);
  999. if (Value){
  1000. if (!OOC(TIMERID_CHANNELUP)){
  1001. SendAppCommand(APPCOMMAND_MEDIA_CHANNEL_UP);
  1002. OOC(TIMERID_CHANNELUP) = SetTimer(hWndHidServ, TIMERID_CHANNELUP, INITIAL_WAIT, NULL);
  1003. }
  1004. } else {
  1005. KillTimer(hWndHidServ, TIMERID_CHANNELUP);
  1006. OOC(TIMERID_CHANNELUP) = 0;
  1007. }
  1008. ReleaseMutex(hMutexOOC);
  1009. break;
  1010. case CInputUsage_Channel_Decrement:
  1011. INFO(("Fast Forward."));
  1012. WaitForSingleObject(hMutexOOC, INFINITE);
  1013. if (Value){
  1014. if (!OOC(TIMERID_CHANNELDOWN)){
  1015. SendAppCommand(APPCOMMAND_MEDIA_CHANNEL_DOWN);
  1016. OOC(TIMERID_CHANNELDOWN) = SetTimer(hWndHidServ, TIMERID_CHANNELDOWN, INITIAL_WAIT, NULL);
  1017. }
  1018. } else {
  1019. KillTimer(hWndHidServ, TIMERID_CHANNELDOWN);
  1020. OOC(TIMERID_CHANNELDOWN) = 0;
  1021. }
  1022. ReleaseMutex(hMutexOOC);
  1023. break;
  1024. // These buttons do not auto repeat...
  1025. // eHome remote control buttons
  1026. case CInputUsage_Play:
  1027. if (Value){
  1028. INFO(("Play."));
  1029. SendAppCommand(APPCOMMAND_MEDIA_PLAY);
  1030. }
  1031. break;
  1032. case CInputUsage_Pause:
  1033. if (Value){
  1034. INFO(("Pause."));
  1035. SendAppCommand(APPCOMMAND_MEDIA_PAUSE);
  1036. }
  1037. break;
  1038. case CInputUsage_Record:
  1039. if (Value){
  1040. INFO(("Record."));
  1041. SendAppCommand(APPCOMMAND_MEDIA_RECORD);
  1042. }
  1043. break;
  1044. // regular
  1045. case CInputUsage_Loudness:
  1046. if (Value){
  1047. INFO(("Toggle Loudness."));
  1048. //SendAppCommandEx(??);
  1049. }
  1050. break;
  1051. case CInputUsage_Bass_Boost:
  1052. if (Value) {
  1053. INFO(("Toggle BassBoost."));
  1054. SendAppCommand(APPCOMMAND_BASS_BOOST);
  1055. }
  1056. break;
  1057. case CInputUsage_Mute:
  1058. INFO(("Toggle Mute."));
  1059. if (fromSpeaker) {
  1060. INFO(("From speaker."));
  1061. if (Value) {
  1062. SendAppCommand(APPCOMMAND_VOLUME_MUTE);
  1063. }
  1064. } else {
  1065. INFO(("From keyboard."));
  1066. SendVK(VK_VOLUME_MUTE, Value);
  1067. }
  1068. break;
  1069. case CInputUsage_Play_Pause:
  1070. INFO(("Media Play/Pause."));
  1071. SendVK(VK_MEDIA_PLAY_PAUSE, Value);
  1072. break;
  1073. case CInputUsage_Stop:
  1074. INFO(("Media Stop."));
  1075. SendVK(VK_MEDIA_STOP, Value);
  1076. break;
  1077. case CInputUsage_Launch_Configuration:
  1078. INFO(("Launch Configuration."));
  1079. SendVK(VK_LAUNCH_MEDIA_SELECT, Value);
  1080. break;
  1081. case CInputUsage_Launch_Email:
  1082. INFO(("Launch Email."));
  1083. SendVK(VK_LAUNCH_MAIL, Value);
  1084. break;
  1085. case CInputUsage_Launch_Calculator:
  1086. INFO(("Launch Calculator."));
  1087. SendVK(VK_LAUNCH_APP2, Value);
  1088. break;
  1089. case CInputUsage_Launch_Browser:
  1090. INFO(("Launch Browser."));
  1091. SendVK(VK_LAUNCH_APP1, Value);
  1092. break;
  1093. case CInputUsage_App_Search:
  1094. INFO(("App Search."));
  1095. SendVK(VK_BROWSER_SEARCH, Value);
  1096. break;
  1097. case CInputUsage_App_Home:
  1098. INFO(("App Home."));
  1099. SendVK(VK_BROWSER_HOME, Value);
  1100. break;
  1101. case CInputUsage_App_Stop:
  1102. INFO(("App Stop."));
  1103. SendVK(VK_BROWSER_STOP, Value);
  1104. break;
  1105. case CInputUsage_App_Refresh:
  1106. INFO(("App Refresh."));
  1107. SendVK(VK_BROWSER_REFRESH, Value);
  1108. break;
  1109. case CInputUsage_App_Bookmarks:
  1110. INFO(("App Bookmarks."));
  1111. SendVK(VK_BROWSER_FAVORITES, Value);
  1112. break;
  1113. case CInputUsage_App_Previous:
  1114. if (Value){
  1115. INFO(("App Previous."));
  1116. //SendAppCommand(??);
  1117. }
  1118. break;
  1119. case CInputUsage_App_Next:
  1120. if (Value){
  1121. INFO(("App Next."));
  1122. //SendAppCommand(??);
  1123. }
  1124. break;
  1125. #if(0)
  1126. // New buttons
  1127. case CInputUsage_App_Help:
  1128. if (Value) {
  1129. INFO(("App Help"));
  1130. SendAppCommand(APPCOMMAND_HELP);
  1131. }
  1132. break;
  1133. case CInputUsage_App_Find:
  1134. if (Value) {
  1135. INFO(("App Find"));
  1136. SendAppCommand(APPCOMMAND_FIND);
  1137. }
  1138. break;
  1139. case CInputUsage_App_New:
  1140. if (Value) {
  1141. INFO(("App New"));
  1142. SendAppCommand(APPCOMMAND_NEW);
  1143. }
  1144. break;
  1145. case CInputUsage_App_Open:
  1146. if (Value) {
  1147. INFO(("App Open"));
  1148. SendAppCommand(APPCOMMAND_OPEN);
  1149. }
  1150. break;
  1151. case CInputUsage_App_Close:
  1152. if (Value) {
  1153. INFO(("App Close"));
  1154. SendAppCommand(APPCOMMAND_CLOSE);
  1155. }
  1156. break;
  1157. case CInputUsage_App_Save:
  1158. if (Value) {
  1159. INFO(("App Save"));
  1160. SendAppCommand(APPCOMMAND_SAVE);
  1161. }
  1162. break;
  1163. case CInputUsage_App_Print:
  1164. if (Value) {
  1165. INFO(("App Print"));
  1166. SendAppCommand(APPCOMMAND_PRINT);
  1167. }
  1168. break;
  1169. case CInputUsage_App_Undo:
  1170. if (Value) {
  1171. INFO(("App Undo"));
  1172. SendAppCommand(APPCOMMAND_UNDO);
  1173. }
  1174. break;
  1175. case CInputUsage_App_Redo:
  1176. if (Value) {
  1177. INFO(("App Redo"));
  1178. SendAppCommand(APPCOMMAND_REDO);
  1179. }
  1180. break;
  1181. case CInputUsage_App_Copy:
  1182. if (Value) {
  1183. INFO(("App Copy"));
  1184. SendAppCommand(APPCOMMAND_COPY);
  1185. }
  1186. break;
  1187. case CInputUsage_App_Cut:
  1188. if (Value) {
  1189. INFO(("App Cut"));
  1190. SendAppCommand(APPCOMMAND_CUT);
  1191. }
  1192. break;
  1193. case CInputUsage_App_Paste:
  1194. if (Value) {
  1195. INFO(("App Paste"));
  1196. SendAppCommand(APPCOMMAND_PASTE);
  1197. }
  1198. break;
  1199. case CInputUsage_App_Reply_To_Mail:
  1200. if (Value) {
  1201. INFO(("App Reply To Mail"));
  1202. SendAppCommand(APPCOMMAND_REPLY_TO_MAIL);
  1203. }
  1204. break;
  1205. case CInputUsage_App_Forward_Mail:
  1206. if (Value) {
  1207. INFO(("App Forward Mail"));
  1208. SendAppCommand(APPCOMMAND_FORWARD_MAIL);
  1209. }
  1210. break;
  1211. case CInputUsage_App_Send_Mail:
  1212. if (Value) {
  1213. INFO(("App Send Mail"));
  1214. SendAppCommand(APPCOMMAND_SEND_MAIL);
  1215. }
  1216. break;
  1217. case CInputUsage_App_Spell_Check:
  1218. if (Value) {
  1219. INFO(("App Spell Check"));
  1220. SendAppCommand(APPCOMMAND_SPELL_CHECK);
  1221. }
  1222. break;
  1223. #endif
  1224. /// Value Usages
  1225. // These are not buttons, but are "value" events and do not have
  1226. // a corresponding button up event. Also, these never have an
  1227. // auto repeat function.
  1228. case CInputUsage_Volume:
  1229. INFO(("Volume dial"));
  1230. if (Value>0) SendAppCommand(APPCOMMAND_VOLUME_UP);
  1231. else if (Value<0)SendAppCommand(APPCOMMAND_VOLUME_DOWN);
  1232. break;
  1233. case CInputUsage_Bass:
  1234. INFO(("Bass dial"));
  1235. if (Value>0) SendAppCommand(APPCOMMAND_BASS_UP);
  1236. else if (Value<0)SendAppCommand(APPCOMMAND_BASS_DOWN);
  1237. break;
  1238. case CInputUsage_Treble:
  1239. INFO(("Treble dial"));
  1240. if (Value>0) SendAppCommand(APPCOMMAND_TREBLE_UP);
  1241. else if (Value<0)SendAppCommand(APPCOMMAND_TREBLE_DOWN);
  1242. break;
  1243. ////
  1244. /// Media Select usages are not handled in this sample.
  1245. //
  1246. default:
  1247. INFO(("Unhandled Usage (%x)", Usage));
  1248. break;
  1249. }
  1250. break;
  1251. #if(0)
  1252. case HID_USAGE_PAGE_KEYBOARD:
  1253. switch (Usage) {
  1254. case CInputUsage_Keypad_Equals:
  1255. INFO(("Keypad ="));
  1256. HidRepeaterCharButtonDown(TIMERID_KEYPAD_EQUAL, Value, L'=');
  1257. break;
  1258. case CInputUsage_Keypad_LParen:
  1259. INFO(("Keypad ("));
  1260. HidRepeaterCharButtonDown(TIMERID_KEYPAD_LPAREN, Value, L'(');
  1261. break;
  1262. case CInputUsage_Keypad_RParen:
  1263. INFO(("Keypad )"));
  1264. HidRepeaterCharButtonDown(TIMERID_KEYPAD_RPAREN, Value, L')');
  1265. break;
  1266. case CInputUsage_Keypad_At:
  1267. INFO(("Keypad @"));
  1268. HidRepeaterCharButtonDown(TIMERID_KEYPAD_AT, Value, L'@');
  1269. break;
  1270. }
  1271. break;
  1272. #endif
  1273. default:
  1274. INFO(("Unhandled Page (%x)", Page));
  1275. break;
  1276. }
  1277. } else {
  1278. INFO(("Unhandled Collection (%x), usage = %x", Collection, Usage));
  1279. }
  1280. }
  1281. BOOL
  1282. DeviceChangeHandler(
  1283. WPARAM wParam,
  1284. LPARAM lParam
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. This is the handler for WM_DEVICECHANGE messages and is called
  1289. whenever a device node is added or removed in the system. This
  1290. event will cause us to refrsh our device information.
  1291. --*/
  1292. {
  1293. struct _DEV_BROADCAST_HEADER *pdbhHeader;
  1294. pdbhHeader = (struct _DEV_BROADCAST_HEADER *)lParam;
  1295. switch (wParam) {
  1296. case DBT_DEVICEQUERYREMOVE :
  1297. TRACE(("DBT_DEVICEQUERYREMOVE, fall through to..."));
  1298. //
  1299. // Fall thru.
  1300. //
  1301. case DBT_DEVICEREMOVECOMPLETE:
  1302. TRACE(("DBT_DEVICEREMOVECOMPLETE"));
  1303. TRACE(("dbcd_devicetype %x", pdbhHeader->dbcd_devicetype));
  1304. if (pdbhHeader->dbcd_devicetype==DBT_DEVTYP_HANDLE)
  1305. {
  1306. PDEV_BROADCAST_HANDLE pdbHandle = (PDEV_BROADCAST_HANDLE)lParam;
  1307. INFO(("Closing HID device (%x).", pdbHandle->dbch_handle));
  1308. DestroyDeviceByHandle(pdbHandle->dbch_handle);
  1309. break;
  1310. }
  1311. break;
  1312. case DBT_DEVICEQUERYREMOVEFAILED:
  1313. TRACE(("DBT_DEVICEQUERYREMOVEFAILED, fall through to..."));
  1314. // The notification handle has already been closed
  1315. // so we should never actually get this message. If we do,
  1316. // falling through to device arrival is the correct thing to do.
  1317. //
  1318. // Fall thru.
  1319. //
  1320. case DBT_DEVICEARRIVAL:
  1321. TRACE(("DBT_DEVICEARRIVAL: reenumerate"));
  1322. TRACE(("dbcd_devicetype %x", pdbhHeader->dbcd_devicetype));
  1323. if (pdbhHeader->dbcd_devicetype==DBT_DEVTYP_DEVICEINTERFACE)
  1324. {
  1325. // We will refresh our device info for any devnode arrival or removal.
  1326. INFO(("HID device refresh."));
  1327. PostMessage(hWndHidServ, WM_HIDSERV_PNP_HID, 0, 0);
  1328. break;
  1329. }
  1330. }
  1331. return TRUE;
  1332. }
  1333. VOID
  1334. HidKeyboardSettingsChange(WPARAM WParam)
  1335. {
  1336. if (WParam == SPI_SETKEYBOARDSPEED ||
  1337. WParam == SPI_SETKEYBOARDDELAY) {
  1338. DWORD dwV;
  1339. int v;
  1340. //
  1341. // The repeat rate has changed. Adjust the timer interval.
  1342. // The keyboard delay has changed. Adjust the timer interval.
  1343. //
  1344. INFO(("Getting keyboard repeat rate."));
  1345. SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &dwV, 0);
  1346. REPEAT_INTERVAL = 400 - (12*dwV);
  1347. INFO(("Getting keyboard delay."));
  1348. SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &v, 0);
  1349. INITIAL_WAIT = (1+v)*250;
  1350. }
  1351. }
  1352. LRESULT
  1353. CALLBACK
  1354. HidServProc(
  1355. HWND hWnd,
  1356. UINT uMsg,
  1357. WPARAM wParam,
  1358. LPARAM lParam
  1359. )
  1360. /*++
  1361. Routine Description:
  1362. The primary message queue for the app.
  1363. --*/
  1364. {
  1365. TRACE(("HidServProc uMsg=%x", uMsg));
  1366. switch (uMsg)
  1367. {
  1368. // init
  1369. case WM_CREATE :
  1370. TRACE(("WM_CREATE"));
  1371. //
  1372. // Find out the default key values
  1373. //
  1374. HidKeyboardSettingsChange(SPI_SETKEYBOARDSPEED);
  1375. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1376. break;
  1377. // start
  1378. case WM_HIDSERV_START :
  1379. TRACE(("WM_HIDSERV_START"));
  1380. HidServStart();
  1381. break;
  1382. // stop
  1383. case WM_HIDSERV_STOP :
  1384. TRACE(("WM_HIDSERV_STOP"));
  1385. HidServStop();
  1386. break;
  1387. // configuration change
  1388. case WM_DEVICECHANGE:
  1389. TRACE(("WM_DEVICECHANGE"));
  1390. DeviceChangeHandler(wParam, lParam);
  1391. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1392. break;
  1393. // Process Consumer Input usage
  1394. case WM_CI_USAGE:
  1395. TRACE(("WM_CI_USAGE"));
  1396. HidServUpdate((DWORD)wParam, (DWORD)lParam);
  1397. break;
  1398. // HID device list refresh.
  1399. case WM_HIDSERV_PNP_HID:
  1400. TRACE(("WM_HIDSERV_PNP_HID"));
  1401. if (PnpEnabled){
  1402. INFO(("HID DeviceChange rebuild."));
  1403. RebuildHidDeviceList();
  1404. TRACE(("DeviceChange rebuild done."));
  1405. }
  1406. break;
  1407. #if WIN95_BUILD
  1408. // Stop the specified hid device that has already been removed from
  1409. // the global list.
  1410. case WM_HIDSERV_STOP_DEVICE:
  1411. StopHidDevice((PHID_DEVICE) lParam);
  1412. break;
  1413. #endif // WIN95_BUILD
  1414. // Process Timer
  1415. case WM_TIMER:
  1416. TRACE(("WM_TIMER"));
  1417. // All auto-repeat controls handled here.
  1418. VolumeTimerHandler(wParam); // wParam is Timer ID.
  1419. break;
  1420. // Usually an app need not respond to suspend/resume events, but there
  1421. // have been problems with keeping some system handles open. So on
  1422. // suspend, we close everything down except this message loop. On resume,
  1423. // we bring it all back.
  1424. case WM_POWERBROADCAST:
  1425. TRACE(("WM_POWERBROADCAST"));
  1426. switch ( (DWORD)wParam )
  1427. {
  1428. case PBT_APMQUERYSUSPEND:
  1429. TRACE(("\tPBT_APMQUERYSUSPEND"));
  1430. HidservSetPnP(FALSE);
  1431. break;
  1432. case PBT_APMQUERYSUSPENDFAILED:
  1433. TRACE(("\tPBT_APMQUERYSUSPENDFAILED"));
  1434. HidservSetPnP(TRUE);
  1435. break;
  1436. case PBT_APMSUSPEND:
  1437. TRACE(("\tPBT_APMSUSPEND"));
  1438. // Handle forced suspend
  1439. if(PnpEnabled) {
  1440. // Prevent any device refresh.
  1441. HidservSetPnP(FALSE);
  1442. }
  1443. break;
  1444. case PBT_APMRESUMESUSPEND:
  1445. TRACE(("\tPBT_APMRESUMESUSPEND"));
  1446. HidservSetPnP(TRUE);
  1447. break;
  1448. case PBT_APMRESUMEAUTOMATIC:
  1449. TRACE(("\tPBT_APMRESUMEAUTOMATIC"));
  1450. HidservSetPnP(TRUE);
  1451. break;
  1452. }
  1453. break;
  1454. // close
  1455. case WM_CLOSE :
  1456. TRACE(("WM_CLOSE"));
  1457. HidServExit();
  1458. PostMessage(hWndHidServ, WM_QUIT, 0, 0);
  1459. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1460. break;
  1461. case WM_WTSSESSION_CHANGE:
  1462. WARN(("WM_WTSSESSION_CHANGE type %x, session %d", wParam, lParam));
  1463. switch (wParam) {
  1464. case WTS_CONSOLE_CONNECT:
  1465. InputSessionId = (ULONG)lParam;
  1466. InputSessionLocked = FALSE;
  1467. break;
  1468. case WTS_CONSOLE_DISCONNECT:
  1469. if (InputSessionId == (ULONG)lParam) {
  1470. InputSessionId = 0;
  1471. }
  1472. break;
  1473. case WTS_SESSION_LOCK:
  1474. if (InputSessionId == (ULONG)lParam) {
  1475. InputSessionLocked = TRUE;
  1476. }
  1477. break;
  1478. case WTS_SESSION_UNLOCK:
  1479. if (InputSessionId == (ULONG)lParam) {
  1480. InputSessionLocked = FALSE;
  1481. }
  1482. break;
  1483. }
  1484. break;
  1485. case WM_SETTINGCHANGE:
  1486. HidKeyboardSettingsChange(wParam);
  1487. TRACE(("WM_SETTINGCHANGE"));
  1488. default:
  1489. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  1490. }
  1491. return FALSE;
  1492. }