Leaked source code of windows server 2003
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.

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