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.

304 lines
6.7 KiB

  1. /***************************************************************************
  2. *
  3. * vjoy.c
  4. *
  5. * Virtual (analog) joystick driver for ntvdm
  6. *
  7. * Copyright (c) 1991-1996 Microsoft Corporation. All Rights Reserved.
  8. *
  9. ***************************************************************************/
  10. /*****************************************************************************
  11. *
  12. * #includes
  13. *
  14. *****************************************************************************/
  15. #include <windows.h> // The VDD is a win32 DLL
  16. #include <vddsvc.h> // Definition of VDD calls
  17. #include <ntddjoy.h>
  18. #include <vjoy.h>
  19. #define JOY_DRIVER_PATH L"\\\\.\\JOY1"
  20. #define JOYSTICK_POLL_INTERVAL 100
  21. JOY_DD_INPUT_DATA JoyData;
  22. HANDLE hJoyDriver = INVALID_HANDLE_VALUE;
  23. BOOL bInAnalogRead = FALSE;
  24. BOOL bDataValid = FALSE;
  25. ULONG ReadsSinceLastPortWrite = 0;
  26. BOOL bEnabled = FALSE;
  27. BOOL bAttemptedInit = FALSE;
  28. UCHAR JoyFlags = 0xf;
  29. USHORT TimeNdx;
  30. ULONG Times[4];
  31. UCHAR Values[4];
  32. LONG InitialCount;
  33. /*
  34. * DLL entry point routine.
  35. * Returns TRUE on success.
  36. */
  37. BOOL WINAPI
  38. DllEntryPoint(
  39. HINSTANCE hInstance,
  40. DWORD reason,
  41. LPVOID reserved
  42. )
  43. {
  44. static VDD_IO_PORTRANGE PortRange;
  45. static VDD_IO_HANDLERS handlers = {
  46. JoystickPortRead,
  47. NULL,
  48. NULL,
  49. NULL,
  50. JoystickPortWrite,
  51. NULL,
  52. NULL,
  53. NULL};
  54. switch (reason) {
  55. case DLL_PROCESS_ATTACH:
  56. DisableThreadLibraryCalls(hInstance);
  57. PortRange.First = JOYSTICK_PORT;
  58. PortRange.Last = JOYSTICK_PORT;
  59. if (!VDDInstallIOHook((HANDLE)hInstance, 1, &PortRange, &handlers)) {
  60. return FALSE;
  61. }
  62. if (!JoystickInit()) {
  63. VDDDeInstallIOHook((HANDLE)hInstance, 1, &PortRange);
  64. return FALSE;
  65. }
  66. return TRUE;
  67. case DLL_PROCESS_DETACH:
  68. bEnabled = FALSE; // tell thread to exit
  69. VDDDeInstallIOHook((HANDLE)hInstance, 1, &PortRange);
  70. return TRUE;
  71. default:
  72. return TRUE;
  73. }
  74. }
  75. BOOL
  76. JoystickInit(
  77. VOID
  78. )
  79. {
  80. HANDLE tHandle;
  81. ULONG ThreadId;
  82. ULONG numread;
  83. // BUGBUG: Should be using MM calls instead of this
  84. hJoyDriver = CreateFile(JOY_DRIVER_PATH,
  85. GENERIC_READ,
  86. 0,
  87. (LPSECURITY_ATTRIBUTES) NULL,
  88. OPEN_EXISTING,
  89. 0,
  90. (HANDLE) NULL);
  91. if (hJoyDriver != INVALID_HANDLE_VALUE) {
  92. if(!(tHandle = CreateThread(NULL, 0, JoystickPollThread,
  93. NULL, CREATE_SUSPENDED, &ThreadId))) {
  94. CloseHandle(hJoyDriver);
  95. return FALSE;
  96. }
  97. bEnabled = TRUE;
  98. //
  99. // Do an initial read
  100. //
  101. if (ReadFile(hJoyDriver, &JoyData, sizeof(JOY_DD_INPUT_DATA), &numread, NULL)) {
  102. bDataValid = TRUE;
  103. } else {
  104. bDataValid = FALSE;
  105. }
  106. ResumeThread(tHandle);
  107. CloseHandle(tHandle);
  108. }
  109. return TRUE;
  110. }
  111. VOID
  112. JoystickPortRead(
  113. WORD port,
  114. BYTE *pData
  115. )
  116. {
  117. BYTE data = 0xff;
  118. USHORT CurrentTime;
  119. LONG TargetTime;
  120. USHORT TargetCount;
  121. LONG USecsElapsed;
  122. ULONG TargetValue;
  123. static USHORT LastWriteTime;
  124. static LONG InitialCount;
  125. if (!bAttemptedInit) {
  126. bAttemptedInit = TRUE;
  127. JoystickInit();
  128. }
  129. if (!bEnabled) {
  130. *pData = data;
  131. return;
  132. }
  133. if (bDataValid && !JoyData.Unplugged) {
  134. //
  135. // Get the button state
  136. //
  137. data = (BYTE) ((~JoyData.Buttons << 4) & 0xf0);
  138. //
  139. // Get the analog resistive inputs
  140. //
  141. if (bInAnalogRead) {
  142. if (!ReadsSinceLastPortWrite) {
  143. VdmParametersInfo(VDM_GET_TIMER0_INITIAL_COUNT, &InitialCount, sizeof(LONG));
  144. VdmParametersInfo(VDM_GET_LAST_UPDATED_TIMER0_COUNT, &LastWriteTime, sizeof(USHORT));
  145. VDM_TRACE(0x6a1, (USHORT) 0, LastWriteTime);
  146. }
  147. if (++ReadsSinceLastPortWrite > 256) {
  148. // Too much time elapsed, we are done
  149. VDM_TRACE(0x6bf, 0, 0);
  150. if (JoyData.XTime) {
  151. JoyFlags &= ~1;
  152. }
  153. if (JoyData.YTime) {
  154. JoyFlags &= ~2;
  155. }
  156. if (JoyData.ZTime) {
  157. JoyFlags &= ~4;
  158. }
  159. if (JoyData.TTime) {
  160. JoyFlags &= ~8;
  161. }
  162. bInAnalogRead = FALSE;
  163. } else {
  164. TargetTime = (LONG)(LastWriteTime - (USHORT)(Times[TimeNdx]*3));
  165. if (TargetTime < 0) {
  166. TargetTime += InitialCount;
  167. }
  168. TargetCount = (USHORT) TargetTime;
  169. VdmParametersInfo(VDM_SET_NEXT_TIMER0_COUNT, &TargetCount, sizeof(USHORT));
  170. VDM_TRACE(0x6b2, Values[TimeNdx], TargetTime);
  171. JoyFlags &= ~Values[TimeNdx];
  172. if (++TimeNdx >= 4) {
  173. bInAnalogRead = FALSE;
  174. }
  175. }
  176. }
  177. data += JoyFlags;
  178. }
  179. *pData = data;
  180. // VDM_TRACE(0x6b0, data, 0);
  181. }
  182. VOID
  183. JoystickPortWrite(
  184. WORD port,
  185. BYTE data
  186. )
  187. {
  188. ULONG numread;
  189. ULONG TTim;
  190. CHAR TVal;
  191. int i, j;
  192. if (!bAttemptedInit) {
  193. bAttemptedInit = TRUE;
  194. JoystickInit();
  195. }
  196. ReadsSinceLastPortWrite = 0;
  197. JoyFlags = 0xf;
  198. Values[0] = 1;
  199. Values[1] = 2;
  200. Values[2] = 4;
  201. Values[3] = 8;
  202. Times[0] = JoyData.XTime;
  203. Times[1] = JoyData.YTime;
  204. Times[2] = JoyData.ZTime;
  205. Times[3] = JoyData.TTime;
  206. //
  207. // Sort them
  208. // Using just a bubble sort here with 4 items...
  209. //
  210. for (i=0; i<3; i++) {
  211. for (j=0; j<3-i; j++) {
  212. if (Times[j] > Times[j+1]) {
  213. TTim = Times[j];
  214. TVal = Values[j];
  215. Times[j] = Times[j+1];
  216. Values[j] = Values[j+1];
  217. Times[j+1] = TTim;
  218. Values[j+1] = TVal;
  219. }
  220. }
  221. }
  222. for (TimeNdx=0; TimeNdx<4; TimeNdx++) {
  223. if (Times[TimeNdx]) {
  224. break;
  225. }
  226. }
  227. if (TimeNdx < 4) {
  228. bInAnalogRead = TRUE;
  229. }
  230. for (i=0; i<4; i++) {
  231. VDM_TRACE(0x6a0, (USHORT) Values[i], Times[i]);
  232. }
  233. }
  234. DWORD WINAPI
  235. JoystickPollThread(
  236. LPVOID context
  237. )
  238. {
  239. ULONG numread;
  240. while(bEnabled) {
  241. Sleep(JOYSTICK_POLL_INTERVAL);
  242. if (ReadFile(hJoyDriver, &JoyData, sizeof(JOY_DD_INPUT_DATA), &numread, NULL)) {
  243. bDataValid = TRUE;
  244. } else {
  245. bDataValid = FALSE;
  246. }
  247. }
  248. return 0;
  249. }