Keyboard.cpp 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************
  5. Operate on Scan Codes as Int, valid >=0, invalid <0, because on:
  6. Mac KB_A has scan code=0
  7. Android there are scan codes bigger than byte
  8. /******************************************************************************/
  9. #if WINDOWS_OLD
  10. /*
  11. RightAlt (AltGr on Polish, Norwegian, .. keyboards) also triggers GetKeyState/GetAsyncKeyState VK_LCONTROL
  12. changing Direct Input exclusive mode (calling 'Unacquire' and 'Acquire') resets the 'GetDeviceState' of any currently pressed keys, they need to be pushed again to activate their state
  13. Pressing Ctrl+Shift (system shortcut for changing language input) may disable 'GetKeyState' for Ctrl
  14. Prefer key events instead of 'GetDeviceState' to record pushes/releases within the same frame
  15. */
  16. enum COOP_MODE
  17. {
  18. BACKGROUND,
  19. FOREGROUND,
  20. KEYBOARD_MODE=FOREGROUND, // prefer FOREGROUND to avoid recording input when not focused, maybe BACKGROUND could trigger some anti-virus warnings (potential key-logger), otherwise we could use (_exclusive ? FOREGROUND : BACKGROUND) // prefer background mode so we can get correct information about 'GetDeviceState' when activating the app with LMB (otherwise, the state is delayed by 1 frame), however _exclusive does not support BACKGROUND
  21. };
  22. #if !KB_RAW_INPUT
  23. #define BUF_KEYS 256
  24. struct DIK
  25. {
  26. KB_KEY key;
  27. Byte dik;
  28. };
  29. static const DIK Keys[]= // only keys known to have the same physical location on all keyboard layouts can be listed here
  30. {
  31. {KB_LCTRL , DIK_LCONTROL},
  32. //{KB_RCTRL , DIK_RCONTROL}, processed using WM_*KEY*
  33. {KB_LSHIFT, DIK_LSHIFT }, // WM_*KEY* does not provide an option to check for left/right shift
  34. {KB_RSHIFT, DIK_RSHIFT }, // WM_*KEY* does not provide an option to check for left/right shift
  35. //{KB_LALT , DIK_LALT }, processed using WM_*KEY*
  36. //{KB_RALT , DIK_RALT }, processed using WM_*KEY*
  37. //{KB_LWIN , DIK_LWIN }, processed using WM_*KEY*
  38. //{KB_RWIN , DIK_RWIN }, processed using WM_*KEY*
  39. {KB_PRINT , DIK_SYSRQ }, // VK_PRINT is not processed because it's assigned as Screen Capture
  40. };
  41. #endif
  42. #elif ANDROID
  43. /*
  44. Key characters come from:
  45. -hardware keyboards (detected only from C++ based on keycodes, 'dispatchKeyEvent' does not detect them)
  46. -touch keyboards (detected from C++ based on keycodes but without unicode and from 'dispatchKeyEvent')
  47. To prevent accidental detecting the same key twice, only one source is allowed per frame.
  48. */
  49. struct InputText
  50. {
  51. Str text;
  52. VecI2 cur;
  53. };
  54. static Bool InputTextIs;
  55. static InputText InputTextData;
  56. static SyncLock InputTextLock;
  57. Byte KeySource;
  58. #endif
  59. Keyboard Kb;
  60. /******************************************************************************/
  61. #if ANDROID
  62. static void SetKeyboardVisible(Bool visible)
  63. {
  64. #if 0 // not working
  65. if(AndroidApp && AndroidApp->activity)
  66. if(visible)ANativeActivity_showSoftInput(AndroidApp->activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED); // ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT
  67. else ANativeActivity_hideSoftInput(AndroidApp->activity, 0); // ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY
  68. #else
  69. if(Jni && ActivityClass && Activity)
  70. {
  71. #if 1 // activate keyboard using EditText Java object to allow auto-completion
  72. if(visible)
  73. {
  74. C Str *text=&S;
  75. Int start=0, end=0;
  76. Bool pass=false;
  77. if(Gui.kb())switch(Gui.kb()->type())
  78. {
  79. case GO_TEXTBOX:
  80. {
  81. TextBox &tb=Gui.kb()->asTextBox();
  82. text =&tb();
  83. end = tb.cursor();
  84. start=((tb._edit.sel<0) ? tb.cursor() : tb._edit.sel);
  85. }break;
  86. case GO_TEXTLINE:
  87. {
  88. TextLine &tl=Gui.kb()->asTextLine();
  89. text =&tl();
  90. pass = tl.password();
  91. end = tl.cursor ();
  92. start=((tl._edit.sel<0) ? tl.cursor() : tl._edit.sel);
  93. }break;
  94. }
  95. if(JMethodID editText=Jni->GetMethodID(ActivityClass, "editText", "(Ljava/lang/String;IIZ)V"))
  96. if(JString t=JString(Jni, *text))
  97. Jni->CallVoidMethod(Activity, editText, t(), jint(start), jint(end), jboolean(pass));
  98. }else
  99. {
  100. if(JMethodID editTextHide=Jni->GetMethodID(ActivityClass, "editTextHide", "()V"))
  101. Jni->CallVoidMethod(Activity, editTextHide);
  102. }
  103. #else
  104. if(JClass ContextClass="android/content/Context")
  105. if(JFieldID INPUT_METHOD_SERVICEField=Jni->GetStaticFieldID(ContextClass, "INPUT_METHOD_SERVICE", "Ljava/lang/String;"))
  106. if(JObject INPUT_METHOD_SERVICE=Jni->GetStaticObjectField(ContextClass, INPUT_METHOD_SERVICEField))
  107. if(JClass InputMethodManagerClass="android/view/inputmethod/InputMethodManager")
  108. if(JMethodID getSystemService=Jni->GetMethodID(ActivityClass, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"))
  109. if(JObject InputMethodManager=Jni->CallObjectMethod(Activity, getSystemService, INPUT_METHOD_SERVICE()))
  110. if(JMethodID getWindow=Jni->GetMethodID(ActivityClass, "getWindow", "()Landroid/view/Window;"))
  111. if(JObject window=Jni->CallObjectMethod(Activity, getWindow))
  112. if(JClass WindowClass="android/view/Window")
  113. if(JMethodID getDecorView=Jni->GetMethodID(WindowClass, "getDecorView", "()Landroid/view/View;"))
  114. if(JObject decor_view=Jni->CallObjectMethod(window, getDecorView))
  115. {
  116. if(visible)
  117. {
  118. if(JMethodID showSoftInput=Jni->GetMethodID(InputMethodManagerClass, "showSoftInput", "(Landroid/view/View;I)Z"))
  119. Bool ok=Jni->CallBooleanMethod(InputMethodManager, showSoftInput, decor_view(), jint(0));
  120. }else
  121. {
  122. if(JClass ViewClass="android/view/View")
  123. if(JMethodID getWindowToken=Jni->GetMethodID(ViewClass, "getWindowToken", "()Landroid/os/IBinder;"))
  124. if(JObject binder=Jni->CallObjectMethod(decor_view, getWindowToken))
  125. if(JMethodID hideSoftInput=Jni->GetMethodID(InputMethodManagerClass, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z"))
  126. Bool ok=Jni->CallBooleanMethod(InputMethodManager, hideSoftInput, binder(), jint(0));
  127. }
  128. }
  129. #endif
  130. }
  131. #endif
  132. }
  133. static void UpdateKeyboardRect()
  134. {
  135. if(Kb._visible && !Kb.hwAvailable())
  136. {
  137. Kb._recti.set(0, D.resH()/2, D.resW(), D.resH()); // initially set as lower half of the screen
  138. if(Jni && ActivityClass)
  139. if(JMethodID getWindow=Jni->GetMethodID(ActivityClass, "getWindow", "()Landroid/view/Window;"))
  140. if(JObject window=Jni->CallObjectMethod(Activity, getWindow))
  141. if(JClass WindowClass="android/view/Window")
  142. if(JMethodID getDecorView=Jni->GetMethodID(WindowClass, "getDecorView", "()Landroid/view/View;"))
  143. if(JObject decor_view=Jni->CallObjectMethod(window, getDecorView))
  144. if(JClass ViewClass="android/view/View")
  145. if(JMethodID getWindowVisibleDisplayFrame=Jni->GetMethodID(ViewClass, "getWindowVisibleDisplayFrame", "(Landroid/graphics/Rect;)V"))
  146. if(JClass RectClass="android/graphics/Rect")
  147. if(JMethodID RectCtor=Jni->GetMethodID(RectClass, "<init>", "()V"))
  148. if(JFieldID left=Jni->GetFieldID(RectClass, "left", "I"))
  149. if(JFieldID right=Jni->GetFieldID(RectClass, "right", "I"))
  150. if(JFieldID top=Jni->GetFieldID(RectClass, "top", "I"))
  151. if(JFieldID bottom=Jni->GetFieldID(RectClass, "bottom", "I"))
  152. if(JObject r=Jni->NewObject(RectClass, RectCtor))
  153. {
  154. Jni->CallVoidMethod(decor_view, getWindowVisibleDisplayFrame, r());
  155. RectI app_recti(Jni->GetIntField(r, left), Jni->GetIntField(r, top), Jni->GetIntField(r, right), Jni->GetIntField(r, bottom)); // this is the app rect (for example 0,0,1280,800), but we want the keyboard rect
  156. Int l_size=Max(0, app_recti.min.x-0),
  157. r_size=Max(0, D.resW()-app_recti.max.x ),
  158. t_size=Max(0, app_recti.min.y-0),
  159. b_size=Max(0, D.resH()-app_recti.max.y ), max_size=Max(l_size, r_size, t_size, b_size);
  160. if(b_size>=max_size)Kb._recti.set( 0, D.resH()-b_size, D.resW(), D.resH());else // bottom size is the biggest
  161. if(t_size>=max_size)Kb._recti.set( 0, 0, D.resW(), t_size );else // top size is the biggest
  162. if(l_size>=max_size)Kb._recti.set( 0, 0, l_size , D.resH());else // left size is the biggest
  163. Kb._recti.set(D.resW()-r_size, 0, D.resW(), D.resH()); // right size is the biggest
  164. }
  165. }
  166. }
  167. #endif
  168. /******************************************************************************/
  169. inline static void Set(KB_KEY key, Char c, Char qwerty_shift, CChar8 *name)
  170. {
  171. Kb._key_char[key]=c;
  172. Kb._key_name[key]=name;
  173. }
  174. Keyboard::Keyboard()
  175. {
  176. #if 0 // there's only one 'Keyboard' global 'Kb' and it doesn't need clearing members to zero
  177. _exclusive=_text_input=_refresh_visible=_visible=false;
  178. #endif
  179. _last_key_scan_code=-1;
  180. _imm=true;
  181. _cur=_last=-1; _last_t=0;
  182. _curh_tn=0.200f;
  183. #if 0
  184. REPA(key_char)Set(KB_KEY(i), '\0', '\0', null);
  185. #endif
  186. // set these first in case KB_NPENTER==KB_ENTER, so that KB_ENTER can override the name of KB_NPENTER
  187. Set(KB_NPDIV , '/' , '/' , "NumPad/");
  188. Set(KB_NPMUL , '*' , '*' , "NumPad*");
  189. Set(KB_NPSUB , '-' , '-' , "NumPad-");
  190. Set(KB_NPADD , '+' , '+' , "NumPad+");
  191. Set(KB_NPDEL , '\0', '\0', "NumPadDel");
  192. Set(KB_NPENTER, '\n', '\n', "NumPadEnter");
  193. Set(KB_NP0, '0', '\0', "NumPad0");
  194. Set(KB_NP1, '1', '\0', "NumPad1");
  195. Set(KB_NP2, '2', '\0', "NumPad2");
  196. Set(KB_NP3, '3', '\0', "NumPad3");
  197. Set(KB_NP4, '4', '\0', "NumPad4");
  198. Set(KB_NP5, '5', '\0', "NumPad5");
  199. Set(KB_NP6, '6', '\0', "NumPad6");
  200. Set(KB_NP7, '7', '\0', "NumPad7");
  201. Set(KB_NP8, '8', '\0', "NumPad8");
  202. Set(KB_NP9, '9', '\0', "NumPad9");
  203. Set(KB_0, '0', ')', "0");
  204. Set(KB_1, '1', '!', "1");
  205. Set(KB_2, '2', '@', "2");
  206. Set(KB_3, '3', '#', "3");
  207. Set(KB_4, '4', '$', "4");
  208. Set(KB_5, '5', '%', "5");
  209. Set(KB_6, '6', '^', "6");
  210. Set(KB_7, '7', '&', "7");
  211. Set(KB_8, '8', '*', "8");
  212. Set(KB_9, '9', '(', "9");
  213. Set(KB_A, 'a', 'A', "A");
  214. Set(KB_B, 'b', 'B', "B");
  215. Set(KB_C, 'c', 'C', "C");
  216. Set(KB_D, 'd', 'D', "D");
  217. Set(KB_E, 'e', 'E', "E");
  218. Set(KB_F, 'f', 'F', "F");
  219. Set(KB_G, 'g', 'G', "G");
  220. Set(KB_H, 'h', 'H', "H");
  221. Set(KB_I, 'i', 'I', "I");
  222. Set(KB_J, 'j', 'J', "J");
  223. Set(KB_K, 'k', 'K', "K");
  224. Set(KB_L, 'l', 'L', "L");
  225. Set(KB_M, 'm', 'M', "M");
  226. Set(KB_N, 'n', 'N', "N");
  227. Set(KB_O, 'o', 'O', "O");
  228. Set(KB_P, 'p', 'P', "P");
  229. Set(KB_Q, 'q', 'Q', "Q");
  230. Set(KB_R, 'r', 'R', "R");
  231. Set(KB_S, 's', 'S', "S");
  232. Set(KB_T, 't', 'T', "T");
  233. Set(KB_U, 'u', 'U', "U");
  234. Set(KB_V, 'v', 'V', "V");
  235. Set(KB_W, 'w', 'W', "W");
  236. Set(KB_X, 'x', 'X', "X");
  237. Set(KB_Y, 'y', 'Y', "Y");
  238. Set(KB_Z, 'z', 'Z', "Z");
  239. Set(KB_F1 , '\0', '\0', "F1");
  240. Set(KB_F2 , '\0', '\0', "F2");
  241. Set(KB_F3 , '\0', '\0', "F3");
  242. Set(KB_F4 , '\0', '\0', "F4");
  243. Set(KB_F5 , '\0', '\0', "F5");
  244. Set(KB_F6 , '\0', '\0', "F6");
  245. Set(KB_F7 , '\0', '\0', "F7");
  246. Set(KB_F8 , '\0', '\0', "F8");
  247. Set(KB_F9 , '\0', '\0', "F9");
  248. Set(KB_F10, '\0', '\0', "F10");
  249. Set(KB_F11, '\0', '\0', "F11");
  250. Set(KB_F12, '\0', '\0', "F12");
  251. Set(KB_ESC , '\0', '\0', "Escape");
  252. Set(KB_ENTER, '\n', '\n', "Enter");
  253. Set(KB_SPACE, ' ' , ' ' , "Space");
  254. Set(KB_BACK , '\0', '\0', "Backspace");
  255. Set(KB_TAB , '\t', '\t', "Tab");
  256. Set(KB_LCTRL , '\0', '\0', "LeftControl");
  257. Set(KB_RCTRL , '\0', '\0', "RightControl");
  258. Set(KB_LSHIFT, '\0', '\0', "LeftShift");
  259. Set(KB_RSHIFT, '\0', '\0', "RightShift");
  260. Set(KB_LALT , '\0', '\0', "LeftAlt");
  261. Set(KB_RALT , '\0', '\0', "RightAlt");
  262. #if APPLE
  263. Set(KB_LWIN , '\0', '\0', "LeftCmd");
  264. Set(KB_RWIN , '\0', '\0', "RightCmd");
  265. #else
  266. Set(KB_LWIN , '\0', '\0', "LeftWin");
  267. Set(KB_RWIN , '\0', '\0', "RightWin");
  268. #endif
  269. Set(KB_MENU , '\0', '\0', "Menu");
  270. Set(KB_FIND , '\0', '\0', "Find");
  271. Set(KB_LEFT , '\0', '\0', "Left");
  272. Set(KB_RIGHT, '\0', '\0', "Right");
  273. Set(KB_UP , '\0', '\0', "Up");
  274. Set(KB_DOWN , '\0', '\0', "Down");
  275. Set(KB_INS , '\0', '\0', "Insert");
  276. Set(KB_DEL , '\0', '\0', "Delete");
  277. Set(KB_HOME, '\0', '\0', "Home");
  278. Set(KB_END , '\0', '\0', "End");
  279. Set(KB_PGUP, '\0', '\0', "PageUp");
  280. Set(KB_PGDN, '\0', '\0', "PageDown");
  281. Set(KB_SUB , '-' , '_', "-");
  282. Set(KB_EQUAL , '=' , '+', "=");
  283. Set(KB_LBR , '[' , '{', "[");
  284. Set(KB_RBR , ']' , '}', "]");
  285. Set(KB_SEMICOLON , ';' , ':', ";");
  286. Set(KB_APOSTROPHE, '\'', '"', "'");
  287. Set(KB_COMMA , ',' , '<', ",");
  288. Set(KB_DOT , '.' , '>', ".");
  289. Set(KB_SLASH , '/' , '?', "/");
  290. Set(KB_BACKSLASH , '\\', '|', "\\");
  291. Set(KB_TILDE , '`' , '~', "Tilde");
  292. Set(KB_CAPS , '\0', '\0', "CapsLock");
  293. Set(KB_NUM , '\0', '\0', "NumLock");
  294. Set(KB_SCROLL, '\0', '\0', "ScrollLock");
  295. Set(KB_PRINT , '\0', '\0', "PrintScreen");
  296. Set(KB_PAUSE , '\0', '\0', "Pause");
  297. Set(KB_VOL_DOWN, '\0', '\0', "VolumeDown");
  298. Set(KB_VOL_UP , '\0', '\0', "VolumeUp");
  299. Set(KB_VOL_MUTE, '\0', '\0', "VolumeMute");
  300. Set(KB_NAV_BACK , '\0', '\0', "NavigateBackward");
  301. Set(KB_NAV_FORWARD, '\0', '\0', "NavigateForward");
  302. Set(KB_MEDIA_PREV, '\0', '\0', "MediaPrevious");
  303. Set(KB_MEDIA_NEXT, '\0', '\0', "MediaNext");
  304. Set(KB_MEDIA_PLAY, '\0', '\0', "MediaPlay");
  305. Set(KB_MEDIA_STOP, '\0', '\0', "MediaStop");
  306. Set(KB_ZOOM_IN , '\0', '\0', "ZoomIn");
  307. Set(KB_ZOOM_OUT, '\0', '\0', "ZoomOut");
  308. }
  309. #if MAC
  310. static void KeyboardChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) {Kb.setLayout();}
  311. #endif
  312. void Keyboard::init() // Linux requires XDisplay to be created, so we can't do this in the constructor
  313. {
  314. setLayout();
  315. #if MAC
  316. // add callback when keyboard layout changes
  317. CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), null, KeyboardChanged, kTISNotifySelectedKeyboardInputSourceChanged, null, CFNotificationSuspensionBehaviorDeliverImmediately);
  318. #endif
  319. }
  320. /******************************************************************************/
  321. void Keyboard::del()
  322. {
  323. #if WINDOWS_OLD
  324. #if KB_RAW_INPUT
  325. RAWINPUTDEVICE rid[1];
  326. rid[0].usUsagePage=0x01;
  327. rid[0].usUsage =0x06; // keyboard
  328. rid[0].dwFlags =RIDEV_REMOVE;
  329. rid[0].hwndTarget =App.Hwnd();
  330. RegisterRawInputDevices(rid, Elms(rid), SIZE(RAWINPUTDEVICE));
  331. #else
  332. RELEASE(_did);
  333. #endif
  334. #endif
  335. }
  336. void Keyboard::create()
  337. {
  338. if(LogInit)LogN("Keyboard.create");
  339. #if WINDOWS_OLD
  340. #if KB_RAW_INPUT
  341. RAWINPUTDEVICE rid[1];
  342. rid[0].usUsagePage=0x01;
  343. rid[0].usUsage =0x06; // keyboard
  344. rid[0].dwFlags =((KEYBOARD_MODE==BACKGROUND) ? RIDEV_INPUTSINK : 0)|(_exclusive ? RIDEV_NOHOTKEYS : 0);
  345. rid[0].hwndTarget =App.Hwnd();
  346. RegisterRawInputDevices(rid, Elms(rid), SIZE(RAWINPUTDEVICE));
  347. #else
  348. // DISCL_EXCLUSIVE|DISCL_BACKGROUND is not possible at all
  349. // DISCL_NOWINKEY |DISCL_BACKGROUND is not possible at all
  350. // Keyboard doesn't use DISCL_EXCLUSIVE at all, because then the WM_CHAR and WM_KEYDOWN wouldn't be processed
  351. if(InputDevices.DI)
  352. if(OK(InputDevices.DI->CreateDevice(GUID_SysKeyboard, &_did, null)))
  353. {
  354. if(OK(_did->SetDataFormat(&c_dfDIKeyboard)))
  355. if(OK(_did->SetCooperativeLevel(App.Hwnd(), (_exclusive ? DISCL_NOWINKEY : 0)|DISCL_NONEXCLUSIVE|((KEYBOARD_MODE==FOREGROUND) ? DISCL_FOREGROUND : DISCL_BACKGROUND))))
  356. {
  357. DIPROPDWORD dipdw;
  358. dipdw.diph.dwSize =SIZE(DIPROPDWORD );
  359. dipdw.diph.dwHeaderSize=SIZE(DIPROPHEADER);
  360. dipdw.diph.dwObj =0;
  361. dipdw.diph.dwHow =DIPH_DEVICE;
  362. dipdw.dwData =BUF_KEYS;
  363. _did->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);
  364. if(KEYBOARD_MODE==BACKGROUND)_did->Acquire(); // in background mode we always want the keyboard to be acquired
  365. goto ok;
  366. }
  367. RELEASE(_did);
  368. }
  369. ok:;
  370. #endif
  371. #endif
  372. }
  373. /******************************************************************************/
  374. Char Keyboard::keyChar(KB_KEY k)C {ASSERT(1<<(8*SIZE(k))==ELMS(_key_char)); return _key_char[k];}
  375. CChar8* Keyboard::keyName(KB_KEY k)C {ASSERT(1<<(8*SIZE(k))==ELMS(_key_name)); return _key_name[k];}
  376. /******************************************************************************/
  377. #if WINDOWS_OLD
  378. #define KB_F13 KB_NONE
  379. #define KB_F14 KB_NONE
  380. #define KB_F15 KB_NONE
  381. #define KB_F16 KB_NONE
  382. #define KB_F17 KB_NONE
  383. #define KB_F18 KB_NONE
  384. #define KB_F19 KB_NONE
  385. #if 1 // these keys should be ignored because they're different even though US keyboard was selected, so when US keyboard is selected, then '_qwerty' and 'MapVirtualKey' have 1:1 mapping
  386. #define KB_PRINT KB_NONE
  387. #define KB_NP5 KB_NONE
  388. #define KB_PAUSE KB_NONE
  389. #define KB_LWIN KB_NONE
  390. #define KB_RWIN KB_NONE
  391. #define KB_MENU KB_NONE
  392. #endif
  393. static const KB_KEY ScanCodeToQwertyKey[]=
  394. {
  395. // 0 1 2 3 4 5 6 7 8 9 A B C D E F
  396. KB_NONE, KB_ESC , KB_1 , KB_2 , KB_3 , KB_4 , KB_5 , KB_6 , KB_7 , KB_8 , KB_9 , KB_0 , KB_SUB , KB_EQUAL, KB_BACK , KB_TAB , // 0
  397. KB_Q , KB_W , KB_E , KB_R , KB_T , KB_Y , KB_U , KB_I , KB_O , KB_P , KB_LBR , KB_RBR , KB_ENTER, KB_LCTRL, KB_A , KB_S , // 1
  398. KB_D , KB_F , KB_G , KB_H , KB_J , KB_K , KB_L , KB_SEMI , KB_APO , KB_TILDE, KB_LSHIFT, KB_BSLASH, KB_Z , KB_X , KB_C , KB_V , // 2
  399. KB_B , KB_N , KB_M , KB_COMMA , KB_DOT , KB_SLASH, KB_RSHIFT, KB_PRINT, KB_LALT, KB_SPACE, KB_CAPS , KB_F1 , KB_F2 , KB_F3 , KB_F4 , KB_F5 , // 3
  400. KB_F6 , KB_F7 , KB_F8 , KB_F9 , KB_F10 , KB_NUM , KB_SCROLL, KB_HOME , KB_UP , KB_PGUP , KB_NPSUB , KB_LEFT , KB_NP5 , KB_RIGHT, KB_NPADD, KB_END , // 4
  401. KB_DOWN, KB_PGDN, KB_INS , KB_DEL , KB_NONE, KB_NONE , KB_NONE , KB_F11 , KB_F12 , KB_PAUSE, KB_NONE , KB_LWIN , KB_RWIN , KB_MENU , KB_NONE , KB_NONE, // 5
  402. KB_NONE, KB_NONE, KB_NONE, KB_NONE , KB_F13 , KB_F14 , KB_F15 , KB_F16 , KB_F17 , KB_F18 , KB_F19 , KB_NONE , KB_NONE , KB_NONE , KB_NONE , KB_NONE, // 6
  403. KB_NONE, KB_NONE, KB_NONE, KB_NONE , KB_NONE, KB_NONE , KB_NONE , KB_NONE , KB_NONE, KB_NONE , KB_NONE , KB_NONE , KB_NONE , KB_NONE , KB_NONE , KB_NONE, // 7
  404. };
  405. #undef KB_PRINT
  406. #undef KB_NP5
  407. #undef KB_PAUSE
  408. #undef KB_LWIN
  409. #undef KB_RWIN
  410. #undef KB_MENU
  411. #elif MAC
  412. KB_KEY ScanCodeToKey[Elms(ScanCodeToQwertyKey)];
  413. const KB_KEY ScanCodeToQwertyKey[0x80]=
  414. {
  415. // 0x00
  416. KB_A,
  417. KB_S,
  418. KB_D,
  419. KB_F,
  420. KB_H,
  421. KB_G,
  422. KB_Z,
  423. KB_X,
  424. KB_C,
  425. KB_V,
  426. KB_NONE,
  427. KB_B,
  428. KB_Q,
  429. KB_W,
  430. KB_E,
  431. KB_R,
  432. // 0x10
  433. KB_Y,
  434. KB_T,
  435. KB_1,
  436. KB_2,
  437. KB_3,
  438. KB_4,
  439. KB_6,
  440. KB_5,
  441. KB_EQUAL,
  442. KB_9,
  443. KB_7,
  444. KB_SUB,
  445. KB_8,
  446. KB_0,
  447. KB_RBR,
  448. KB_O,
  449. // 0x20
  450. KB_U,
  451. KB_LBR,
  452. KB_I,
  453. KB_P,
  454. KB_ENTER,
  455. KB_L,
  456. KB_J,
  457. KB_APO,
  458. KB_K,
  459. KB_SEMI,
  460. KB_BSLASH,
  461. KB_COMMA,
  462. KB_SLASH,
  463. KB_N,
  464. KB_M,
  465. KB_DOT,
  466. // 0x30
  467. KB_TAB,
  468. KB_SPACE,
  469. KB_TILDE,
  470. KB_BACK,
  471. KB_NONE, // KB_NP_ENTER
  472. KB_ESC,
  473. KB_NONE, // KB_RWIN
  474. KB_NONE, // KB_LWIN
  475. KB_NONE, // KB_LSHIFT
  476. KB_NONE, // KB_CAPS
  477. KB_NONE, // KB_LALT
  478. KB_NONE, // KB_LCTRL
  479. KB_NONE, // KB_RSHIFT
  480. KB_NONE, // KB_RALT
  481. KB_NONE, // KB_RCTRL
  482. KB_NONE,
  483. // 0x40
  484. KB_NONE,
  485. KB_NPDEL,
  486. KB_NONE,
  487. KB_NPMUL,
  488. KB_NONE,
  489. KB_NPADD,
  490. KB_NONE,
  491. KB_NUM,
  492. KB_VOL_UP ,
  493. KB_VOL_DOWN,
  494. KB_VOL_MUTE,
  495. KB_NPDIV,
  496. KB_NPENTER,
  497. KB_NONE,
  498. KB_NPSUB,
  499. KB_NONE,
  500. // 0x50
  501. KB_NONE,
  502. KB_NONE,
  503. KB_NP0,
  504. KB_NP1,
  505. KB_NP2,
  506. KB_NP3,
  507. KB_NP4,
  508. KB_NP5,
  509. KB_NP6,
  510. KB_NP7,
  511. KB_NONE,
  512. KB_NP8,
  513. KB_NP9,
  514. KB_NONE,
  515. KB_NONE,
  516. KB_NONE,
  517. // 0x60
  518. KB_F5,
  519. KB_F6,
  520. KB_F7,
  521. KB_F3,
  522. KB_F8,
  523. KB_F9,
  524. KB_NONE,
  525. KB_F11,
  526. KB_NONE,
  527. KB_PRINT,
  528. KB_NONE,
  529. KB_SCROLL,
  530. KB_NONE,
  531. KB_F10,
  532. KB_MENU,
  533. KB_F12,
  534. // 0x70
  535. KB_NONE,
  536. KB_PAUSE,
  537. KB_INS,
  538. KB_HOME,
  539. KB_PGUP,
  540. KB_DEL,
  541. KB_F4,
  542. KB_END,
  543. KB_F2,
  544. KB_PGDN,
  545. KB_F1,
  546. KB_LEFT,
  547. KB_RIGHT,
  548. KB_DOWN,
  549. KB_UP,
  550. };
  551. #elif LINUX
  552. KB_KEY ScanCodeToKey[Elms(ScanCodeToQwertyKey)];
  553. const KB_KEY ScanCodeToQwertyKey[0x90]=
  554. {
  555. KB_NONE, // 0x00
  556. KB_NONE, // 0x01
  557. KB_NONE, // 0x02
  558. KB_NONE, // 0x03
  559. KB_NONE, // 0x04
  560. KB_NONE, // 0x05
  561. KB_NONE, // 0x06
  562. KB_NONE, // 0x07
  563. KB_NONE, // 0x08
  564. KB_ESC, // 0x09
  565. KB_1, // 0x0A
  566. KB_2, // 0x0B
  567. KB_3, // 0x0C
  568. KB_4, // 0x0D
  569. KB_5, // 0x0E
  570. KB_6, // 0x0F
  571. KB_7, // 0x10
  572. KB_8, // 0x11
  573. KB_9, // 0x12
  574. KB_0, // 0x13
  575. KB_SUB, // 0x14
  576. KB_EQUAL, // 0x15
  577. KB_BACK, // 0x16
  578. KB_TAB, // 0x17
  579. KB_Q, // 0x18
  580. KB_W, // 0x19
  581. KB_E, // 0x1A
  582. KB_R, // 0x1B
  583. KB_T, // 0x1C
  584. KB_Y, // 0x1D
  585. KB_U, // 0x1E
  586. KB_I, // 0x1F
  587. KB_O, // 0x20
  588. KB_P, // 0x21
  589. KB_LBR, // 0x22
  590. KB_RBR, // 0x23
  591. KB_ENTER, // 0x24
  592. KB_LCTRL, // 0x25
  593. KB_A, // 0x26
  594. KB_S, // 0x27
  595. KB_D, // 0x28
  596. KB_F, // 0x29
  597. KB_G, // 0x2A
  598. KB_H, // 0x2B
  599. KB_J, // 0x2C
  600. KB_K, // 0x2D
  601. KB_L, // 0x2E
  602. KB_SEMI, // 0x2F
  603. KB_APO, // 0x30
  604. KB_TILDE, // 0x31
  605. KB_LSHIFT, // 0x32
  606. KB_BACKSLASH, // 0x33
  607. KB_Z, // 0x34
  608. KB_X, // 0x35
  609. KB_C, // 0x36
  610. KB_V, // 0x37
  611. KB_B, // 0x38
  612. KB_N, // 0x39
  613. KB_M, // 0x3A
  614. KB_COMMA, // 0x3B
  615. KB_DOT, // 0x3C
  616. KB_SLASH, // 0x3D
  617. KB_RSHIFT, // 0x3E
  618. KB_NPMUL, // 0x3F
  619. KB_LALT, // 0x40
  620. KB_SPACE, // 0x41
  621. KB_NONE, // 0x42
  622. KB_F1, // 0x43
  623. KB_F2, // 0x44
  624. KB_F3, // 0x45
  625. KB_F4, // 0x46
  626. KB_F5, // 0x47
  627. KB_F6, // 0x48
  628. KB_F7, // 0x49
  629. KB_F8, // 0x4A
  630. KB_F9, // 0x4B
  631. KB_F10, // 0x4C
  632. KB_NUM, // 0x4D
  633. KB_SCROLL, // 0x4E
  634. KB_NP7, // 0x4F
  635. KB_NP8, // 0x50
  636. KB_NP9, // 0x51
  637. KB_NPSUB, // 0x52
  638. KB_NP4, // 0x53
  639. KB_NP5, // 0x54
  640. KB_NP6, // 0x55
  641. KB_NPADD, // 0x56
  642. KB_NP1, // 0x57
  643. KB_NP2, // 0x58
  644. KB_NP3, // 0x59
  645. KB_NP0, // 0x5A
  646. KB_NPDEL, // 0x5B
  647. KB_NONE, // 0x5C
  648. KB_NONE, // 0x5D
  649. KB_NONE, // 0x5E
  650. KB_F11, // 0x5F
  651. KB_F12, // 0x60
  652. KB_NONE, // 0x61
  653. KB_NONE, // 0x62
  654. KB_NONE, // 0x63
  655. KB_NONE, // 0x64
  656. KB_NONE, // 0x65
  657. KB_NONE, // 0x66
  658. KB_NONE, // 0x67
  659. KB_NPENTER, // 0x68
  660. KB_RCTRL, // 0x69
  661. KB_NPDIV, // 0x6A
  662. KB_NONE, // 0x6B
  663. KB_RALT, // 0x6C
  664. KB_NONE, // 0x6D
  665. KB_HOME, // 0x6E
  666. KB_UP, // 0x6F
  667. KB_PGUP, // 0x70
  668. KB_LEFT, // 0x71
  669. KB_RIGHT, // 0x72
  670. KB_END, // 0x73
  671. KB_DOWN, // 0x74
  672. KB_PGDN, // 0x75
  673. KB_INS, // 0x76
  674. KB_DEL, // 0x77
  675. KB_NONE, // 0x78
  676. KB_NONE, // 0x79
  677. KB_NONE, // 0x7A
  678. KB_NONE, // 0x7B
  679. KB_NONE, // 0x7C
  680. KB_NONE, // 0x7D
  681. KB_NONE, // 0x7E
  682. KB_PAUSE, // 0x7F
  683. KB_NONE, // 0x80
  684. KB_NONE, // 0x81
  685. KB_NONE, // 0x82
  686. KB_NONE, // 0x83
  687. KB_NONE, // 0x84
  688. KB_LWIN, // 0x85
  689. KB_RWIN, // 0x86
  690. KB_MENU, // 0x87
  691. KB_NONE, // 0x88
  692. KB_NONE, // 0x89
  693. KB_NONE, // 0x8A
  694. KB_NONE, // 0x8B
  695. KB_NONE, // 0x8C
  696. KB_NONE, // 0x8D
  697. KB_NONE, // 0x8E
  698. KB_NONE, // 0x8F
  699. };
  700. #endif
  701. static const KB_KEY VariableKeys[]= // keys that may change depending on layout
  702. {
  703. KB_OEM_102, // !! put this first on the list so it's processed last in REPA loop (to avoid selecting it unless necessary, because it's uncommon key) !!
  704. KB_TILDE,
  705. KB_0, KB_1, KB_2, KB_3, KB_4, KB_5, KB_6, KB_7, KB_8, KB_9,
  706. KB_SUB, KB_EQUAL,
  707. KB_Q, KB_W, KB_E, KB_R, KB_T, KB_Y, KB_U, KB_I, KB_O, KB_P, KB_LBR, KB_RBR, KB_BSLASH,
  708. KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, KB_SEMI, KB_APO,
  709. KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMMA, KB_DOT, KB_SLASH,
  710. };
  711. struct KeyData
  712. {
  713. Byte scan_code, cs;
  714. Char c[3];
  715. void add(Char c) {T.c[cs++]=CaseUp(c);} // add CaseUp so later when checking for characters we can just do >='A' && <='Z', use Up instead of Down because KB_A is 'A'
  716. };
  717. void Keyboard::setLayout()
  718. {
  719. REPAO(_qwerty)=KB_KEY(i);
  720. #if WINDOWS
  721. #if 1 && WINDOWS_OLD // this is better, but 'MapVirtualKey' is available only on WINDOWS_OLD
  722. FREPA(ScanCodeToQwertyKey)if(KB_KEY k=ScanCodeToQwertyKey[i])if(UInt vk=MapVirtualKey(i, MAPVK_VSC_TO_VK_EX))if(k!=vk)
  723. _qwerty[k]=KB_KEY(vk);
  724. #else
  725. #if WINDOWS_OLD
  726. LANG_TYPE lang=LANG_TYPE((UInt(UIntPtr(GetKeyboardLayout(0)))>>16)&0xFF); // LOWORD represents the language, while HIWORD represents the keyboard layout
  727. #elif WINDOWS_NEW
  728. LANG_TYPE lang=LanguageCode(Windows::Globalization::Language::CurrentInputMethodLanguageTag->Data());
  729. #endif
  730. switch(lang)
  731. {
  732. // conversion map was detected by changing to another keyboard layout in the OS, and observing what was received in WM_KEYDOWN while pressing keys
  733. case LANG_CROATIAN: // LANG_BOSNIAN, LANG_SERBIAN - QWERTZ
  734. {
  735. _qwerty[KB_Y ]=KB_Z;
  736. _qwerty[KB_Z ]=KB_Y;
  737. _qwerty[KB_SUB ]=KB_SLASH;
  738. _qwerty[KB_SLASH]=KB_SUB;
  739. }break;
  740. case LANG_CZECH: // QWERTZ
  741. {
  742. _qwerty[KB_Y ]=KB_Z;
  743. _qwerty[KB_Z ]=KB_Y;
  744. _qwerty[KB_SUB ]=KB_EQUAL;
  745. _qwerty[KB_EQUAL]=KB_SLASH;
  746. _qwerty[KB_SLASH]=KB_SUB;
  747. }break;
  748. case LANG_DANISH: // QWERTY
  749. {
  750. _qwerty[KB_TILDE ]=KB_BSLASH;
  751. _qwerty[KB_SUB ]=KB_EQUAL;
  752. _qwerty[KB_EQUAL ]=KB_LBR;
  753. _qwerty[KB_LBR ]=KB_RBR;
  754. _qwerty[KB_RBR ]=KB_SEMI;
  755. _qwerty[KB_BSLASH]=KB_SLASH;
  756. _qwerty[KB_SEMI ]=KB_TILDE;
  757. _qwerty[KB_SLASH ]=KB_SUB;
  758. }break;
  759. case LANG_DUTCH: // AZERTY
  760. {
  761. _qwerty[KB_Q ]=KB_A;
  762. _qwerty[KB_A ]=KB_Q;
  763. _qwerty[KB_W ]=KB_Z;
  764. _qwerty[KB_Z ]=KB_W;
  765. _qwerty[KB_SUB ]=KB_LBR;
  766. _qwerty[KB_EQUAL]=KB_SUB;
  767. _qwerty[KB_LBR ]=KB_RBR;
  768. _qwerty[KB_RBR ]=KB_SEMI;
  769. _qwerty[KB_SEMI ]=KB_M;
  770. _qwerty[KB_APO ]=KB_TILDE;
  771. _qwerty[KB_TILDE]=KB_APO;
  772. _qwerty[KB_M ]=KB_COMMA;
  773. _qwerty[KB_COMMA]=KB_DOT;
  774. _qwerty[KB_DOT ]=KB_SLASH;
  775. _qwerty[KB_SLASH]=KB_EQUAL;
  776. }break;
  777. case LANG_ESTONIAN: // QWERTY
  778. {
  779. _qwerty[KB_TILDE]=KB_APO;
  780. _qwerty[KB_LBR ]=KB_TILDE;
  781. _qwerty[KB_RBR ]=KB_LBR;
  782. _qwerty[KB_APO ]=KB_SLASH;
  783. _qwerty[KB_SLASH]=KB_RBR;
  784. }break;
  785. case LANG_FINNISH : // QWERTY
  786. case LANG_NORWEGIAN: // QWERTY
  787. case LANG_SWEDISH : // QWERTY
  788. {
  789. _qwerty[KB_TILDE ]=KB_BSLASH;
  790. _qwerty[KB_SUB ]=KB_EQUAL;
  791. _qwerty[KB_EQUAL ]=KB_LBR;
  792. _qwerty[KB_LBR ]=KB_RBR;
  793. _qwerty[KB_RBR ]=KB_SEMI;
  794. _qwerty[KB_BSLASH]=KB_SLASH;
  795. _qwerty[KB_SEMI ]=KB_TILDE;
  796. _qwerty[KB_SLASH ]=KB_SUB;
  797. }break;
  798. case LANG_FRENCH: // AZERTY
  799. {
  800. _qwerty[KB_Q ]=KB_A;
  801. _qwerty[KB_A ]=KB_Q;
  802. _qwerty[KB_W ]=KB_Z;
  803. _qwerty[KB_Z ]=KB_W;
  804. _qwerty[KB_SUB ]=KB_LBR;
  805. _qwerty[KB_LBR ]=KB_RBR;
  806. _qwerty[KB_RBR ]=KB_SEMI;
  807. _qwerty[KB_SEMI ]=KB_M;
  808. _qwerty[KB_APO ]=KB_TILDE;
  809. _qwerty[KB_TILDE]=KB_APO;
  810. _qwerty[KB_M ]=KB_COMMA;
  811. _qwerty[KB_COMMA]=KB_DOT;
  812. _qwerty[KB_DOT ]=KB_SLASH;
  813. _qwerty[KB_SLASH]=KB_KEY(223); _qwerty[223]=KB_NONE; // VK_OEM_8 was received in WM_KEYDOWN when pressing '/', need to disable _qwerty[VK_OEM_8] so reverse convert will work
  814. }break;
  815. case LANG_GERMAN: // QWERTZ
  816. {
  817. _qwerty[KB_Y ]=KB_Z;
  818. _qwerty[KB_Z ]=KB_Y;
  819. _qwerty[KB_SUB ]=KB_LBR;
  820. _qwerty[KB_EQUAL ]=KB_RBR;
  821. _qwerty[KB_LBR ]=KB_SEMI;
  822. _qwerty[KB_RBR ]=KB_EQUAL;
  823. _qwerty[KB_TILDE ]=KB_BACKSLASH;
  824. _qwerty[KB_BACKSLASH]=KB_SLASH;
  825. _qwerty[KB_SEMI ]=KB_TILDE;
  826. _qwerty[KB_SLASH ]=KB_SUB;
  827. }break;
  828. case LANG_HUNGARIAN: // QWERTZ
  829. {
  830. _qwerty[KB_Y ]=KB_Z;
  831. _qwerty[KB_Z ]=KB_Y;
  832. _qwerty[KB_TILDE]=KB_0;
  833. _qwerty[KB_0 ]=KB_TILDE;
  834. _qwerty[KB_SUB ]=KB_SLASH;
  835. _qwerty[KB_SLASH]=KB_SUB;
  836. }break;
  837. case LANG_ITALIAN: // QWERTY
  838. {
  839. _qwerty[KB_TILDE ]=KB_BSLASH;
  840. _qwerty[KB_SUB ]=KB_LBR;
  841. _qwerty[KB_EQUAL ]=KB_RBR;
  842. _qwerty[KB_LBR ]=KB_SEMI;
  843. _qwerty[KB_RBR ]=KB_EQUAL;
  844. _qwerty[KB_BSLASH]=KB_SLASH;
  845. _qwerty[KB_SEMI ]=KB_TILDE;
  846. _qwerty[KB_SLASH ]=KB_SUB;
  847. }break;
  848. case LANG_LUXEMBOURGISH: // QWERTZ
  849. {
  850. _qwerty[KB_Y ]=KB_Z;
  851. _qwerty[KB_Z ]=KB_Y;
  852. _qwerty[KB_TILDE]=KB_SLASH;
  853. _qwerty[KB_SUB ]=KB_LBR;
  854. _qwerty[KB_EQUAL]=KB_RBR;
  855. _qwerty[KB_LBR ]=KB_SEMI;
  856. _qwerty[KB_RBR ]=KB_TILDE;
  857. _qwerty[KB_SEMI ]=KB_APO;
  858. _qwerty[KB_APO ]=KB_BSLASH;
  859. _qwerty[KB_SLASH]=KB_SUB;
  860. }break;
  861. case LANG_PORTUGUESE: // QWERTY
  862. {
  863. _qwerty[KB_TILDE ]=KB_BSLASH;
  864. _qwerty[KB_SUB ]=KB_LBR;
  865. _qwerty[KB_EQUAL ]=KB_RBR;
  866. _qwerty[KB_LBR ]=KB_EQUAL;
  867. _qwerty[KB_RBR ]=KB_SEMI;
  868. _qwerty[KB_BSLASH]=KB_SLASH;
  869. _qwerty[KB_SEMI ]=KB_TILDE;
  870. _qwerty[KB_SLASH ]=KB_SUB;
  871. }break;
  872. case LANG_SPANISH: // QWERTY
  873. {
  874. _qwerty[KB_TILDE ]=KB_BSLASH;
  875. _qwerty[KB_SUB ]=KB_LBR;
  876. _qwerty[KB_EQUAL ]=KB_RBR;
  877. _qwerty[KB_LBR ]=KB_SEMI;
  878. _qwerty[KB_RBR ]=KB_EQUAL;
  879. _qwerty[KB_BSLASH]=KB_SLASH;
  880. _qwerty[KB_SEMI ]=KB_TILDE;
  881. _qwerty[KB_SLASH ]=KB_SUB;
  882. }break;
  883. case LANG_SLOVAK: // QWERTZ
  884. {
  885. _qwerty[KB_Y ]=KB_Z;
  886. _qwerty[KB_Z ]=KB_Y;
  887. _qwerty[KB_SUB ]=KB_SLASH;
  888. _qwerty[KB_EQUAL]=KB_KEY(223); _qwerty[223]=KB_NONE; // VK_OEM_8 was received in WM_KEYDOWN when pressing '-', need to disable _qwerty[VK_OEM_8] so reverse convert will work
  889. _qwerty[KB_SLASH]=KB_SUB;
  890. }break;
  891. case LANG_SLOVENIAN: // QWERTZ
  892. {
  893. _qwerty[KB_Y ]=KB_Z;
  894. _qwerty[KB_Z ]=KB_Y;
  895. _qwerty[KB_SUB ]=KB_SLASH;
  896. _qwerty[KB_SLASH]=KB_SUB;
  897. }break;
  898. case LANG_TURKISH: // QWERTY
  899. {
  900. _qwerty[KB_SUB ]=KB_KEY(223); _qwerty[223]=KB_NONE; // VK_OEM_8 was received in WM_KEYDOWN when pressing '-', need to disable _qwerty[VK_OEM_8] so reverse convert will work
  901. _qwerty[KB_EQUAL ]=KB_SUB;
  902. _qwerty[KB_BSLASH]=KB_COMMA;
  903. _qwerty[KB_COMMA ]=KB_SLASH;
  904. _qwerty[KB_DOT ]=KB_BSLASH;
  905. _qwerty[KB_SLASH ]=KB_DOT;
  906. }break;
  907. }
  908. #endif
  909. #elif MAC || LINUX
  910. Bool ok=false;
  911. #if MAC
  912. if(TISInputSourceRef key_layout=TISCopyCurrentKeyboardLayoutInputSource())
  913. {
  914. if(CFDataRef unicode_data=(CFDataRef)TISGetInputSourceProperty(key_layout, kTISPropertyUnicodeKeyLayoutData))
  915. if(UCKeyboardLayout *data=(UCKeyboardLayout*)CFDataGetBytePtr(unicode_data))
  916. {
  917. UInt keyboard_type=LMGetKbdType();
  918. #elif LINUX
  919. if(XDisplay)
  920. {
  921. #endif
  922. ok=true;
  923. Bool variable_key[256]; Zero(variable_key); REPA(VariableKeys)variable_key[VariableKeys[i]]=true;
  924. MemtN<KeyData, Elms(VariableKeys)> kds;
  925. FREPA(ScanCodeToKey)
  926. {
  927. KB_KEY qwerty_key=ScanCodeToQwertyKey[i];
  928. if(variable_key[qwerty_key]) // if this is a variable key (can change), then get what pressing it will give us (what characters), remember up to 3 combinations, default, with shift, and with right alt
  929. {
  930. KeyData kd; kd.cs=0;
  931. #if MAC
  932. UniCharCount len; UniChar s[8];
  933. UInt dead_key_state=0; if(UCKeyTranslate(data, i, kUCKeyActionDown, 0x00, keyboard_type, kUCKeyTranslateNoDeadKeysMask, &dead_key_state, Elms(s), &len, s)==noErr)if(len>0)kd.add(s[0]);
  934. dead_key_state=0; if(UCKeyTranslate(data, i, kUCKeyActionDown, 0x02, keyboard_type, kUCKeyTranslateNoDeadKeysMask, &dead_key_state, Elms(s), &len, s)==noErr)if(len>0)kd.add(s[0]); // with Shift
  935. dead_key_state=0; if(UCKeyTranslate(data, i, kUCKeyActionDown, 0x40, keyboard_type, kUCKeyTranslateNoDeadKeysMask, &dead_key_state, Elms(s), &len, s)==noErr)if(len>0)kd.add(s[0]); // with RightAlt
  936. #elif LINUX
  937. KeySym ks=XkbKeycodeToKeysym(XDisplay, KeyCode(i), 0, 0); if(ks!=NoSymbol)kd.add(Char(ks));
  938. ks=XkbKeycodeToKeysym(XDisplay, KeyCode(i), 0, 1); if(ks!=NoSymbol)kd.add(Char(ks)); // Shift
  939. #endif
  940. if(kd.cs){kd.scan_code=i; kds.New()=kd;} // if has any character mapping, then store into list to process later
  941. ScanCodeToKey[i]=KB_NONE; // set as unassigned
  942. }else ScanCodeToKey[i]=qwerty_key; // assign keys that are not variable
  943. }
  944. Bool (&unassigned_key)[256]=variable_key; // we can reuse this array, because only variable keys are unassigned
  945. // assign characters first, priority #1
  946. REPAD(ki, kds)
  947. {
  948. C KeyData &kd=kds[ki]; REPD(ci, kd.cs)
  949. {
  950. Char c=kd.c[ci]; ASSERT(KB_A=='A' && KB_Z=='Z'); if(c>='A' && c<='Z')if(unassigned_key[KB_KEY(c)]){unassigned_key[KB_KEY(c)]=false; ScanCodeToKey[kd.scan_code]=KB_KEY(c); kds.remove(ki); goto next_chr;}
  951. }
  952. next_chr:;
  953. }
  954. // assign digits, priority #2
  955. REPAD(ki, kds)
  956. {
  957. C KeyData &kd=kds[ki]; REPD(ci, kd.cs)
  958. {
  959. Char c=kd.c[ci]; ASSERT(KB_0=='0' && KB_9=='9'); if(c>='0' && c<='9')if(unassigned_key[KB_KEY(c)]){unassigned_key[KB_KEY(c)]=false; ScanCodeToKey[kd.scan_code]=KB_KEY(c); kds.remove(ki); goto next_dig;}
  960. }
  961. next_dig:;
  962. }
  963. // assign symbols, priority #3
  964. REPAD(ki, kds)
  965. {
  966. C KeyData &kd=kds[ki]; REPD(ci, kd.cs)
  967. {
  968. Char c=kd.c[ci]; if(!(c>='A' && c<='Z') && !(c>='0' && c<='9'))REPA(VariableKeys)
  969. {
  970. KB_KEY k=VariableKeys[i]; if(Kb._key_char[k]==c)
  971. {
  972. if(unassigned_key[k]){unassigned_key[k]=false; ScanCodeToKey[kd.scan_code]=k; kds.remove(ki); goto next_sym;}
  973. break;
  974. }
  975. }
  976. }
  977. next_sym:;
  978. }
  979. // assign with QWERTY mapping, priority #4
  980. REPAD(ki, kds)
  981. {
  982. C KeyData &kd=kds[ki];
  983. KB_KEY k=ScanCodeToQwertyKey[kd.scan_code]; if(unassigned_key[k]){unassigned_key[k]=false; ScanCodeToKey[kd.scan_code]=k; kds.remove(ki);}
  984. }
  985. // assign remaining to any key that was not assigned yet
  986. REPAD(ki, kds)
  987. {
  988. C KeyData &kd=kds[ki]; REPA(VariableKeys) // !! here use REPA to go from the back, to process KB_OEM_102 last (to avoid selecting it unless necessary, because it's uncommon key) !!
  989. {
  990. KB_KEY k=VariableKeys[i]; if(unassigned_key[k]){unassigned_key[k]=false; ScanCodeToKey[kd.scan_code]=k; break;}
  991. }
  992. }
  993. #if MAC
  994. }
  995. CFRelease(key_layout);
  996. }
  997. #elif LINUX
  998. }
  999. #endif
  1000. if(!ok)Copy(ScanCodeToKey, ScanCodeToQwertyKey); // if couldn't obtain keyboard layout, then set as QWERTY
  1001. REPAO(_qwerty)=KB_KEY(i); REPA(ScanCodeToKey)if(KB_KEY qwerty_key=ScanCodeToQwertyKey[i])if(KB_KEY key=ScanCodeToKey[i])_qwerty[qwerty_key]=key;
  1002. #endif
  1003. }
  1004. void Keyboard::swappedCtrlCmd (Bool swapped) {T._swapped_ctrl_cmd=swapped;}
  1005. void Keyboard::requestTextInput( ) {T._text_input =true ;}
  1006. void Keyboard::refreshTextInput( ) {T._refresh_visible =true ;}
  1007. void Keyboard:: setTextInput(C Str &text, Int start, Int end, Bool password)
  1008. {
  1009. #if ANDROID
  1010. if(Jni && ActivityClass && Activity)
  1011. if(JMethodID editTextSet=Jni->GetMethodID(ActivityClass, "editTextSet", "(Ljava/lang/String;IIZ)V"))
  1012. if(JString t=JString(Jni, text))
  1013. Jni->CallVoidMethod(Activity, editTextSet, t(), jint(start), jint(end), jboolean(password));
  1014. #endif
  1015. }
  1016. /******************************************************************************/
  1017. #if WINDOWS_OLD
  1018. Bool Keyboard::imm ( )C { HIMC imc=ImmGetContext (App.Hwnd()); if(imc)ImmReleaseContext(App.Hwnd(), imc); return imc!=null;}
  1019. void Keyboard::imm (Bool enable) {if(_imm!=enable){_imm=enable; ImmAssociateContext(App.Hwnd(), enable ? _imc : null);}}
  1020. Bool Keyboard::immNative( )C {return ImmGetOpenStatus(_imc)!=0;}
  1021. void Keyboard::immNative(Bool native)
  1022. {
  1023. ImmSetOpenStatus(_imc, native);
  1024. if(native)
  1025. {
  1026. LANG_TYPE lang=LANG_TYPE((UInt(UIntPtr(GetKeyboardLayout(0)))>>16)&0xFF); // LOWORD represents the language, while HIWORD represents the keyboard layout
  1027. if(lang==LANG_KOREAN)
  1028. {
  1029. DWORD c, s;
  1030. ImmGetConversionStatus(_imc, &c , &s);
  1031. ImmSetConversionStatus(_imc, c|1, s);
  1032. }
  1033. }
  1034. }
  1035. #else
  1036. Bool Keyboard::immNative( )C {return false;}
  1037. void Keyboard::immNative(Bool native) {}
  1038. #endif
  1039. /******************************************************************************/
  1040. void Keyboard::clear()
  1041. {
  1042. k.clear();
  1043. _last_key_scan_code=-1;
  1044. REPAO(_button)&=~BS_NOT_ON;
  1045. }
  1046. /******************************************************************************/
  1047. INLINE static void AddModifiers(Keyboard::Key &k)
  1048. {
  1049. if(Kb.anyCtrl ())k.flags|=Keyboard::Key::CTRL;
  1050. if(Kb.anyShift())k.flags|=Keyboard::Key::SHIFT;
  1051. if(Kb.anyAlt ())k.flags|=Keyboard::Key::ALT;
  1052. if(Kb.anyWin ())k.flags|=Keyboard::Key::WIN;
  1053. if(Kb.b(KB_LALT))k.flags|=Keyboard::Key::LALT;
  1054. }
  1055. void Keyboard::queue(Char chr, Int scan_code)
  1056. {
  1057. if(Unsigned(chr)>=32)
  1058. {
  1059. if(_last_key_scan_code==scan_code && scan_code>=0 && _key_buffer_len)
  1060. {
  1061. Key &last_key=_key_buffer[(_key_buffer_pos+_key_buffer_len-1)&0xFF];
  1062. if( !last_key.c){last_key.c=chr; return;}
  1063. }
  1064. Key k;
  1065. k.c=chr;
  1066. k.k=KB_NONE;
  1067. k.flags=Key::FIRST;
  1068. AddModifiers(k);
  1069. queue(k); _last_key_scan_code=scan_code;
  1070. }
  1071. }
  1072. void Keyboard::push(KB_KEY key, Int scan_code)
  1073. {
  1074. if(key)
  1075. {
  1076. Key k;
  1077. if(_button[key]&BS_ON) // repeated press
  1078. {
  1079. k.flags=0;
  1080. _button[key]|=BS_REPEAT;
  1081. }else // first press
  1082. {
  1083. k.flags=Key::FIRST;
  1084. _cur =key;
  1085. _button[key]|=BS_PUSHED|BS_ON;
  1086. if(_last==key && Time.appTime()-_last_t<=DoubleClickTime+Time.ad())
  1087. {
  1088. _button[key]|=BS_DOUBLE;
  1089. _last =-1;
  1090. }else
  1091. {
  1092. _last =key;
  1093. _last_t=Time.appTime();
  1094. }
  1095. InputCombo.add(InputButton(INPUT_KEYBOARD, key));
  1096. }
  1097. // !! set modifier flags after adjusting '_button' above !!
  1098. k.c='\0';
  1099. k.k=key;
  1100. AddModifiers(k);
  1101. queue(k); _last_key_scan_code=scan_code;
  1102. }
  1103. }
  1104. void Keyboard::release(KB_KEY key)
  1105. {
  1106. if(_button[key]&BS_ON)
  1107. {
  1108. if(_cur==key)_cur=-1;
  1109. FlagDisable(_button[key], BS_ON );
  1110. FlagEnable (_button[key], BS_RELEASED);
  1111. }
  1112. }
  1113. /******************************************************************************/
  1114. void Keyboard::update()
  1115. {
  1116. #if WINDOWS_OLD
  1117. imm(visibleWanted());
  1118. #if !KB_RAW_INPUT
  1119. if(App.active() && _did)
  1120. {
  1121. DIDEVICEOBJECTDATA didod[BUF_KEYS];
  1122. DWORD elms=BUF_KEYS, ret=_did->GetDeviceData(SIZE(DIDEVICEOBJECTDATA), didod, &elms, 0);
  1123. if(ret==DI_OK || ret==DI_BUFFEROVERFLOW)FREP(elms) // process in order
  1124. {
  1125. C DIDEVICEOBJECTDATA &d=didod[i];
  1126. Byte dik=d.dwOfs;
  1127. REPA(Keys) // process only special keys
  1128. {
  1129. C DIK &key=Keys[i]; if(key.dik==dik)
  1130. {
  1131. if(d.dwData&0x80)push(key.key);else release(key.key);
  1132. break;
  1133. }
  1134. }
  1135. }
  1136. if(ret!=DI_OK) // if we failed to catch entire input, then check most recent state
  1137. {
  1138. Byte dik[256]; if(!OK(_did->GetDeviceState(SIZE(dik), &dik))) // if failed
  1139. {
  1140. _did->Acquire(); // try to re-acquire if lost access for some reason
  1141. if(!OK(_did->GetDeviceState(SIZE(dik), &dik)))Zero(dik); // if still failed, then zero
  1142. }
  1143. REPA(Keys) // process only special keys
  1144. {
  1145. C DIK &key=Keys[i];
  1146. Bool on =(dik[key.dik] || ((key.key==KB_LCTRL) ? _special&1 : GetKeyState(key.key)<0)); // use a combination of both DirectInput and WinApi, because DirectInput loses state when changing exclusive mode (calling 'Unacquire' and 'Acquire'), however we can't use 'GetKeyState' for control (because it can be triggered by AltGr and may be disabled by Ctrl+Shift system shortcut)
  1147. if( on!=FlagTest(_button[key.key], BS_ON))
  1148. {
  1149. if(on)push(key.key);else release(key.key);
  1150. }
  1151. }
  1152. }else // if most recent state wasn't checked
  1153. if(_special&(2|4)) // if we're forcing Shifts, then check if any got released
  1154. {
  1155. if((_special&2) && GetKeyState(VK_LSHIFT)>=0){release(KB_LSHIFT); FlagDisable(_special, 2);}
  1156. if((_special&4) && GetKeyState(VK_RSHIFT)>=0){release(KB_RSHIFT); FlagDisable(_special, 4);}
  1157. }
  1158. }
  1159. #endif
  1160. #elif WINDOWS_NEW
  1161. if(App.active()) // need to manually check for certain keys
  1162. {
  1163. // Shifts may get stuck when 2 pressed at the same time
  1164. if(Kb.b(KB_LSHIFT) && !FlagTest((Int)App.Hwnd()->GetKeyState(Windows::System::VirtualKey:: LeftShift), (Int)Windows::UI::Core::CoreVirtualKeyStates::Down))Kb.release(KB_LSHIFT);
  1165. if(Kb.b(KB_RSHIFT) && !FlagTest((Int)App.Hwnd()->GetKeyState(Windows::System::VirtualKey::RightShift), (Int)Windows::UI::Core::CoreVirtualKeyStates::Down))Kb.release(KB_RSHIFT);
  1166. // not detected through system events
  1167. Bool print=FlagTest((Int)App.Hwnd()->GetKeyState(Windows::System::VirtualKey::Snapshot), (Int)Windows::UI::Core::CoreVirtualKeyStates::Down);
  1168. if( print!=b(KB_PRINT))
  1169. {
  1170. if(print)push(KB_PRINT, 0);else release(KB_PRINT);
  1171. }
  1172. }
  1173. #else
  1174. // keyboard state obtained externally in main loop
  1175. #endif
  1176. #if ANDROID
  1177. // display keyboard
  1178. Bool visible_wanted =visibleWanted();
  1179. if( visible_wanted!=_visible || _refresh_visible){SetKeyboardVisible(_visible=visible_wanted); _refresh_visible=false;}
  1180. UpdateKeyboardRect();
  1181. if(InputTextIs)
  1182. {
  1183. InputText temp; Bool pass=false; Int enters=0; // enter workaround
  1184. {
  1185. SyncLocker locker(InputTextLock);
  1186. if(Gui.kb())switch(Gui.kb()->type())
  1187. {
  1188. case GO_TEXTBOX:
  1189. {
  1190. // no need to apply Enter fix for 'TextBox', because we allow enters there as characters
  1191. TextBox &tb=Gui.kb()->asTextBox();
  1192. tb. setChanged(InputTextData.text);
  1193. tb.cursorChanged(InputTextData.cur.y);
  1194. tb._edit.sel =((InputTextData.cur.x==InputTextData.cur.y) ? -1 : InputTextData.cur.x);
  1195. _key_buffer_len=0; // this is a workaround for a bug in Google/Samsung Keyboard (but not SwiftKey) when Backspace key is triggered even though it shouldn't, when tapping Back key on the soft keyboard (when last character is space, or sometimes when just typed something), in that case 2 Back's are processed (one from EditText Java_com_esenthel_Native_text and one AINPUT_EVENT_TYPE_KEY), this code removes all queued keys to remove KB_BACK
  1196. }break;
  1197. case GO_TEXTLINE:
  1198. {
  1199. // some soft keyboards (GBoard) may generate enter keys as characters, this is a workaround for that
  1200. {
  1201. REPA(InputTextData.text)if(InputTextData.text[i]=='\n')
  1202. {
  1203. enters++; // increase enter counter
  1204. InputTextData.text.remove(i); // remove this character
  1205. if(InputTextData.cur.x>i)InputTextData.cur.x--; // adjust cursor
  1206. if(InputTextData.cur.y>i)InputTextData.cur.y--; // adjust cursor
  1207. }
  1208. }
  1209. TextLine &tl=Gui.kb()->asTextLine();
  1210. if(tl.setChanged(InputTextData.text) || !enters) // adjust cursor only if we've changed some text or didn't process the enter workaround (this is to avoid when pressing just enter key, changes the cursor position on GBoard)
  1211. {
  1212. tl.cursorChanged(InputTextData.cur.y);
  1213. tl._edit.sel =((InputTextData.cur.x==InputTextData.cur.y) ? -1 : InputTextData.cur.x);
  1214. }
  1215. _key_buffer_len=0; // this is a workaround for a bug in Google/Samsung Keyboard (but not SwiftKey) when Backspace key is triggered even though it shouldn't, when tapping Back key on the soft keyboard (when last character is space, or sometimes when just typed something), in that case 2 Back's are processed (one from EditText Java_com_esenthel_Native_text and one AINPUT_EVENT_TYPE_KEY), this code removes all queued keys to remove KB_BACK
  1216. pass=tl.password();
  1217. }break;
  1218. }
  1219. if(enters)Swap(temp, InputTextData);
  1220. InputTextIs=false;
  1221. }
  1222. if(enters) // call after we got out of sync lock in case this method would trigger 'Java_com_esenthel_Native_text' and introduce some sort of deadlock
  1223. {
  1224. const Int scan_code=0; REP(enters){push(KB_ENTER, scan_code); queue('\n', scan_code); release(KB_ENTER);} _last_key_scan_code=-1; // manually push and release enter keys, use any scan_code>=0 to force linking characters with keys
  1225. setTextInput(temp.text, temp.cur.x, temp.cur.y, pass);
  1226. }
  1227. }
  1228. #endif
  1229. // cursor visibility
  1230. if(_cur>=0){_hidden=false; _curh_t=0;}else
  1231. if((_curh_t+=Time.ad())>_curh_tn)
  1232. {
  1233. if(_curh_t>=2*_curh_tn)_curh_t =0;
  1234. else _curh_t-=_curh_tn;
  1235. _hidden^=1;
  1236. }
  1237. // misc
  1238. _ctrl =FlagTest(_button[KB_LCTRL ]|_button[KB_RCTRL ], BS_ON|BS_PUSHED);
  1239. _shift=FlagTest(_button[KB_LSHIFT]|_button[KB_RSHIFT], BS_ON|BS_PUSHED);
  1240. _alt =FlagTest(_button[KB_LALT ]|_button[KB_RALT ], BS_ON|BS_PUSHED);
  1241. _win =FlagTest(_button[KB_LWIN ]|_button[KB_RWIN ], BS_ON|BS_PUSHED);
  1242. #if ANDROID
  1243. KeySource=KEY_ANY; // re-allow input from all modes
  1244. #endif
  1245. if(b(KB_LALT) && !ctrl() && !win())
  1246. {
  1247. #if !WEB
  1248. if(!(App.flag&APP_NO_CLOSE ) && bp(KB_F4 ) && !shift()){App.close(); eat(KB_F4 );} // simulate Alt+F4 behavior on (this is also needed on Windows)
  1249. #endif
  1250. if( (App.flag&APP_FULL_TOGGLE) && bp(KB_ENTER) ){D.toggle(shift()); eat(KB_ENTER);} // process Alt+Enter to toggle full-screen
  1251. }
  1252. _text_input=false;
  1253. nextInQueue();
  1254. }
  1255. /******************************************************************************/
  1256. // EAT
  1257. /******************************************************************************
  1258. do not advance the buffers, so remaining keys will be processed in the next frame, instead just clear current. This is because the code that checked for next key press was already executed in this frame, and because in each frame buffers are automatically advanced, then the key would disappear on next advance before the codes can check for it
  1259. disable button flags (such as push), this is needed so when calling this method, it will prevent other Keyboard Shortcuts being triggered (those that are detected based on button flags)
  1260. /******************************************************************************/
  1261. void Keyboard::Key::eat()C
  1262. {
  1263. if(c==Kb.k.c)Kb.k.c='\0';
  1264. if(k==Kb.k.k)
  1265. {
  1266. FlagDisable(Kb._button[k], BS_NOT_ON); // do this first, while 'k' is still available (before clearing, in case this is 'Kb.k')
  1267. Kb.k.k=KB_NONE;
  1268. }
  1269. }
  1270. void Keyboard::eat(Char8 c) {eat(Char8To16Fast(c));}
  1271. void Keyboard::eat(Char c)
  1272. {
  1273. if(T.k(c) && c)
  1274. {
  1275. FlagDisable(_button[k.k], BS_NOT_ON); // do this first, while 'k' is still available
  1276. k.clear();
  1277. }
  1278. }
  1279. void Keyboard::eat(KB_KEY key)
  1280. {
  1281. FlagDisable(_button[key&0xFF], BS_NOT_ON); // always disable even if "T.k!=key"
  1282. if(T.k(key) && key)k.clear();
  1283. }
  1284. void Keyboard::eatKey()
  1285. {
  1286. FlagDisable(_button[k.k], BS_NOT_ON); // do this first, while 'k' is still available
  1287. k.clear();
  1288. }
  1289. void Keyboard::eat()
  1290. {
  1291. REPA(_button)FlagDisable(_button[i], BS_NOT_ON);
  1292. k.clear();
  1293. }
  1294. /******************************************************************************/
  1295. void Keyboard::nextInQueue()
  1296. {
  1297. if(!_key_buffer_len)k.clear();else
  1298. {
  1299. k=_key_buffer[_key_buffer_pos++];
  1300. _key_buffer_len-- ;
  1301. }
  1302. }
  1303. Keyboard::Key* Keyboard::nextKeyPtr()
  1304. {
  1305. return _key_buffer_len ? &_key_buffer[_key_buffer_pos] : null;
  1306. }
  1307. void Keyboard::nextKey()
  1308. {
  1309. //eatKey(); instead of calling this, just disable button state, because 'k' will be modified in 'nextInQueue'
  1310. FlagDisable(_button[k.k], BS_NOT_ON); // do this first, while 'k' is still available
  1311. nextInQueue();
  1312. }
  1313. void Keyboard::queue(C Key &key) // !! Warning: this doesn't check for 'key.k' and 'key.c' being invalid !!
  1314. {
  1315. if(_key_buffer_len<255)
  1316. {
  1317. _key_buffer[(_key_buffer_pos+_key_buffer_len)&0xFF]=key;
  1318. _key_buffer_len++;
  1319. _last_key_scan_code=-1;
  1320. }
  1321. }
  1322. /******************************************************************************/
  1323. void Keyboard::acquire(Bool on)
  1324. {
  1325. #if WINDOWS_OLD
  1326. #if !KB_RAW_INPUT
  1327. if(_did)
  1328. {
  1329. if(KEYBOARD_MODE==FOREGROUND) // we need to change acquire only if we're operating in Foreground mode
  1330. {
  1331. if(on)
  1332. {
  1333. _did->Acquire();
  1334. // upon activating the app, we need to check if some keys are pressed, for some reason 'GetDeviceState' will not return it until the next frame
  1335. if(GetKeyState(VK_LCONTROL)<0 && GetKeyState(VK_RMENU)>=0){push(KB_LCTRL ); _special|=1;} // we can enable LCTRL only if we know the right alt isn't pressed, because AltGr (Polish, Norwegian, .. keyboards) generates a false LCTRL
  1336. if(GetKeyState(VK_LSHIFT )<0 ){push(KB_LSHIFT); _special|=2;}
  1337. if(GetKeyState(VK_RSHIFT )<0 ){push(KB_RSHIFT); _special|=4;}
  1338. }else _did->Unacquire();
  1339. }else
  1340. {
  1341. // ignore recorded background input (this will remove keys from the DI buffer)
  1342. DIDEVICEOBJECTDATA didod[BUF_KEYS];
  1343. DWORD elms=BUF_KEYS, ret=_did->GetDeviceData(SIZE(DIDEVICEOBJECTDATA), didod, &elms, 0);
  1344. }
  1345. }
  1346. #endif
  1347. #endif
  1348. #if WINDOWS || LINUX
  1349. if(!on)REP(256)release(KB_KEY(i)); // need to manually release because Windows 'WM_*KEYUP', 'KeyUp' and Linux 'KeyRelease' aren't processed when app lost focus
  1350. #endif
  1351. }
  1352. void Keyboard::exclusive(Bool on)
  1353. {
  1354. #if WINDOWS_OLD
  1355. if(_exclusive!=on)
  1356. {
  1357. _exclusive=on; // set this first because it affects 'KEYBOARD_MODE'
  1358. #if KB_RAW_INPUT
  1359. if(App.hwnd())
  1360. {
  1361. RAWINPUTDEVICE rid[1];
  1362. rid[0].usUsagePage=0x01;
  1363. rid[0].usUsage =0x06; // keyboard
  1364. rid[0].dwFlags =((KEYBOARD_MODE==BACKGROUND) ? RIDEV_INPUTSINK : 0)|(_exclusive ? RIDEV_NOHOTKEYS : 0);
  1365. rid[0].hwndTarget =App.Hwnd();
  1366. RegisterRawInputDevices(rid, Elms(rid), SIZE(RAWINPUTDEVICE));
  1367. }
  1368. #else
  1369. if(_did)
  1370. {
  1371. _did->Unacquire(); // this also resets the 'GetDeviceState' of any currently pressed keys, they need to be pushed again to activate their state
  1372. _did->SetCooperativeLevel(App.Hwnd(), (_exclusive ? DISCL_NOWINKEY : 0)|DISCL_NONEXCLUSIVE|((KEYBOARD_MODE==FOREGROUND) ? DISCL_FOREGROUND : DISCL_BACKGROUND));
  1373. if(KEYBOARD_MODE==BACKGROUND || App.active())_did->Acquire(); // in background mode we always want the keyboard to be acquired, in foreground only if it's active
  1374. // because calling 'Unacquire' resets the state, we need to remember if some keys are pressed, other keys don't have to be remembered because they are processed using WM_*KEY*
  1375. _special=1*Kb.b(KB_LCTRL )
  1376. |2*Kb.b(KB_LSHIFT)
  1377. |4*Kb.b(KB_RSHIFT);
  1378. }
  1379. #endif
  1380. }
  1381. #endif
  1382. }
  1383. /******************************************************************************/
  1384. Bool Keyboard::hwAvailable()
  1385. {
  1386. #if WINDOWS_NEW
  1387. return Windows::Devices::Input::KeyboardCapabilities().KeyboardPresent>0;
  1388. #elif DESKTOP
  1389. return true;
  1390. #elif ANDROID
  1391. return (AndroidApp && AndroidApp->config) ? FlagTest(AConfiguration_getKeyboard(AndroidApp->config), (UInt)ACONFIGURATION_KEYBOARD_QWERTY) : false;
  1392. // HW connected: AConfiguration_getKeyboard->2, AConfiguration_getKeysHidden->1
  1393. // HW disconnected: AConfiguration_getKeyboard->1, AConfiguration_getKeysHidden->3
  1394. #else
  1395. return false;
  1396. #endif
  1397. }
  1398. Bool Keyboard::softCoverage(Rect &rect)
  1399. {
  1400. if(_visible && !hwAvailable())
  1401. {
  1402. rect=D.pixelToScreen(T._recti);
  1403. return true;
  1404. }
  1405. return false;
  1406. }
  1407. KB_KEY Keyboard::qwerty(KB_KEY qwerty)C {ASSERT(1<<(8*SIZE(qwerty))==ELMS(_qwerty)); return _qwerty[qwerty];}
  1408. Bool Keyboard::visibleWanted()C {return Gui.kb() && (Gui.kb()->type()==GO_TEXTLINE || Gui.kb()->type()==GO_TEXTBOX) || _text_input;}
  1409. /******************************************************************************/
  1410. // KEYBOARD SHORTCUT
  1411. /******************************************************************************/
  1412. #if APPLE
  1413. #define KBSC_CTRL_EX (KBSC_CTRL|KBSC_WIN_CTRL)
  1414. #define KBSC_WIN_EX (KBSC_WIN |KBSC_CTRL_CMD)
  1415. #else
  1416. #define KBSC_CTRL_EX (KBSC_CTRL|KBSC_CTRL_CMD)
  1417. #define KBSC_WIN_EX (KBSC_WIN |KBSC_WIN_CTRL)
  1418. #endif
  1419. inline Bool KbSc::testFlag()C
  1420. {
  1421. return FlagTest(flag, KBSC_CTRL_EX)==Kb.k.ctrl ()
  1422. && FlagTest(flag, KBSC_SHIFT )==Kb.k.shift()
  1423. && FlagTest(flag, KBSC_ALT )==Kb.k.alt ()
  1424. && FlagTest(flag, KBSC_WIN_EX )==Kb.k.win ()
  1425. && (flag& KBSC_REPEAT || Kb.k.first());
  1426. }
  1427. inline Bool KbSc::testFlagChar()C
  1428. {
  1429. return FlagTest(flag, KBSC_CTRL_EX)==Kb.k.ctrl ()
  1430. //&& FlagTest(flag, KBSC_SHIFT )==Kb.k.shift() shift is not checked, because for KBSC_CHAR we just specify the character being lower/upper case, and KBSC_SHIFT would mess this up
  1431. && FlagTest(flag, KBSC_ALT )==Kb.k.lalt () // only left Alt is checked, because right Alt may trigger accented characters
  1432. && FlagTest(flag, KBSC_WIN_EX )==Kb.k.win ();
  1433. }
  1434. Bool KbSc::pd()C
  1435. {
  1436. switch(mode)
  1437. {
  1438. case KBSC_CHAR: return Kb.k.c==index && testFlagChar();
  1439. case KBSC_KEY : return Kb.k.k==index && testFlag (); // must check either 'key' or 'bp', but not both, because 'key' is set to the first key queued in the buffer, if there are multiple keys then by default they will be processed one per frame, so if two keys were pressed, 2nd will be processed on the next frame, and in that case 'bp' for it is now false. We could check all keys in the buffer, however it's better to process keyboard shortcuts in order (for example if there's keyboard shortcuts: "Save" "Close" and user presses both very quickly in the same frame, we need to make sure that they are processed in correct order). 'key' was chosen instead of 'bp' to allow processing shortcuts in order
  1440. }
  1441. return false;
  1442. }
  1443. #if APPLE
  1444. #define WIN_TEXT "Cmd+" // Apple keyboards have "Cmd" key instead of "Win" key
  1445. #else
  1446. #define WIN_TEXT "Win+"
  1447. #endif
  1448. Str KbSc::asText()C
  1449. {
  1450. Str s; switch(mode)
  1451. {
  1452. case KBSC_CHAR: {Char c=index; if(flag&KBSC_CTRL_EX)s+="Ctrl+"; if(flag&KBSC_WIN_EX)s+=WIN_TEXT; if(CharFlag(c)&CHARF_UP )s+="Shift+"; if(flag&KBSC_ALT)s+="Alt+"; if(CChar8 *n=CharName(c))s+=n;else s+=CaseUp(c);} break;
  1453. case KBSC_KEY : { if(flag&KBSC_CTRL_EX)s+="Ctrl+"; if(flag&KBSC_WIN_EX)s+=WIN_TEXT; if( flag &KBSC_SHIFT)s+="Shift+"; if(flag&KBSC_ALT)s+="Alt+"; s+=Kb.keyName(KB_KEY(index)); } break;
  1454. }
  1455. return s;
  1456. }
  1457. void KbSc::eat()C
  1458. {
  1459. switch(mode)
  1460. {
  1461. case KBSC_CHAR: Kb.eat(Char (index)); break;
  1462. case KBSC_KEY : Kb.eat(KB_KEY(index)); break;
  1463. }
  1464. }
  1465. /******************************************************************************/
  1466. }
  1467. /******************************************************************************/
  1468. #if ANDROID
  1469. extern "C"
  1470. {
  1471. JNIEXPORT void JNICALL Java_com_esenthel_Native_text(JNIEnv *env, jclass clazz, jstring text, jint start, jint end)
  1472. {
  1473. JNI jni(env);
  1474. SyncLocker locker(InputTextLock);
  1475. InputTextData.text=jni(text);
  1476. InputTextData.cur .set(start, end);
  1477. InputTextIs=true;
  1478. }
  1479. JNIEXPORT void JNICALL Java_com_esenthel_Native_key(JNIEnv *env, jclass clazz, jint chr, jint key_code)
  1480. {
  1481. switch(KeySource)
  1482. {
  1483. case KEY_ANY : KeySource=KEY_JAVA; // !! no break on purpose !!
  1484. case KEY_JAVA: Kb.queue(Char(chr), key_code); break;
  1485. }
  1486. }
  1487. }
  1488. #endif
  1489. /******************************************************************************/