Input.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #include "stdh.h"
  13. #include <Engine/Base/Timer.h>
  14. #include <Engine/Base/Input.h>
  15. #include <Engine/Base/Translation.h>
  16. #include <Engine/Base/KeyNames.h>
  17. #include <Engine/Math/Functions.h>
  18. #include <Engine/Graphics/Viewport.h>
  19. #include <Engine/Base/Console.h>
  20. #include <Engine/Base/Synchronization.h>
  21. #include <Engine/Base/ErrorReporting.h>
  22. extern INDEX inp_iKeyboardReadingMethod;
  23. extern FLOAT inp_fMouseSensitivity;
  24. extern INDEX inp_bAllowMouseAcceleration;
  25. extern INDEX inp_bMousePrecision;
  26. extern FLOAT inp_fMousePrecisionFactor;
  27. extern FLOAT inp_fMousePrecisionThreshold;
  28. extern FLOAT inp_fMousePrecisionTimeout;
  29. extern FLOAT inp_bInvertMouse;
  30. extern INDEX inp_bFilterMouse;
  31. extern INDEX inp_bAllowPrescan;
  32. extern INDEX inp_i2ndMousePort;
  33. extern FLOAT inp_f2ndMouseSensitivity;
  34. extern INDEX inp_b2ndMousePrecision;
  35. extern FLOAT inp_f2ndMousePrecisionThreshold;
  36. extern FLOAT inp_f2ndMousePrecisionTimeout;
  37. extern FLOAT inp_f2ndMousePrecisionFactor;
  38. extern INDEX inp_bFilter2ndMouse;
  39. extern INDEX inp_bInvert2ndMouse;
  40. extern INDEX inp_iMButton4Dn = 0x20040;
  41. extern INDEX inp_iMButton4Up = 0x20000;
  42. extern INDEX inp_iMButton5Dn = 0x10020;
  43. extern INDEX inp_iMButton5Up = 0x10000;
  44. extern INDEX inp_bMsgDebugger = FALSE;
  45. extern INDEX inp_bForceJoystickPolling = 0;
  46. extern INDEX inp_ctJoysticksAllowed = 8;
  47. extern INDEX inp_bAutoDisableJoysticks = 0;
  48. static CTString inp_astrAxisTran[MAX_OVERALL_AXES];// translated names for axis
  49. /*
  50. NOTE: Three different types of key codes are used here:
  51. 1) kid - engine internal type - defined in KeyNames.h
  52. 2) scancode - raw PC keyboard scancodes as returned in keydown/keyup messages
  53. 3) virtkey - virtual key codes used by windows
  54. */
  55. // name that is not translated (international)
  56. #define INTNAME(str) str, ""
  57. // name that is translated
  58. #define TRANAME(str) str, "ETRS" str
  59. // basic key conversion table
  60. static struct KeyConversion {
  61. INDEX kc_iKID;
  62. INDEX kc_iVirtKey;
  63. INDEX kc_iScanCode;
  64. char *kc_strName;
  65. char *kc_strNameTrans;
  66. } _akcKeys[] = {
  67. // reserved for 'no-key-pressed'
  68. { KID_NONE, -1, -1, TRANAME("None")},
  69. // numbers row
  70. { KID_1 , '1', 2, INTNAME("1")},
  71. { KID_2 , '2', 3, INTNAME("2")},
  72. { KID_3 , '3', 4, INTNAME("3")},
  73. { KID_4 , '4', 5, INTNAME("4")},
  74. { KID_5 , '5', 6, INTNAME("5")},
  75. { KID_6 , '6', 7, INTNAME("6")},
  76. { KID_7 , '7', 8, INTNAME("7")},
  77. { KID_8 , '8', 9, INTNAME("8")},
  78. { KID_9 , '9', 10, INTNAME("9")},
  79. { KID_0 , '0', 11, INTNAME("0")},
  80. { KID_MINUS , 189, 12, INTNAME("-")},
  81. { KID_EQUALS , 187, 13, INTNAME("=")},
  82. // 1st alpha row
  83. { KID_Q , 'Q', 16, INTNAME("Q")},
  84. { KID_W , 'W', 17, INTNAME("W")},
  85. { KID_E , 'E', 18, INTNAME("E")},
  86. { KID_R , 'R', 19, INTNAME("R")},
  87. { KID_T , 'T', 20, INTNAME("T")},
  88. { KID_Y , 'Y', 21, INTNAME("Y")},
  89. { KID_U , 'U', 22, INTNAME("U")},
  90. { KID_I , 'I', 23, INTNAME("I")},
  91. { KID_O , 'O', 24, INTNAME("O")},
  92. { KID_P , 'P', 25, INTNAME("P")},
  93. { KID_LBRACKET , 219, 26, INTNAME("[")},
  94. { KID_RBRACKET , 221, 27, INTNAME("]")},
  95. { KID_BACKSLASH , 220, 43, INTNAME("\\")},
  96. // 2nd alpha row
  97. { KID_A , 'A', 30, INTNAME("A")},
  98. { KID_S , 'S', 31, INTNAME("S")},
  99. { KID_D , 'D', 32, INTNAME("D")},
  100. { KID_F , 'F', 33, INTNAME("F")},
  101. { KID_G , 'G', 34, INTNAME("G")},
  102. { KID_H , 'H', 35, INTNAME("H")},
  103. { KID_J , 'J', 36, INTNAME("J")},
  104. { KID_K , 'K', 37, INTNAME("K")},
  105. { KID_L , 'L', 38, INTNAME("L")},
  106. { KID_SEMICOLON , 186, 39, INTNAME(";")},
  107. { KID_APOSTROPHE , 222, 40, INTNAME("'")},
  108. // 3rd alpha row
  109. { KID_Z , 'Z', 44, INTNAME("Z")},
  110. { KID_X , 'X', 45, INTNAME("X")},
  111. { KID_C , 'C', 46, INTNAME("C")},
  112. { KID_V , 'V', 47, INTNAME("V")},
  113. { KID_B , 'B', 48, INTNAME("B")},
  114. { KID_N , 'N', 49, INTNAME("N")},
  115. { KID_M , 'M', 50, INTNAME("M")},
  116. { KID_COMMA , 190, 51, INTNAME(",")},
  117. { KID_PERIOD , 188, 52, INTNAME(".")},
  118. { KID_SLASH , 191, 53, INTNAME("/")},
  119. // row with F-keys
  120. { KID_F1 , VK_F1, 59, INTNAME("F1")},
  121. { KID_F2 , VK_F2, 60, INTNAME("F2")},
  122. { KID_F3 , VK_F3, 61, INTNAME("F3")},
  123. { KID_F4 , VK_F4, 62, INTNAME("F4")},
  124. { KID_F5 , VK_F5, 63, INTNAME("F5")},
  125. { KID_F6 , VK_F6, 64, INTNAME("F6")},
  126. { KID_F7 , VK_F7, 65, INTNAME("F7")},
  127. { KID_F8 , VK_F8, 66, INTNAME("F8")},
  128. { KID_F9 , VK_F9, 67, INTNAME("F9")},
  129. { KID_F10 , VK_F10, 68, INTNAME("F10")},
  130. { KID_F11 , VK_F11, 87, INTNAME("F11")},
  131. { KID_F12 , VK_F12, 88, INTNAME("F12")},
  132. // extra keys
  133. { KID_ESCAPE , VK_ESCAPE, 1, TRANAME("Escape")},
  134. { KID_TILDE , -1, 41, TRANAME("Tilde")},
  135. { KID_BACKSPACE , VK_BACK, 14, TRANAME("Backspace")},
  136. { KID_TAB , VK_TAB, 15, TRANAME("Tab")},
  137. { KID_CAPSLOCK , VK_CAPITAL, 58, TRANAME("Caps Lock")},
  138. { KID_ENTER , VK_RETURN, 28, TRANAME("Enter")},
  139. { KID_SPACE , VK_SPACE, 57, TRANAME("Space")},
  140. // modifier keys
  141. { KID_LSHIFT , VK_LSHIFT , 42, TRANAME("Left Shift")},
  142. { KID_RSHIFT , VK_RSHIFT , 54, TRANAME("Right Shift")},
  143. { KID_LCONTROL , VK_LCONTROL, 29, TRANAME("Left Control")},
  144. { KID_RCONTROL , VK_RCONTROL, 256+29, TRANAME("Right Control")},
  145. { KID_LALT , VK_LMENU , 56, TRANAME("Left Alt")},
  146. { KID_RALT , VK_RMENU , 256+56, TRANAME("Right Alt")},
  147. // navigation keys
  148. { KID_ARROWUP , VK_UP, 256+72, TRANAME("Arrow Up")},
  149. { KID_ARROWDOWN , VK_DOWN, 256+80, TRANAME("Arrow Down")},
  150. { KID_ARROWLEFT , VK_LEFT, 256+75, TRANAME("Arrow Left")},
  151. { KID_ARROWRIGHT , VK_RIGHT, 256+77, TRANAME("Arrow Right")},
  152. { KID_INSERT , VK_INSERT, 256+82, TRANAME("Insert")},
  153. { KID_DELETE , VK_DELETE, 256+83, TRANAME("Delete")},
  154. { KID_HOME , VK_HOME, 256+71, TRANAME("Home")},
  155. { KID_END , VK_END, 256+79, TRANAME("End")},
  156. { KID_PAGEUP , VK_PRIOR, 256+73, TRANAME("Page Up")},
  157. { KID_PAGEDOWN , VK_NEXT, 256+81, TRANAME("Page Down")},
  158. { KID_PRINTSCR , VK_SNAPSHOT, 256+55, TRANAME("Print Screen")},
  159. { KID_SCROLLLOCK , VK_SCROLL, 70, TRANAME("Scroll Lock")},
  160. { KID_PAUSE , VK_PAUSE, 69, TRANAME("Pause")},
  161. // numpad numbers
  162. { KID_NUM0 , VK_NUMPAD0, 82, INTNAME("Num 0")},
  163. { KID_NUM1 , VK_NUMPAD1, 79, INTNAME("Num 1")},
  164. { KID_NUM2 , VK_NUMPAD2, 80, INTNAME("Num 2")},
  165. { KID_NUM3 , VK_NUMPAD3, 81, INTNAME("Num 3")},
  166. { KID_NUM4 , VK_NUMPAD4, 75, INTNAME("Num 4")},
  167. { KID_NUM5 , VK_NUMPAD5, 76, INTNAME("Num 5")},
  168. { KID_NUM6 , VK_NUMPAD6, 77, INTNAME("Num 6")},
  169. { KID_NUM7 , VK_NUMPAD7, 71, INTNAME("Num 7")},
  170. { KID_NUM8 , VK_NUMPAD8, 72, INTNAME("Num 8")},
  171. { KID_NUM9 , VK_NUMPAD9, 73, INTNAME("Num 9")},
  172. { KID_NUMDECIMAL , VK_DECIMAL, 83, INTNAME("Num .")},
  173. // numpad gray keys
  174. { KID_NUMLOCK , VK_NUMLOCK, 256+69, INTNAME("Num Lock")},
  175. { KID_NUMSLASH , VK_DIVIDE, 256+53, INTNAME("Num /")},
  176. { KID_NUMMULTIPLY , VK_MULTIPLY, 55, INTNAME("Num *")},
  177. { KID_NUMMINUS , VK_SUBTRACT, 74, INTNAME("Num -")},
  178. { KID_NUMPLUS , VK_ADD, 78, INTNAME("Num +")},
  179. { KID_NUMENTER , VK_SEPARATOR, 256+28, TRANAME("Num Enter")},
  180. // mouse buttons
  181. { KID_MOUSE1 , VK_LBUTTON, -1, TRANAME("Mouse Button 1")},
  182. { KID_MOUSE2 , VK_RBUTTON, -1, TRANAME("Mouse Button 2")},
  183. { KID_MOUSE3 , VK_MBUTTON, -1, TRANAME("Mouse Button 3")},
  184. { KID_MOUSE4 , -1, -1, TRANAME("Mouse Button 4")},
  185. { KID_MOUSE5 , -1, -1, TRANAME("Mouse Button 5")},
  186. { KID_MOUSEWHEELUP , -1, -1, TRANAME("Mouse Wheel Up")},
  187. { KID_MOUSEWHEELDOWN , -1, -1, TRANAME("Mouse Wheel Down")},
  188. // 2nd mouse buttons
  189. { KID_2MOUSE1 , -1, -1, TRANAME("2nd Mouse Button 1")},
  190. { KID_2MOUSE2 , -1, -1, TRANAME("2nd Mouse Button 2")},
  191. { KID_2MOUSE3 , -1, -1, TRANAME("2nd Mouse Button 3")},
  192. };
  193. // autogenerated fast conversion tables
  194. static INDEX _aiScanToKid[512];
  195. static INDEX _aiVirtToKid[256];
  196. // make fast conversion tables from the general table
  197. static void MakeConversionTables(void)
  198. {
  199. // clear conversion tables
  200. memset(_aiScanToKid, -1, sizeof(_aiScanToKid));
  201. memset(_aiVirtToKid, -1, sizeof(_aiVirtToKid));
  202. // for each Key
  203. for (INDEX iKey=0; iKey<ARRAYCOUNT(_akcKeys); iKey++) {
  204. struct KeyConversion &kc = _akcKeys[iKey];
  205. // get codes
  206. INDEX iKID = kc.kc_iKID;
  207. INDEX iScan = kc.kc_iScanCode;
  208. INDEX iVirt = kc.kc_iVirtKey;
  209. // update the tables
  210. if (iScan>=0) {
  211. _aiScanToKid[iScan] = iKID;
  212. }
  213. if (iVirt>=0) {
  214. _aiVirtToKid[iVirt] = iKID;
  215. }
  216. }
  217. }
  218. // variables for message interception
  219. static HHOOK _hGetMsgHook = NULL;
  220. static HHOOK _hSendMsgHook = NULL;
  221. static int _iMouseZ = 0;
  222. static BOOL _bWheelUp = FALSE;
  223. static BOOL _bWheelDn = FALSE;
  224. CTCriticalSection csInput;
  225. // which keys are pressed, as recorded by message interception (by KIDs)
  226. static UBYTE _abKeysPressed[256];
  227. // set a key according to a keydown/keyup message
  228. static void SetKeyFromMsg(MSG *pMsg, BOOL bDown)
  229. {
  230. INDEX iKID = -1;
  231. // if capturing scan codes
  232. if (inp_iKeyboardReadingMethod==2) {
  233. // get scan code
  234. INDEX iScan = (pMsg->lParam>>16)&0x1FF; // (we use the extended bit too!)
  235. // convert scan code to kid
  236. iKID = _aiScanToKid[iScan];
  237. // if capturing virtual key codes
  238. } else if (inp_iKeyboardReadingMethod==1) {
  239. // get virtualkey
  240. INDEX iVirt = (pMsg->wParam)&0xFF;
  241. if (iVirt == VK_SHIFT) {
  242. iVirt = VK_LSHIFT;
  243. }
  244. if (iVirt == VK_CONTROL) {
  245. iVirt = VK_LCONTROL;
  246. }
  247. if (iVirt == VK_MENU) {
  248. iVirt = VK_LMENU;
  249. }
  250. // convert virtualkey to kid
  251. iKID = _aiVirtToKid[iVirt];
  252. // if not capturing
  253. } else {
  254. // do nothing
  255. return;
  256. }
  257. if (iKID>=0 && iKID<ARRAYCOUNT(_abKeysPressed)) {
  258. // CPrintF("%s: %d\n", _pInput->inp_strButtonNames[iKID], bDown);
  259. _abKeysPressed[iKID] = bDown;
  260. }
  261. }
  262. static void CheckMessage(MSG *pMsg)
  263. {
  264. if ( pMsg->message == WM_LBUTTONUP) {
  265. _abKeysPressed[KID_MOUSE1] = FALSE;
  266. } else if ( pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK) {
  267. _abKeysPressed[KID_MOUSE1] = TRUE;
  268. } else if ( pMsg->message == WM_RBUTTONUP) {
  269. _abKeysPressed[KID_MOUSE2] = FALSE;
  270. } else if ( pMsg->message == WM_RBUTTONDOWN || pMsg->message == WM_RBUTTONDBLCLK) {
  271. _abKeysPressed[KID_MOUSE2] = TRUE;
  272. } else if ( pMsg->message == WM_MBUTTONUP) {
  273. _abKeysPressed[KID_MOUSE3] = FALSE;
  274. } else if ( pMsg->message == WM_MBUTTONDOWN || pMsg->message == WM_MBUTTONDBLCLK) {
  275. _abKeysPressed[KID_MOUSE3] = TRUE;
  276. } else if ( pMsg->message == inp_iMButton4Dn) {
  277. _abKeysPressed[KID_MOUSE4] = TRUE;
  278. } else if ( pMsg->message == inp_iMButton4Up) {
  279. _abKeysPressed[KID_MOUSE4] = FALSE;
  280. } else if ( pMsg->message == inp_iMButton5Dn) {
  281. _abKeysPressed[KID_MOUSE5] = TRUE;
  282. } else if ( pMsg->message == inp_iMButton5Up) {
  283. _abKeysPressed[KID_MOUSE5] = FALSE;
  284. } else if (pMsg->message==WM_KEYUP || pMsg->message==WM_SYSKEYUP) {
  285. SetKeyFromMsg(pMsg, FALSE);
  286. } else if (pMsg->message==WM_KEYDOWN || pMsg->message==WM_SYSKEYDOWN) {
  287. SetKeyFromMsg(pMsg, TRUE);
  288. } else if (inp_bMsgDebugger && pMsg->message >= 0x10000) {
  289. CPrintF("%08x(%d)\n", pMsg->message, pMsg->message);
  290. }
  291. }
  292. // procedure called when message is retreived
  293. LRESULT CALLBACK GetMsgProc(
  294. int nCode, // hook code
  295. WPARAM wParam, // message identifier
  296. LPARAM lParam) // mouse coordinates
  297. {
  298. MSG *pMsg = (MSG*)lParam;
  299. CheckMessage(pMsg);
  300. LRESULT retValue = 0;
  301. retValue = CallNextHookEx( _hGetMsgHook, nCode, wParam, lParam );
  302. #ifndef WM_MOUSEWHEEL
  303. #define WM_MOUSEWHEEL 0x020A
  304. #endif
  305. if (wParam == PM_NOREMOVE) {
  306. return retValue;
  307. }
  308. if ( pMsg->message == WM_MOUSEWHEEL) {
  309. _iMouseZ += SWORD(UWORD(HIWORD(pMsg->wParam)));
  310. }
  311. return retValue;
  312. }
  313. // procedure called when message is sent
  314. LRESULT CALLBACK SendMsgProc(
  315. int nCode, // hook code
  316. WPARAM wParam, // message identifier
  317. LPARAM lParam) // mouse coordinates
  318. {
  319. MSG *pMsg = (MSG*)lParam;
  320. CheckMessage(pMsg);
  321. LRESULT retValue = 0;
  322. retValue = CallNextHookEx( _hSendMsgHook, nCode, wParam, lParam );
  323. return retValue;
  324. }
  325. // --------- 2ND MOUSE HANDLING
  326. #define MOUSECOMBUFFERSIZE 256L
  327. static HANDLE _h2ndMouse = NONE;
  328. static BOOL _bIgnoreMouse2 = TRUE;
  329. static INDEX _i2ndMouseX, _i2ndMouseY, _i2ndMouseButtons;
  330. static INDEX _iByteNum = 0;
  331. static UBYTE _aubComBytes[4] = {0,0,0,0};
  332. static INDEX _iLastPort = -1;
  333. static void Poll2ndMouse(void)
  334. {
  335. // reset (mouse reading is relative)
  336. _i2ndMouseX = 0;
  337. _i2ndMouseY = 0;
  338. if( _h2ndMouse==NONE) return;
  339. // check
  340. COMSTAT csComStat;
  341. DWORD dwErrorFlags;
  342. ClearCommError( _h2ndMouse, &dwErrorFlags, &csComStat);
  343. DWORD dwLength = Min( MOUSECOMBUFFERSIZE, (INDEX)csComStat.cbInQue);
  344. if( dwLength<=0) return;
  345. // readout
  346. UBYTE aubMouseBuffer[MOUSECOMBUFFERSIZE];
  347. INDEX iRetries = 999;
  348. while( iRetries>0 && !ReadFile( _h2ndMouse, aubMouseBuffer, dwLength, &dwLength, NULL)) iRetries--;
  349. if( iRetries<=0) return; // what, didn't make it?
  350. // parse the mouse packets
  351. for( INDEX i=0; i<dwLength; i++)
  352. {
  353. // prepare
  354. if( aubMouseBuffer[i] & 64) _iByteNum = 0;
  355. if( _iByteNum<4) _aubComBytes[_iByteNum] = aubMouseBuffer[i];
  356. _iByteNum++;
  357. // buttons ?
  358. if( _iByteNum==1) {
  359. _i2ndMouseButtons &= ~3;
  360. _i2ndMouseButtons |= (_aubComBytes[0] & (32+16)) >>4;
  361. }
  362. // axes ?
  363. else if( _iByteNum==3) {
  364. char iDX = ((_aubComBytes[0] & 3) <<6) + _aubComBytes[1];
  365. char iDY = ((_aubComBytes[0] & 12) <<4) + _aubComBytes[2];
  366. _i2ndMouseX += iDX;
  367. _i2ndMouseY += iDY;
  368. }
  369. // 3rd button?
  370. else if( _iByteNum==4) {
  371. _i2ndMouseButtons &= ~4;
  372. if( aubMouseBuffer[i]&32) _i2ndMouseButtons |= 4;
  373. }
  374. }
  375. // ignore pooling?
  376. if( _bIgnoreMouse2) {
  377. if( _i2ndMouseX!=0 || _i2ndMouseY!=0) _bIgnoreMouse2 = FALSE;
  378. _i2ndMouseX = 0;
  379. _i2ndMouseY = 0;
  380. _i2ndMouseButtons = 0;
  381. return;
  382. }
  383. }
  384. static void Startup2ndMouse(INDEX iPort)
  385. {
  386. // skip if disabled
  387. ASSERT( iPort>=0 && iPort<=4);
  388. if( iPort==0) return;
  389. // determine port string
  390. CTString str2ndMousePort( 0, "COM%d", iPort);
  391. // create COM handle if needed
  392. if( _h2ndMouse==NONE) {
  393. _h2ndMouse = CreateFileA( str2ndMousePort, GENERIC_READ|GENERIC_WRITE, 0, NULL,
  394. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  395. if( _h2ndMouse==INVALID_HANDLE_VALUE) {
  396. // failed! :(
  397. INDEX iError = GetLastError();
  398. /*
  399. if( iError==5) CPrintF( "Cannot open %s (access denied).\n"
  400. "The port is probably already used by another device (mouse, modem...)\n",
  401. str2ndMousePort);
  402. else CPrintF( "Cannot open %s (error %d).\n", str2ndMousePort, iError);
  403. */
  404. _h2ndMouse = NONE;
  405. return;
  406. }
  407. }
  408. // setup and purge buffers
  409. SetupComm( _h2ndMouse, MOUSECOMBUFFERSIZE, MOUSECOMBUFFERSIZE);
  410. PurgeComm( _h2ndMouse, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
  411. // setup port to 1200 7N1
  412. DCB dcb;
  413. dcb.DCBlength = sizeof(DCB);
  414. GetCommState( _h2ndMouse, &dcb);
  415. dcb.BaudRate = CBR_1200;
  416. dcb.ByteSize = 7;
  417. dcb.Parity = NOPARITY;
  418. dcb.StopBits = ONESTOPBIT;
  419. dcb.fDtrControl = DTR_CONTROL_ENABLE;
  420. dcb.fRtsControl = RTS_CONTROL_ENABLE;
  421. dcb.fBinary = TRUE;
  422. dcb.fParity = TRUE;
  423. SetCommState( _h2ndMouse, &dcb);
  424. // reset
  425. _iByteNum = 0;
  426. _aubComBytes[0] = _aubComBytes[1] = _aubComBytes[2] = _aubComBytes[3] = 0;
  427. _bIgnoreMouse2 = TRUE; // ignore mouse polling until 1 after non-0 readout
  428. _iLastPort = iPort;
  429. //CPrintF( "STARTUP M2!\n");
  430. }
  431. static void Shutdown2ndMouse(void)
  432. {
  433. // skip if already disabled
  434. if( _h2ndMouse==NONE) return;
  435. // disable!
  436. SetCommMask( _h2ndMouse, 0);
  437. EscapeCommFunction( _h2ndMouse, CLRDTR);
  438. EscapeCommFunction( _h2ndMouse, CLRRTS);
  439. PurgeComm( _h2ndMouse, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
  440. // close port if changed
  441. if( _iLastPort != inp_i2ndMousePort) {
  442. CloseHandle( _h2ndMouse);
  443. _h2ndMouse = NONE;
  444. } // over and out
  445. _bIgnoreMouse2 = TRUE;
  446. }
  447. // pointer to global input object
  448. CInput *_pInput = NULL;
  449. // deafult constructor
  450. CInput::CInput(void)
  451. {
  452. // disable control scaning
  453. inp_bInputEnabled = FALSE;
  454. inp_bPollJoysticks = FALSE;
  455. inp_bLastPrescan = FALSE;
  456. // clear key buffer
  457. for( INDEX iButton=0; iButton<MAX_OVERALL_BUTTONS; iButton++)
  458. {
  459. inp_ubButtonsBuffer[ iButton] = 0;
  460. }
  461. // clear axis relative and absolute values
  462. for( INDEX iAxis=0; iAxis<MAX_OVERALL_AXES; iAxis++)
  463. {
  464. inp_caiAllAxisInfo[ iAxis].cai_fReading = 0.0f;
  465. inp_caiAllAxisInfo[ iAxis].cai_bExisting = FALSE;
  466. }
  467. MakeConversionTables();
  468. }
  469. // destructor
  470. CInput::~CInput()
  471. {
  472. if( _h2ndMouse!=NONE) CloseHandle( _h2ndMouse);
  473. _h2ndMouse = NONE;
  474. }
  475. void CInput::SetJoyPolling(BOOL bPoll)
  476. {
  477. inp_bPollJoysticks = bPoll;
  478. }
  479. /*
  480. * Sets names of keys on keyboard
  481. */
  482. void CInput::SetKeyNames( void)
  483. {
  484. // set name "None" for all keys, known keys will override this default name
  485. {for( INDEX iKey=0; iKey<ARRAYCOUNT(inp_strButtonNames); iKey++) {
  486. inp_strButtonNames[iKey] = "None";
  487. inp_strButtonNamesTra[iKey] = TRANS("None");
  488. }}
  489. // for each Key
  490. {for (INDEX iKey=0; iKey<ARRAYCOUNT(_akcKeys); iKey++) {
  491. struct KeyConversion &kc = _akcKeys[iKey];
  492. // set the name
  493. if (kc.kc_strName!=NULL) {
  494. inp_strButtonNames[kc.kc_iKID] = kc.kc_strName;
  495. if (strlen(kc.kc_strNameTrans)==0) {
  496. inp_strButtonNamesTra[kc.kc_iKID] = kc.kc_strName;
  497. } else {
  498. inp_strButtonNamesTra[kc.kc_iKID] = TranslateConst(kc.kc_strNameTrans, 4);
  499. }
  500. }
  501. }}
  502. // -------- Enumerate known axis -------------
  503. // no axis as axis type 0
  504. inp_caiAllAxisInfo[0].cai_strAxisName = "None";
  505. inp_astrAxisTran[ 0] = TRANS("None");
  506. // mouse axis occupy types from 1 up to 3
  507. inp_caiAllAxisInfo[1].cai_strAxisName = "mouse X";
  508. inp_astrAxisTran[ 1] = TRANS("mouse X");
  509. inp_caiAllAxisInfo[2].cai_strAxisName = "mouse Y";
  510. inp_astrAxisTran[ 2] = TRANS("mouse Y");
  511. inp_caiAllAxisInfo[3].cai_strAxisName = "mouse Z";
  512. inp_astrAxisTran[ 3] = TRANS("mouse Z");
  513. inp_caiAllAxisInfo[4].cai_strAxisName = "2nd mouse X";
  514. inp_astrAxisTran[ 4] = TRANS("2nd mouse X");
  515. inp_caiAllAxisInfo[5].cai_strAxisName = "2nd mouse Y";
  516. inp_astrAxisTran[ 5] = TRANS("2nd mouse Y");
  517. // -------- Get number of joysticks ----------
  518. // get number of joystics
  519. INDEX ctJoysticksPresent = joyGetNumDevs();
  520. CPrintF(TRANS(" joysticks found: %d\n"), ctJoysticksPresent);
  521. ctJoysticksPresent = Min(ctJoysticksPresent, inp_ctJoysticksAllowed);
  522. CPrintF(TRANS(" joysticks allowed: %d\n"), ctJoysticksPresent);
  523. // -------- Enumerate axis and buttons for joysticks ----------
  524. for (INDEX iJoy=0; iJoy<MAX_JOYSTICKS; iJoy++) {
  525. inp_abJoystickOn[iJoy] = FALSE;
  526. if (iJoy<ctJoysticksPresent && CheckJoystick(iJoy)) {
  527. inp_abJoystickOn[iJoy] = TRUE;
  528. }
  529. AddJoystickAbbilities(iJoy);
  530. }
  531. }
  532. // check if a joystick exists
  533. BOOL CInput::CheckJoystick(INDEX iJoy)
  534. {
  535. CPrintF(TRANS(" joy %d:"), iJoy+1);
  536. JOYCAPS jc;
  537. // seek for capabilities of requested joystick
  538. MMRESULT mmResult = joyGetDevCaps( JOYSTICKID1+iJoy, &jc, sizeof(JOYCAPS));
  539. // report possible errors
  540. if( mmResult == MMSYSERR_NODRIVER) {
  541. CPrintF(TRANS(" joystick driver is not present\n"));
  542. return FALSE;
  543. } else if( mmResult == MMSYSERR_INVALPARAM) {
  544. CPrintF(TRANS(" invalid parameter\n"));
  545. return FALSE;
  546. } else if( mmResult != JOYERR_NOERROR) {
  547. CPrintF(TRANS(" error 0x%08x\n"), mmResult);
  548. return FALSE;
  549. }
  550. CPrintF(" '%s'\n", jc.szPname);
  551. CPrintF(TRANS(" %d axes\n"), jc.wNumAxes);
  552. CPrintF(TRANS(" %d buttons\n"), jc.wNumButtons);
  553. if (jc.wCaps&JOYCAPS_HASPOV) {
  554. CPrintF(TRANS(" POV hat present\n"));
  555. inp_abJoystickHasPOV[iJoy] = TRUE;
  556. } else {
  557. inp_abJoystickHasPOV[iJoy] = FALSE;
  558. }
  559. // read joystick state
  560. JOYINFOEX ji;
  561. ji.dwFlags = JOY_RETURNBUTTONS|JOY_RETURNCENTERED|JOY_RETURNPOV|JOY_RETURNR|
  562. JOY_RETURNX|JOY_RETURNY|JOY_RETURNZ|JOY_RETURNU|JOY_RETURNV;
  563. ji.dwSize = sizeof( JOYINFOEX);
  564. mmResult = joyGetPosEx( JOYSTICKID1+iJoy, &ji);
  565. // if some error
  566. if( mmResult != JOYERR_NOERROR) {
  567. // fail
  568. CPrintF(TRANS(" Cannot read the joystick!\n"));
  569. return FALSE;
  570. }
  571. // for each axis
  572. for(INDEX iAxis=0; iAxis<MAX_AXES_PER_JOYSTICK; iAxis++) {
  573. ControlAxisInfo &cai= inp_caiAllAxisInfo[ FIRST_JOYAXIS+iJoy*MAX_AXES_PER_JOYSTICK+iAxis];
  574. // remember min/max info
  575. switch( iAxis) {
  576. case 0:
  577. cai.cai_slMin = jc.wXmin; cai.cai_slMax = jc.wXmax;
  578. cai.cai_bExisting = TRUE;
  579. break;
  580. case 1:
  581. cai.cai_slMin = jc.wYmin; cai.cai_slMax = jc.wYmax;
  582. cai.cai_bExisting = TRUE;
  583. break;
  584. case 2:
  585. cai.cai_slMin = jc.wZmin; cai.cai_slMax = jc.wZmax;
  586. cai.cai_bExisting = jc.wCaps&JOYCAPS_HASZ;
  587. break;
  588. case 3:
  589. cai.cai_slMin = jc.wRmin; cai.cai_slMax = jc.wRmax;
  590. cai.cai_bExisting = jc.wCaps&JOYCAPS_HASR;
  591. break;
  592. case 4:
  593. cai.cai_slMin = jc.wUmin; cai.cai_slMax = jc.wUmax;
  594. cai.cai_bExisting = jc.wCaps&JOYCAPS_HASU;
  595. break;
  596. case 5:
  597. cai.cai_slMin = jc.wVmin; cai.cai_slMax = jc.wVmax;
  598. cai.cai_bExisting = jc.wCaps&JOYCAPS_HASV;
  599. break;
  600. }
  601. }
  602. return TRUE;
  603. }
  604. // adds axis and buttons for given joystick
  605. void CInput::AddJoystickAbbilities(INDEX iJoy)
  606. {
  607. CTString strJoystickName;
  608. strJoystickName.PrintF("Joy %d", iJoy+1);
  609. CTString strJoystickNameTra;
  610. strJoystickNameTra.PrintF(TRANS("Joy %d"), iJoy+1);
  611. // for each axis
  612. for( UINT iAxis=0; iAxis<6; iAxis++) {
  613. INDEX iAxisTotal = FIRST_JOYAXIS+iJoy*MAX_AXES_PER_JOYSTICK+iAxis;
  614. ControlAxisInfo &cai= inp_caiAllAxisInfo[iAxisTotal];
  615. CTString &strTran = inp_astrAxisTran[iAxisTotal];
  616. // set axis name
  617. switch( iAxis) {
  618. case 0: cai.cai_strAxisName = strJoystickName + " Axis X"; strTran = strJoystickNameTra + TRANS(" Axis X"); break;
  619. case 1: cai.cai_strAxisName = strJoystickName + " Axis Y"; strTran = strJoystickNameTra + TRANS(" Axis Y"); break;
  620. case 2: cai.cai_strAxisName = strJoystickName + " Axis Z"; strTran = strJoystickNameTra + TRANS(" Axis Z"); break;
  621. case 3: cai.cai_strAxisName = strJoystickName + " Axis R"; strTran = strJoystickNameTra + TRANS(" Axis R"); break;
  622. case 4: cai.cai_strAxisName = strJoystickName + " Axis U"; strTran = strJoystickNameTra + TRANS(" Axis U"); break;
  623. case 5: cai.cai_strAxisName = strJoystickName + " Axis V"; strTran = strJoystickNameTra + TRANS(" Axis V"); break;
  624. }
  625. }
  626. INDEX iButtonTotal = FIRST_JOYBUTTON+iJoy*MAX_BUTTONS_PER_JOYSTICK;
  627. // add buttons that the joystick supports
  628. for( UINT iButton=0; iButton<32; iButton++) {
  629. CTString strButtonName;
  630. CTString strButtonNameTra;
  631. // create name for n-th button
  632. strButtonName.PrintF( " Button %d", iButton);
  633. strButtonNameTra.PrintF( TRANS(" Button %d"), iButton);
  634. // set n-th button name
  635. inp_strButtonNames[iButtonTotal] = strJoystickName + strButtonName;
  636. inp_strButtonNamesTra[iButtonTotal] = strJoystickNameTra + strButtonNameTra;
  637. iButtonTotal++;
  638. }
  639. // add the four POV buttons
  640. inp_strButtonNames [ iButtonTotal ] = strJoystickName + (" POV N");
  641. inp_strButtonNamesTra[ iButtonTotal++] = strJoystickNameTra + TRANS(" POV N");
  642. inp_strButtonNames [ iButtonTotal ] = strJoystickName + (" POV E");
  643. inp_strButtonNamesTra[ iButtonTotal++] = strJoystickNameTra + TRANS(" POV E");
  644. inp_strButtonNames [ iButtonTotal ] = strJoystickName + (" POV S");
  645. inp_strButtonNamesTra[ iButtonTotal++] = strJoystickNameTra + TRANS(" POV S");
  646. inp_strButtonNames [ iButtonTotal ] = strJoystickName + (" POV W");
  647. inp_strButtonNamesTra[ iButtonTotal++] = strJoystickNameTra + TRANS(" POV W");
  648. }
  649. /*
  650. * Initializes all available devices and enumerates available controls
  651. */
  652. void CInput::Initialize( void )
  653. {
  654. CPrintF(TRANS("Detecting input devices...\n"));
  655. SetKeyNames();
  656. _h2ndMouse = NONE;
  657. CPrintF("\n");
  658. }
  659. /*
  660. * Enable direct input
  661. */
  662. void CInput::EnableInput(CViewPort *pvp)
  663. {
  664. EnableInput(pvp->vp_hWnd);
  665. }
  666. void CInput::EnableInput(HWND hwnd)
  667. {
  668. // skip if already enabled
  669. if( inp_bInputEnabled) return;
  670. // get window rectangle
  671. RECT rectClient;
  672. GetClientRect(hwnd, &rectClient);
  673. POINT pt;
  674. pt.x=0;
  675. pt.y=0;
  676. ClientToScreen(hwnd, &pt);
  677. OffsetRect(&rectClient, pt.x, pt.y);
  678. // remember mouse pos
  679. GetCursorPos( &inp_ptOldMousePos);
  680. // set mouse clip region
  681. ClipCursor(&rectClient);
  682. // determine screen center position
  683. inp_slScreenCenterX = (rectClient.left + rectClient.right) / 2;
  684. inp_slScreenCenterY = (rectClient.top + rectClient.bottom) / 2;
  685. // clear mouse from screen
  686. while (ShowCursor(FALSE) >= 0);
  687. // save system mouse settings
  688. SystemParametersInfo(SPI_GETMOUSE, 0, &inp_mscMouseSettings, 0);
  689. // set new mouse speed
  690. if (!inp_bAllowMouseAcceleration) {
  691. MouseSpeedControl mscNewSetting = { 0, 0, 0};
  692. SystemParametersInfo(SPI_SETMOUSE, 0, &mscNewSetting, 0);
  693. }
  694. // set cursor position to screen center
  695. SetCursorPos(inp_slScreenCenterX, inp_slScreenCenterY);
  696. _hGetMsgHook = SetWindowsHookEx(WH_GETMESSAGE, &GetMsgProc, NULL, GetCurrentThreadId());
  697. _hSendMsgHook = SetWindowsHookEx(WH_CALLWNDPROC, &SendMsgProc, NULL, GetCurrentThreadId());
  698. // if required, try to enable 2nd mouse
  699. Shutdown2ndMouse();
  700. inp_i2ndMousePort = Clamp( inp_i2ndMousePort, 0L, 4L);
  701. Startup2ndMouse(inp_i2ndMousePort);
  702. // clear button's buffer
  703. memset( _abKeysPressed, 0, sizeof( _abKeysPressed));
  704. // This can be enabled to pre-read the state of currently pressed keys
  705. // for snooping methods, since they only detect transitions.
  706. // That has effect of detecting key presses for keys that were held down before
  707. // enabling.
  708. // the entire thing is disabled because it caused last menu key to re-apply in game.
  709. #if 0
  710. // for each Key
  711. {for (INDEX iKey=0; iKey<ARRAYCOUNT(_akcKeys); iKey++) {
  712. struct KeyConversion &kc = _akcKeys[iKey];
  713. // get codes
  714. INDEX iKID = kc.kc_iKID;
  715. INDEX iScan = kc.kc_iScanCode;
  716. INDEX iVirt = kc.kc_iVirtKey;
  717. // if there is a valid virtkey
  718. if (iVirt>=0) {
  719. // transcribe if modifier
  720. if (iVirt == VK_LSHIFT) {
  721. iVirt = VK_SHIFT;
  722. }
  723. if (iVirt == VK_LCONTROL) {
  724. iVirt = VK_CONTROL;
  725. }
  726. if (iVirt == VK_LMENU) {
  727. iVirt = VK_MENU;
  728. }
  729. // is state is pressed
  730. if (GetAsyncKeyState(iVirt)&0x8000) {
  731. // mark it as pressed
  732. _abKeysPressed[iKID] = 0xFF;
  733. }
  734. }
  735. }}
  736. #endif
  737. // remember current status
  738. inp_bInputEnabled = TRUE;
  739. inp_bPollJoysticks = FALSE;
  740. }
  741. /*
  742. * Disable direct input
  743. */
  744. void CInput::DisableInput( void)
  745. {
  746. // skip if allready disabled
  747. if( !inp_bInputEnabled) return;
  748. UnhookWindowsHookEx(_hGetMsgHook);
  749. UnhookWindowsHookEx(_hSendMsgHook);
  750. // set mouse clip region to entire screen
  751. ClipCursor(NULL);
  752. // restore mouse pos
  753. SetCursorPos( inp_ptOldMousePos.x, inp_ptOldMousePos.y);
  754. // show mouse on screen
  755. while (ShowCursor(TRUE) < 0);
  756. // set system mouse settings
  757. SystemParametersInfo(SPI_SETMOUSE, 0, &inp_mscMouseSettings, 0);
  758. // eventually disable 2nd mouse
  759. Shutdown2ndMouse();
  760. // remember current status
  761. inp_bInputEnabled = FALSE;
  762. inp_bPollJoysticks = FALSE;
  763. }
  764. /*
  765. * Scan states of all available input sources
  766. */
  767. void CInput::GetInput(BOOL bPreScan)
  768. {
  769. // CTSingleLock sl(&csInput, TRUE);
  770. if (!inp_bInputEnabled) {
  771. return;
  772. }
  773. if (bPreScan && !inp_bAllowPrescan) {
  774. return;
  775. }
  776. // if not pre-scanning
  777. if (!bPreScan) {
  778. // clear button's buffer
  779. memset( inp_ubButtonsBuffer, 0, sizeof( inp_ubButtonsBuffer));
  780. // for each Key
  781. {for (INDEX iKey=0; iKey<ARRAYCOUNT(_akcKeys); iKey++) {
  782. struct KeyConversion &kc = _akcKeys[iKey];
  783. // get codes
  784. INDEX iKID = kc.kc_iKID;
  785. INDEX iScan = kc.kc_iScanCode;
  786. INDEX iVirt = kc.kc_iVirtKey;
  787. // if reading async keystate
  788. if (inp_iKeyboardReadingMethod==0) {
  789. // if there is a valid virtkey
  790. if (iVirt>=0) {
  791. // transcribe if modifier
  792. if (iVirt == VK_LSHIFT) {
  793. iVirt = VK_SHIFT;
  794. }
  795. if (iVirt == VK_LCONTROL) {
  796. iVirt = VK_CONTROL;
  797. }
  798. if (iVirt == VK_LMENU) {
  799. iVirt = VK_MENU;
  800. }
  801. // is state is pressed
  802. if (GetAsyncKeyState(iVirt)&0x8000) {
  803. // mark it as pressed
  804. inp_ubButtonsBuffer[iKID] = 0xFF;
  805. }
  806. }
  807. // if snooping messages
  808. } else {
  809. // if snooped that key is pressed
  810. if (_abKeysPressed[iKID]) {
  811. // mark it as pressed
  812. inp_ubButtonsBuffer[iKID] = 0xFF;
  813. }
  814. }
  815. }}
  816. }
  817. // read mouse position
  818. POINT pntMouse;
  819. if( GetCursorPos( &pntMouse))
  820. {
  821. FLOAT fDX = FLOAT( SLONG(pntMouse.x) - inp_slScreenCenterX);
  822. FLOAT fDY = FLOAT( SLONG(pntMouse.y) - inp_slScreenCenterY);
  823. FLOAT fSensitivity = inp_fMouseSensitivity;
  824. if( inp_bAllowMouseAcceleration) fSensitivity *= 0.25f;
  825. FLOAT fD = Sqrt(fDX*fDX+fDY*fDY);
  826. if (inp_bMousePrecision) {
  827. static FLOAT _tmTime = 0.0f;
  828. if( fD<inp_fMousePrecisionThreshold) _tmTime += 0.05f;
  829. else _tmTime = 0.0f;
  830. if( _tmTime>inp_fMousePrecisionTimeout) fSensitivity /= inp_fMousePrecisionFactor;
  831. }
  832. static FLOAT fDXOld;
  833. static FLOAT fDYOld;
  834. static TIME tmOldDelta;
  835. static CTimerValue tvBefore;
  836. CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  837. TIME tmNowDelta = (tvNow-tvBefore).GetSeconds();
  838. if (tmNowDelta<0.001f) {
  839. tmNowDelta = 0.001f;
  840. }
  841. tvBefore = tvNow;
  842. FLOAT fDXSmooth = (fDXOld*tmOldDelta+fDX*tmNowDelta)/(tmOldDelta+tmNowDelta);
  843. FLOAT fDYSmooth = (fDYOld*tmOldDelta+fDY*tmNowDelta)/(tmOldDelta+tmNowDelta);
  844. fDXOld = fDX;
  845. fDYOld = fDY;
  846. tmOldDelta = tmNowDelta;
  847. if (inp_bFilterMouse) {
  848. fDX = fDXSmooth;
  849. fDY = fDYSmooth;
  850. }
  851. // get final mouse values
  852. FLOAT fMouseRelX = +fDX*fSensitivity;
  853. FLOAT fMouseRelY = -fDY*fSensitivity;
  854. if (inp_bInvertMouse) {
  855. fMouseRelY = -fMouseRelY;
  856. }
  857. FLOAT fMouseRelZ = _iMouseZ;
  858. // just interpret values as normal
  859. inp_caiAllAxisInfo[1].cai_fReading = fMouseRelX;
  860. inp_caiAllAxisInfo[2].cai_fReading = fMouseRelY;
  861. inp_caiAllAxisInfo[3].cai_fReading = fMouseRelZ;
  862. // if not pre-scanning
  863. if (!bPreScan) {
  864. // detect wheel up/down movement
  865. _bWheelDn = FALSE;
  866. if (_iMouseZ>0) {
  867. if (_bWheelUp) {
  868. inp_ubButtonsBuffer[KID_MOUSEWHEELUP] = 0x00;
  869. } else {
  870. inp_ubButtonsBuffer[KID_MOUSEWHEELUP] = 0xFF;
  871. _iMouseZ = ClampDn(_iMouseZ-120, 0);
  872. }
  873. }
  874. _bWheelUp = inp_ubButtonsBuffer[KID_MOUSEWHEELUP];
  875. if (_iMouseZ<0) {
  876. if (_bWheelDn) {
  877. inp_ubButtonsBuffer[KID_MOUSEWHEELDOWN] = 0x00;
  878. } else {
  879. inp_ubButtonsBuffer[KID_MOUSEWHEELDOWN] = 0xFF;
  880. _iMouseZ = ClampUp(_iMouseZ+120, 0);
  881. }
  882. }
  883. _bWheelDn = inp_ubButtonsBuffer[KID_MOUSEWHEELDOWN];
  884. }
  885. }
  886. inp_bLastPrescan = bPreScan;
  887. // set cursor position to screen center
  888. if (pntMouse.x!=inp_slScreenCenterX || pntMouse.y!=inp_slScreenCenterY) {
  889. SetCursorPos(inp_slScreenCenterX, inp_slScreenCenterY);
  890. }
  891. // readout 2nd mouse if enabled
  892. if( _h2ndMouse!=NONE)
  893. {
  894. Poll2ndMouse();
  895. //CPrintF( "m2X: %4d, m2Y: %4d, m2B: 0x%02X\n", _i2ndMouseX, _i2ndMouseY, _i2ndMouseButtons);
  896. // handle 2nd mouse buttons
  897. if( _i2ndMouseButtons & 2) inp_ubButtonsBuffer[KID_2MOUSE1] = 0xFF;
  898. if( _i2ndMouseButtons & 1) inp_ubButtonsBuffer[KID_2MOUSE2] = 0xFF;
  899. if( _i2ndMouseButtons & 4) inp_ubButtonsBuffer[KID_2MOUSE3] = 0xFF;
  900. // handle 2nd mouse movement
  901. FLOAT fDX = _i2ndMouseX;
  902. FLOAT fDY = _i2ndMouseY;
  903. FLOAT fSensitivity = inp_f2ndMouseSensitivity;
  904. FLOAT fD = Sqrt(fDX*fDX+fDY*fDY);
  905. if( inp_b2ndMousePrecision) {
  906. static FLOAT _tm2Time = 0.0f;
  907. if( fD<inp_f2ndMousePrecisionThreshold) _tm2Time += 0.05f;
  908. else _tm2Time = 0.0f;
  909. if( _tm2Time>inp_f2ndMousePrecisionTimeout) fSensitivity /= inp_f2ndMousePrecisionFactor;
  910. }
  911. static FLOAT f2DXOld;
  912. static FLOAT f2DYOld;
  913. static TIME tm2OldDelta;
  914. static CTimerValue tv2Before;
  915. CTimerValue tvNow = _pTimer->GetHighPrecisionTimer();
  916. TIME tmNowDelta = (tvNow-tv2Before).GetSeconds();
  917. if( tmNowDelta<0.001f) tmNowDelta = 0.001f;
  918. tv2Before = tvNow;
  919. FLOAT fDXSmooth = (f2DXOld*tm2OldDelta+fDX*tmNowDelta) / (tm2OldDelta+tmNowDelta);
  920. FLOAT fDYSmooth = (f2DYOld*tm2OldDelta+fDY*tmNowDelta) / (tm2OldDelta+tmNowDelta);
  921. f2DXOld = fDX;
  922. f2DYOld = fDY;
  923. tm2OldDelta = tmNowDelta;
  924. if( inp_bFilter2ndMouse) {
  925. fDX = fDXSmooth;
  926. fDY = fDYSmooth;
  927. }
  928. // get final mouse values
  929. FLOAT fMouseRelX = +fDX*fSensitivity;
  930. FLOAT fMouseRelY = -fDY*fSensitivity;
  931. if( inp_bInvert2ndMouse) fMouseRelY = -fMouseRelY;
  932. // just interpret values as normal
  933. inp_caiAllAxisInfo[4].cai_fReading = fMouseRelX;
  934. inp_caiAllAxisInfo[5].cai_fReading = fMouseRelY;
  935. }
  936. // if joystick polling is enabled
  937. if (inp_bPollJoysticks || inp_bForceJoystickPolling) {
  938. // scan all available joysticks
  939. for( INDEX iJoy=0; iJoy<MAX_JOYSTICKS; iJoy++) {
  940. if (inp_abJoystickOn[iJoy] && iJoy<inp_ctJoysticksAllowed) {
  941. // scan joy state
  942. BOOL bSucceeded = ScanJoystick(iJoy, bPreScan);
  943. // if joystick reading failed
  944. if (!bSucceeded && inp_bAutoDisableJoysticks) {
  945. // kill it, so it doesn't slow down CPU
  946. CPrintF(TRANS("Joystick %d failed, disabling it!\n"), iJoy+1);
  947. inp_abJoystickOn[iJoy] = FALSE;
  948. }
  949. }
  950. }
  951. }
  952. }
  953. // Clear all input states (keys become not pressed, axes are reset to zero)
  954. void CInput::ClearInput( void)
  955. {
  956. // clear button's buffer
  957. memset( inp_ubButtonsBuffer, 0, sizeof( inp_ubButtonsBuffer));
  958. // clear axis values
  959. for (INDEX i=0; i<MAX_OVERALL_AXES; i++) {
  960. inp_caiAllAxisInfo[i].cai_fReading = 0;
  961. }
  962. }
  963. const CTString &CInput::GetAxisTransName( INDEX iAxisNo) const
  964. {
  965. return inp_astrAxisTran[iAxisNo];
  966. }
  967. /*
  968. * Scans axis and buttons for given joystick
  969. */
  970. BOOL CInput::ScanJoystick(INDEX iJoy, BOOL bPreScan)
  971. {
  972. // read joystick state
  973. JOYINFOEX ji;
  974. ji.dwFlags = JOY_RETURNBUTTONS|JOY_RETURNCENTERED|JOY_RETURNPOV|JOY_RETURNR|
  975. JOY_RETURNX|JOY_RETURNY|JOY_RETURNZ|JOY_RETURNU|JOY_RETURNV;
  976. ji.dwSize = sizeof( JOYINFOEX);
  977. MMRESULT mmResult = joyGetPosEx( JOYSTICKID1+iJoy, &ji);
  978. // if some error
  979. if( mmResult != JOYERR_NOERROR) {
  980. // fail
  981. return FALSE;
  982. }
  983. // for each available axis
  984. for( INDEX iAxis=0; iAxis<MAX_AXES_PER_JOYSTICK; iAxis++) {
  985. ControlAxisInfo &cai = inp_caiAllAxisInfo[ FIRST_JOYAXIS+iJoy*MAX_AXES_PER_JOYSTICK+iAxis];
  986. // if the axis is not present
  987. if (!cai.cai_bExisting) {
  988. // read as zero
  989. cai.cai_fReading = 0.0f;
  990. // skip to next axis
  991. continue;
  992. }
  993. // read its state
  994. SLONG slAxisReading;
  995. switch( iAxis) {
  996. case 0: slAxisReading = ji.dwXpos; break;
  997. case 1: slAxisReading = ji.dwYpos; break;
  998. case 2: slAxisReading = ji.dwZpos; break;
  999. case 3: slAxisReading = ji.dwRpos; break;
  1000. case 4: slAxisReading = ji.dwUpos; break;
  1001. case 5: slAxisReading = ji.dwVpos; break;
  1002. }
  1003. // convert from min..max to -1..+1
  1004. FLOAT fAxisReading = FLOAT(slAxisReading-cai.cai_slMin)/(cai.cai_slMax-cai.cai_slMin)*2.0f-1.0f;
  1005. // set current axis value
  1006. cai.cai_fReading = fAxisReading;
  1007. }
  1008. // if not pre-scanning
  1009. if (!bPreScan) {
  1010. INDEX iButtonTotal = FIRST_JOYBUTTON+iJoy*MAX_BUTTONS_PER_JOYSTICK;
  1011. // for each available button
  1012. for( INDEX iButton=0; iButton<32; iButton++) {
  1013. // test if the button is pressed
  1014. if(ji.dwButtons & (1L<<iButton)) {
  1015. inp_ubButtonsBuffer[ iButtonTotal++] = 128;
  1016. } else {
  1017. inp_ubButtonsBuffer[ iButtonTotal++] = 0;
  1018. }
  1019. }
  1020. // POV hat initially not pressed
  1021. // CPrintF("%d\n", ji.dwPOV);
  1022. INDEX iStartPOV = iButtonTotal;
  1023. inp_ubButtonsBuffer[ iStartPOV+0] = 0;
  1024. inp_ubButtonsBuffer[ iStartPOV+1] = 0;
  1025. inp_ubButtonsBuffer[ iStartPOV+2] = 0;
  1026. inp_ubButtonsBuffer[ iStartPOV+3] = 0;
  1027. // if we have POV
  1028. if (inp_abJoystickHasPOV[iJoy]) {
  1029. // check the four pov directions
  1030. if (ji.dwPOV==JOY_POVFORWARD) {
  1031. inp_ubButtonsBuffer[ iStartPOV+0] = 128;
  1032. } else if (ji.dwPOV==JOY_POVRIGHT) {
  1033. inp_ubButtonsBuffer[ iStartPOV+1] = 128;
  1034. } else if (ji.dwPOV==JOY_POVBACKWARD) {
  1035. inp_ubButtonsBuffer[ iStartPOV+2] = 128;
  1036. } else if (ji.dwPOV==JOY_POVLEFT) {
  1037. inp_ubButtonsBuffer[ iStartPOV+3] = 128;
  1038. // and four mid-positions
  1039. } else if (ji.dwPOV==JOY_POVFORWARD+4500) {
  1040. inp_ubButtonsBuffer[ iStartPOV+0] = 128;
  1041. inp_ubButtonsBuffer[ iStartPOV+1] = 128;
  1042. } else if (ji.dwPOV==JOY_POVRIGHT+4500) {
  1043. inp_ubButtonsBuffer[ iStartPOV+1] = 128;
  1044. inp_ubButtonsBuffer[ iStartPOV+2] = 128;
  1045. } else if (ji.dwPOV==JOY_POVBACKWARD+4500) {
  1046. inp_ubButtonsBuffer[ iStartPOV+2] = 128;
  1047. inp_ubButtonsBuffer[ iStartPOV+3] = 128;
  1048. } else if (ji.dwPOV==JOY_POVLEFT+4500) {
  1049. inp_ubButtonsBuffer[ iStartPOV+3] = 128;
  1050. inp_ubButtonsBuffer[ iStartPOV+0] = 128;
  1051. }
  1052. }
  1053. }
  1054. // successful
  1055. return TRUE;
  1056. }