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.

626 lines
21 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. tabdev.cpp
  5. Abstract:
  6. This module contains tablet device functions.
  7. Author:
  8. Michael Tsang (MikeTs) 01-Jun-2000
  9. Environment:
  10. User mode
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. /*++
  15. @doc INTERNAL
  16. @func unsigned | DeviceThread | Device thread.
  17. @parm IN OUT PDEVICE_DATA | pdevdata | Points to device data.
  18. @rvalue Always returns 0.
  19. --*/
  20. unsigned __stdcall
  21. DeviceThread(
  22. IN PVOID param
  23. )
  24. {
  25. TRACEPROC("DeviceThread", 2)
  26. PDEVICE_DATA pdevdata = (PDEVICE_DATA)param;
  27. BOOL fDigitizer = (pdevdata == &gdevDigitizer);
  28. BOOL fSuccess = TRUE;
  29. TRACEENTER(("(pdevdata=%p,Thread=%s)\n",
  30. pdevdata, fDigitizer? "Digitizer": "Buttons"));
  31. // Bump our priority so we can service device data ASAP.
  32. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  33. if (OpenTabletDevice(pdevdata))
  34. {
  35. OVERLAPPED overLapped;
  36. HANDLE ahWait[2];
  37. PCHAR apBuf[2];
  38. // Initialize the OVERLAPPED structure for ReadFile
  39. overLapped.Offset = overLapped.OffsetHigh = 0;
  40. overLapped.hEvent = CreateEvent(NULL, // default security
  41. FALSE, // auto-reset event
  42. FALSE, // initially unset
  43. NULL); // no name
  44. TRACEASSERT(overLapped.hEvent != NULL);
  45. // Create the array of event handles to wait upon (below)
  46. ahWait[0] = pdevdata->hStopDeviceEvent;
  47. ahWait[1] = overLapped.hEvent;
  48. // Allocate and zero-init a couple of buffers for device reports
  49. apBuf[0] = (PCHAR)calloc(pdevdata->hidCaps.InputReportByteLength,
  50. sizeof(CHAR));
  51. apBuf[1] = (PCHAR)calloc(pdevdata->hidCaps.InputReportByteLength,
  52. sizeof(CHAR));
  53. TRACEASSERT(apBuf[0] && apBuf[1]);
  54. // Allocate a buffer for HID report button states
  55. pdevdata->dwcButtons = HidP_MaxUsageListLength(HidP_Input,
  56. 0,
  57. pdevdata->pPreParsedData);
  58. if (pdevdata->dwcButtons > 0)
  59. {
  60. pdevdata->pDownButtonUsages = (PUSAGE)malloc(pdevdata->dwcButtons*
  61. sizeof(USAGE));
  62. TRACEASSERT(pdevdata->pDownButtonUsages);
  63. }
  64. else
  65. {
  66. pdevdata->pDownButtonUsages = NULL;
  67. }
  68. if (fDigitizer)
  69. {
  70. // Determine the digitizer's (default) max X & Y values for scaling
  71. // the reports later
  72. GetMinMax(HID_USAGE_PAGE_GENERIC,
  73. HID_USAGE_GENERIC_X,
  74. &gdwMinX,
  75. &gdwMaxX);
  76. gdwRngX = gdwMaxX - gdwMinX;
  77. GetMinMax(HID_USAGE_PAGE_GENERIC,
  78. HID_USAGE_GENERIC_Y,
  79. &gdwMinY, &gdwMaxY);
  80. gdwRngY = gdwMaxY - gdwMinY;
  81. #ifdef DRAW_INK
  82. ghwndDrawInk = GetDesktopWindow();
  83. #endif
  84. }
  85. PTSTHREAD pThread = FindThread(fDigitizer?
  86. TSF_DIGITHREAD: TSF_BUTTONTHREAD);
  87. while (fSuccess && !(gdwfTabSrv & TSF_TERMINATE))
  88. {
  89. if (SwitchThreadToInputDesktop(pThread))
  90. {
  91. BOOL fImpersonate = FALSE;
  92. int iBufIdx = 0;
  93. DWORD dwBytesRead;
  94. fImpersonate = ImpersonateCurrentUser();
  95. // Issue an overlapped read to get a device (input) report
  96. if (ReadReportOverlapped(pdevdata,
  97. apBuf[iBufIdx],
  98. &dwBytesRead,
  99. &overLapped))
  100. {
  101. DWORD rcWait;
  102. MSG Msg;
  103. for (;;)
  104. {
  105. // Wait for the read to complete, or for the termination
  106. // event to be set
  107. if (fDigitizer)
  108. {
  109. rcWait = WaitForMultipleObjectsEx(2,
  110. ahWait,
  111. FALSE,
  112. INFINITE,
  113. FALSE);
  114. }
  115. else
  116. {
  117. rcWait = MsgWaitForMultipleObjects(2,
  118. ahWait,
  119. FALSE,
  120. INFINITE,
  121. QS_TIMER);
  122. }
  123. if (rcWait == WAIT_OBJECT_0)
  124. {
  125. // The terminate device event was set.
  126. break;
  127. }
  128. else if (rcWait == WAIT_OBJECT_0 + 1)
  129. {
  130. DWORD dwcb;
  131. // Previous read has completed, swap the buffer
  132. // pointer and issue another overlapped read
  133. // before processing this report.
  134. PCHAR pBufLast = apBuf[iBufIdx];
  135. iBufIdx ^= 1;
  136. if (!GetOverlappedResult(pdevdata->hDevice,
  137. &overLapped,
  138. &dwcb,
  139. FALSE))
  140. {
  141. TRACEWARN(("GetOverlappedResult failed (err=%d).\n",
  142. GetLastError()));
  143. fSuccess = FALSE;
  144. }
  145. else
  146. {
  147. if (!ReadReportOverlapped(pdevdata,
  148. apBuf[iBufIdx],
  149. &dwBytesRead,
  150. &overLapped))
  151. {
  152. TABSRVERR(("Read error getting device report (err=%d)",
  153. GetLastError()));
  154. fSuccess = FALSE;
  155. break;
  156. }
  157. if (fDigitizer)
  158. {
  159. ProcessDigitizerReport(pBufLast);
  160. }
  161. else
  162. {
  163. ProcessButtonsReport(pBufLast);
  164. }
  165. }
  166. }
  167. else if (!fDigitizer &&
  168. PeekMessage(&Msg,
  169. NULL,
  170. WM_TIMER,
  171. WM_TIMER,
  172. PM_REMOVE | PM_NOYIELD))
  173. {
  174. ((TIMERPROC)Msg.lParam)(Msg.hwnd,
  175. Msg.message,
  176. Msg.wParam,
  177. Msg.time);
  178. }
  179. else
  180. {
  181. TRACEWARN(("WaitForMultipleObject failed (rcWait=%d,err=%d)\n",
  182. rcWait, GetLastError()));
  183. }
  184. }
  185. CancelIo(pdevdata->hDevice);
  186. }
  187. else
  188. {
  189. TABSRVERR(("Read error getting device report (err=%d)",
  190. GetLastError()));
  191. fSuccess = FALSE;
  192. }
  193. if (fImpersonate)
  194. {
  195. RevertToSelf();
  196. }
  197. }
  198. else
  199. {
  200. TABSRVERR(("Failed to set current desktop.\n"));
  201. fSuccess = FALSE;
  202. }
  203. }
  204. if (pdevdata->pDownButtonUsages)
  205. {
  206. free(pdevdata->pDownButtonUsages);
  207. pdevdata->pDownButtonUsages = NULL;
  208. }
  209. free(apBuf[0]);
  210. free(apBuf[1]);
  211. CloseHandle(overLapped.hEvent);
  212. CloseTabletDevice(pdevdata);
  213. }
  214. else
  215. {
  216. TABSRVERR(("Failed to open %s device.\n",
  217. fDigitizer? "Digitizer": "Buttons"));
  218. }
  219. TRACEEXIT(("=0\n"));
  220. return 0;
  221. } //DeviceThread
  222. /*++
  223. @doc INTERNAL
  224. @func BOOL | OpenTabletDevice | Open and initialize the tablet device.
  225. @parm IN OUT PDEVICE_DATA | pDevData | Points to the tablet device data.
  226. @rvalue SUCCESS | Returns TRUE.
  227. @rvalue FAILURE | Returns FALSE.
  228. --*/
  229. BOOL
  230. OpenTabletDevice(
  231. IN OUT PDEVICE_DATA pDevData
  232. )
  233. {
  234. TRACEPROC("OpenTabletDevice", 2)
  235. BOOL rc = FALSE;
  236. GUID hidGuid;
  237. HDEVINFO hDevInfo;
  238. TRACEENTER(("(pDevData=%p,UsagePage=%x,Usage=%x)\n",
  239. pDevData, pDevData->UsagePage, pDevData->Usage));
  240. pDevData->hDevice = INVALID_HANDLE_VALUE;
  241. // Get the GUID for HID devices
  242. HidD_GetHidGuid(&hidGuid);
  243. // Get handle to present HID devices
  244. hDevInfo = SetupDiGetClassDevs(&hidGuid,
  245. NULL,
  246. NULL,
  247. (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
  248. if (hDevInfo != INVALID_HANDLE_VALUE)
  249. {
  250. ULONG i;
  251. // Enumerate the HID devices, looking for the digitizer and button devices
  252. for (i = 0; ; ++i)
  253. {
  254. SP_DEVICE_INTERFACE_DATA devInterface;
  255. devInterface.cbSize = sizeof(devInterface);
  256. // First we have to enumerate the device interfaces
  257. if (SetupDiEnumDeviceInterfaces(hDevInfo,
  258. 0,
  259. &hidGuid,
  260. i,
  261. &devInterface))
  262. {
  263. // Then we get the interface detail information (including device pathname)
  264. PSP_DEVICE_INTERFACE_DETAIL_DATA pIfDetail;
  265. pIfDetail = GetDeviceInterfaceDetail(hDevInfo, &devInterface);
  266. TRACEASSERT(pIfDetail != 0);
  267. if (pIfDetail != 0)
  268. {
  269. DEVICE_DATA thisDev;
  270. TRACEINFO(2, ("HID DEVICE: %s\n", pIfDetail->DevicePath));
  271. // Finally we get specific device info to determine
  272. // if it's one of ours
  273. thisDev = *pDevData;
  274. if (GetDeviceData(pIfDetail->DevicePath, &thisDev))
  275. {
  276. TRACEINFO(2, ("Usage Page: %d, Usage: %d\n",
  277. thisDev.hidCaps.UsagePage,
  278. thisDev.hidCaps.Usage));
  279. // Is this is a device we want?
  280. if ((pDevData->UsagePage == thisDev.hidCaps.UsagePage) &&
  281. (pDevData->Usage == thisDev.hidCaps.Usage))
  282. {
  283. *pDevData = thisDev;
  284. break;
  285. }
  286. else
  287. {
  288. // Not one of our devices, clean-up and try again
  289. CloseTabletDevice(&thisDev);
  290. }
  291. }
  292. free(pIfDetail);
  293. }
  294. }
  295. else
  296. {
  297. DWORD dwLastError = GetLastError();
  298. // SetupDiEnumDeviceInterfaces() failed, hopefull with
  299. // ERROR_NO_MORE_ITEMS
  300. if (dwLastError != ERROR_NO_MORE_ITEMS)
  301. {
  302. TABSRVERR(("SetupDiEnumDeviceInterfaces failed (err=%d)\n",
  303. dwLastError));
  304. }
  305. break;
  306. }
  307. }
  308. // Clean-up from SetupDiGetClassDevs()
  309. SetupDiDestroyDeviceInfoList(hDevInfo);
  310. }
  311. else
  312. {
  313. TABSRVERR(("SetupDiGetClassDevs failed (err=%d)\n", GetLastError()));
  314. }
  315. rc = pDevData->hDevice != INVALID_HANDLE_VALUE;
  316. TRACEEXIT(("=%x\n", rc));
  317. return rc;
  318. } //OpenTabletDevice
  319. /*++
  320. @doc INTERNAL
  321. @func VOID | CloseTabletDevice | Close and clean up the tablet device.
  322. @parm IN PDEVICE_DATA | pDevData | Points to the tablet device data.
  323. @rvalue None.
  324. --*/
  325. VOID
  326. CloseTabletDevice(
  327. IN PDEVICE_DATA pDevData
  328. )
  329. {
  330. TRACEPROC("CloseTabletDevice", 2)
  331. TRACEENTER(("(pDevData=%p)\n", pDevData));
  332. if (pDevData->hDevice != INVALID_HANDLE_VALUE)
  333. {
  334. CloseHandle(pDevData->hDevice);
  335. HidD_FreePreparsedData(pDevData->pPreParsedData);
  336. pDevData->hDevice = INVALID_HANDLE_VALUE;
  337. }
  338. TRACEEXIT(("!\n"));
  339. } //CloseTabletDevice
  340. /*++
  341. @doc INTERNAL
  342. @func PSP_DEVICE_INTERFACE_DETAIL_DATA | GetDeviceInterfaceDetail |
  343. Gets interface details for a specific device.
  344. @parm IN HDEVINFO | hDevInfo | Handle to HID device info.
  345. @parm IN PSP_DEVICE_INTERFACE_DATA | pDevInterface |
  346. Points to device interface data.
  347. @rvalue SUCCESS | Returns pointer to SP_DEVICE_INTERFACE_DETAIL_DATA.
  348. @rvalue FAILURE | Returns NULL.
  349. @note Caller is responsible for freeing the returned memory.
  350. --*/
  351. PSP_DEVICE_INTERFACE_DETAIL_DATA
  352. GetDeviceInterfaceDetail(
  353. IN HDEVINFO hDevInfo,
  354. IN PSP_DEVICE_INTERFACE_DATA pDevInterface
  355. )
  356. {
  357. TRACEPROC("GetDeviceInterfaceDetail", 3)
  358. PSP_DEVICE_INTERFACE_DETAIL_DATA pDetails;
  359. ULONG ulLen = 0;
  360. TRACEENTER(("(hDevInfo=%x,pDevInterface=%p)\n", hDevInfo, pDevInterface));
  361. // Make a call to get the required buffer length
  362. SetupDiGetDeviceInterfaceDetail(hDevInfo,
  363. pDevInterface,
  364. NULL,
  365. 0,
  366. &ulLen,
  367. NULL);
  368. TRACEASSERT(ulLen > 0);
  369. // Allocate a sufficiently large buffer
  370. pDetails = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(ulLen);
  371. TRACEASSERT(pDetails != 0);
  372. if (pDetails != NULL)
  373. {
  374. // Now that we have a buffer, get the details
  375. pDetails->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  376. if (!SetupDiGetDeviceInterfaceDetail(hDevInfo,
  377. pDevInterface,
  378. pDetails,
  379. ulLen,
  380. &ulLen,
  381. NULL))
  382. {
  383. TABSRVERR(("SetupDiGetDeviceInterfaceDetail failed (err=%d)\n",
  384. GetLastError()));
  385. free(pDetails);
  386. pDetails = NULL;
  387. }
  388. }
  389. TRACEEXIT(("=%p\n", pDetails));
  390. return pDetails;
  391. } //GetDeviceInterfaceDetail
  392. /*++
  393. @doc INTERNAL
  394. @func BOOL | GetDeviceData | Opens a HID device and retrieves the
  395. 'preparsed' data and HID capabilities.
  396. @parm IN LPCTSTR | pszDevPath | Points to the device path name.
  397. @parm OUT PDEVICE_DATA | pDevData | Points to the DEVICE_DATA structure.
  398. @rvalue SUCCESS | Returns TRUE.
  399. @rvalue FAILURE | Returns FALSE.
  400. --*/
  401. BOOL
  402. GetDeviceData(
  403. IN LPCTSTR pszDevPath,
  404. OUT PDEVICE_DATA pDevData
  405. )
  406. {
  407. TRACEPROC("GetDeviceData", 3)
  408. BOOL rc = FALSE;
  409. TRACEENTER(("(pszDevPath=%s,pDevData=%p)\n", pszDevPath, pDevData));
  410. // First, open the device for read/write, exclusive access
  411. pDevData->hDevice = CreateFile(pszDevPath,
  412. GENERIC_READ | GENERIC_WRITE,// access mode
  413. FILE_SHARE_READ | FILE_SHARE_WRITE,// sharing flags
  414. NULL, // security attributes
  415. OPEN_EXISTING,
  416. FILE_FLAG_OVERLAPPED, // flags & attributes
  417. NULL); // template file
  418. if (pDevData->hDevice != INVALID_HANDLE_VALUE)
  419. {
  420. // Then get the preparsed data and capabilities
  421. if (HidD_GetPreparsedData(pDevData->hDevice,
  422. &pDevData->pPreParsedData) &&
  423. (HidP_GetCaps(pDevData->pPreParsedData, &pDevData->hidCaps) ==
  424. HIDP_STATUS_SUCCESS))
  425. {
  426. #ifdef DEBUG
  427. #if !defined(_UNICODE)
  428. char szAnsi[512];
  429. #endif
  430. TCHAR szBuff[256];
  431. if (HidD_GetManufacturerString(pDevData->hDevice,
  432. szBuff,
  433. sizeof(szBuff)))
  434. {
  435. #if !defined(_UNICODE)
  436. WideCharToMultiByte(CP_ACP,
  437. 0,
  438. (LPWSTR)szBuff,
  439. -1,
  440. szAnsi,
  441. sizeof(szAnsi),
  442. NULL,
  443. NULL);
  444. strcpy(szBuff, szAnsi);
  445. #endif
  446. TRACEINFO(2, ("ManufacturerStr: %s\n", szBuff));
  447. }
  448. if (HidD_GetProductString(pDevData->hDevice,
  449. szBuff,
  450. sizeof(szBuff)))
  451. {
  452. #if !defined(_UNICODE)
  453. WideCharToMultiByte(CP_ACP,
  454. 0,
  455. (LPWSTR)szBuff,
  456. -1,
  457. szAnsi,
  458. sizeof(szAnsi),
  459. NULL,
  460. NULL);
  461. strcpy(szBuff, szAnsi);
  462. #endif
  463. TRACEINFO(2, ("ProductStr: %s\n", szBuff));
  464. }
  465. #endif
  466. rc = TRUE;
  467. }
  468. else
  469. {
  470. TABSRVERR(("HidD_GetPreparsedData/HidP_GetCaps failed (err=%d)\n",
  471. GetLastError()));
  472. CloseHandle(pDevData->hDevice);
  473. pDevData->hDevice = INVALID_HANDLE_VALUE;
  474. }
  475. }
  476. else
  477. {
  478. TRACEWARN(("failed to open %s (err=%d)\n", pszDevPath, GetLastError()));
  479. }
  480. TRACEEXIT(("=%x\n", rc));
  481. return rc;
  482. } //GetDeviceData
  483. /*++
  484. @doc INTERNAL
  485. @func BOOL | ReadReportOverlapped | Get a device input report using
  486. overlapped ReadFile.
  487. @parm IN PDEVICE_DATA | pDevData | Device to read.
  488. @parm OUT LPVOID | lpvBuffer | Data buffer.
  489. @parm OUT LPDWORD | lpdwcBytesRead | To hold number of bytes read.
  490. @parm IN LPOVERLAPPED | lpOverlapped | Overlapped buffer
  491. @rvalue SUCCESS | Returns TRUE.
  492. @rvalue FAILURE | Returns FALSE.
  493. --*/
  494. BOOL
  495. ReadReportOverlapped(
  496. IN PDEVICE_DATA pDevData,
  497. OUT LPVOID lpvBuffer,
  498. OUT LPDWORD lpdwcBytesRead,
  499. IN LPOVERLAPPED lpOverlapped
  500. )
  501. {
  502. TRACEPROC("ReadReportOverlapped", 5)
  503. BOOL rc = TRUE;
  504. TRACEENTER(("(pDevData=%p,lpvBuffer=%p,lpdwcBytesRead=%p,lpOverlapped=%p)\n",
  505. pDevData, lpvBuffer, lpdwcBytesRead, lpOverlapped));
  506. rc = ReadFile(pDevData->hDevice,
  507. lpvBuffer,
  508. pDevData->hidCaps.InputReportByteLength,
  509. lpdwcBytesRead,
  510. lpOverlapped);
  511. if (rc == TRUE)
  512. {
  513. // ReadFile completed synchronously. Set our completion event
  514. // so this case can be handled by without special checking by
  515. // our caller.
  516. SetEvent(lpOverlapped->hEvent);
  517. }
  518. else
  519. {
  520. DWORD dwLastError = GetLastError();
  521. if (dwLastError == ERROR_IO_PENDING)
  522. {
  523. rc = TRUE;
  524. }
  525. else
  526. {
  527. TABSRVERR(("Error reading device report (err=%d)\n",
  528. dwLastError));
  529. }
  530. }
  531. TRACEEXIT(("=%x\n", rc));
  532. return rc;
  533. } //ReadReportOverlapped