X11Keyboard.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. // Permission is hereby granted, free of charge, to any person obtaining
  2. // a copy of this software and associated documentation files (the
  3. // "Software"), to deal in the Software without restriction, including
  4. // without limitation the rights to use, copy, modify, merge, publish,
  5. // distribute, sublicense, and/or sell copies of the Software, and to
  6. // permit persons to whom the Software is furnished to do so, subject to
  7. // the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  13. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  16. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  17. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  18. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. //
  20. // Copyright (c) 2004 Novell, Inc.
  21. //
  22. // Authors:
  23. // Jackson Harper ([email protected])
  24. //
  25. //
  26. //
  27. // TODO:
  28. // - dead chars are not translated properly
  29. // - There is a lot of potential for optimmization in here
  30. //
  31. using System;
  32. using System.Text;
  33. using System.Runtime.InteropServices;
  34. namespace System.Windows.Forms {
  35. internal class X11Keyboard {
  36. private IntPtr display;
  37. private int min_keycode, max_keycode, keysyms_per_keycode, syms;
  38. private int [] keyc2vkey = new int [256];
  39. private int [] keyc2scan = new int [256];
  40. private byte [] key_state_table = new byte [256];
  41. private bool num_state, cap_state;
  42. private KeyboardLayout layout;
  43. // TODO
  44. private int NumLockMask;
  45. private int AltGrMask;
  46. public X11Keyboard (IntPtr display)
  47. {
  48. this.display = display;
  49. DetectLayout ();
  50. CreateConversionArray (layout);
  51. }
  52. public Keys ModifierKeys {
  53. get {
  54. Keys keys = Keys.None;
  55. if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0)
  56. keys |= Keys.Shift;
  57. if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0)
  58. keys |= Keys.Control;
  59. if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0)
  60. keys |= Keys.Alt;
  61. return keys;
  62. }
  63. }
  64. public void KeyEvent (IntPtr hwnd, XEvent xevent, ref MSG msg)
  65. {
  66. if ((xevent.KeyEvent.keycode >> 8) == 0x10)
  67. xevent.KeyEvent.keycode = xevent.KeyEvent.keycode & 0xFF;
  68. int event_time = (int)xevent.KeyEvent.time;
  69. int vkey = EventToVkey (xevent);
  70. if (vkey == 0)
  71. return;
  72. switch ((VirtualKeys) (vkey & 0xFF)) {
  73. case VirtualKeys.VK_NUMLOCK:
  74. GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.type, event_time);
  75. break;
  76. case VirtualKeys.VK_CAPITAL:
  77. GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.type, event_time);
  78. break;
  79. default:
  80. if (((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) == 0) != ((xevent.KeyEvent.state & NumLockMask) == 0)) {
  81. GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, XEventName.KeyPress, event_time);
  82. GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, XEventName.KeyRelease, event_time);
  83. }
  84. if (((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) == 0) != ((xevent.KeyEvent.state & (int) KeyMasks.LockMask) == 0)) {
  85. GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, XEventName.KeyPress, event_time);
  86. GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, XEventName.KeyRelease, event_time);
  87. }
  88. num_state = false;
  89. cap_state = false;
  90. int bscan = (keyc2scan [xevent.KeyEvent.keycode] & 0xFF);
  91. KeybdEventFlags dw_flags = KeybdEventFlags.None;
  92. if (xevent.type == XEventName.KeyRelease)
  93. dw_flags |= KeybdEventFlags.KeyUp;
  94. if ((vkey & 0x100) != 0)
  95. dw_flags |= KeybdEventFlags.ExtendedKey;
  96. msg = SendKeyboardInput ((VirtualKeys) (vkey & 0xFF), bscan, dw_flags, event_time);
  97. msg.hwnd = hwnd;
  98. break;
  99. }
  100. }
  101. public bool TranslateMessage (ref MSG msg)
  102. {
  103. bool res = false;
  104. if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
  105. res = true;
  106. if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN)
  107. return res;
  108. string buffer;
  109. Msg message;
  110. int tu = ToUnicode ((int) msg.wParam, Control.HighOrder ((int) msg.lParam), out buffer);
  111. switch (tu) {
  112. case 1:
  113. message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_CHAR : Msg.WM_SYSCHAR);
  114. XplatUIX11.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
  115. break;
  116. case -1:
  117. message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_DEADCHAR : Msg.WM_SYSDEADCHAR);
  118. XplatUIX11.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
  119. return true;
  120. }
  121. return res;
  122. }
  123. private int ToUnicode (int vkey, int scan, out string buffer)
  124. {
  125. if ((scan & 0x8000) != 0) {
  126. buffer = String.Empty;
  127. return 0;
  128. }
  129. XEvent e = new XEvent ();
  130. e.KeyEvent.display = display;
  131. e.KeyEvent.keycode = 0;
  132. e.KeyEvent.state = 0;
  133. if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) {
  134. e.KeyEvent.state |= (int) KeyMasks.ShiftMask;
  135. }
  136. if ((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) != 0) {
  137. e.KeyEvent.state |= (int) KeyMasks.LockMask;
  138. }
  139. if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) {
  140. e.KeyEvent.state |= (int) KeyMasks.ControlMask;
  141. }
  142. if ((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) != 0) {
  143. e.KeyEvent.state |= NumLockMask;
  144. }
  145. e.KeyEvent.state |= AltGrMask;
  146. for (int keyc = min_keycode; (keyc <= max_keycode) && (e.KeyEvent.keycode == 0); keyc++) {
  147. // find keycode that could have generated this vkey
  148. if ((keyc2vkey [keyc] & 0xFF) == vkey) {
  149. // filter extended bit because it is not known
  150. e.KeyEvent.keycode = keyc;
  151. if ((EventToVkey (e) & 0xFF) != vkey) {
  152. // Wrong one (ex: because of num,lock state)
  153. e.KeyEvent.keycode = 0;
  154. }
  155. }
  156. }
  157. if ((vkey >= (int) VirtualKeys.VK_NUMPAD0) && (vkey <= (int) VirtualKeys.VK_NUMPAD9))
  158. e.KeyEvent.keycode = XKeysymToKeycode (display, vkey - (int) VirtualKeys.VK_NUMPAD0 + (int) KeypadKeys.XK_KP_0);
  159. if (vkey == (int) VirtualKeys.VK_DECIMAL)
  160. e.KeyEvent.keycode = XKeysymToKeycode (display, (int) KeypadKeys.XK_KP_Decimal);
  161. if (e.KeyEvent.keycode == 0) {
  162. // And I couldn't find the keycode so i returned the vkey and was like whatever
  163. Console.Error.WriteLine ("unknown virtual key {0:X}", vkey);
  164. buffer = String.Empty;
  165. return vkey;
  166. }
  167. IntPtr buf = Marshal.AllocHGlobal (2);
  168. XKeySym t;
  169. int res = XLookupString (ref e, buf, 2, out t, IntPtr.Zero);
  170. int keysym = (int) t;
  171. buffer = String.Empty;
  172. if (res == 0) {
  173. int dead_char = MapDeadKeySym (keysym);
  174. if (dead_char != 0) {
  175. byte [] bytes = new byte [1];
  176. bytes [0] = (byte) dead_char;
  177. Encoding encoding = Encoding.GetEncoding (layout.CodePage);
  178. buffer = new string (encoding.GetChars (bytes));
  179. res = -1;
  180. }
  181. } else {
  182. // Shift + arrow, shift + home, ....
  183. // X returns a char for it, but windows doesn't
  184. if (((e.KeyEvent.state & NumLockMask) == 0) && ((e.KeyEvent.state & (int) KeyMasks.ShiftMask) != 0) &&
  185. (keysym >= (int) KeypadKeys.XK_KP_0) && (keysym <= (int) KeypadKeys.XK_KP_9)) {
  186. buffer = String.Empty;
  187. res = 0;
  188. }
  189. // CTRL + number, X returns chars, windows does not
  190. if ((e.KeyEvent.state & (int) KeyMasks.ControlMask) != 0) {
  191. if (((keysym >= 33) && (keysym < 'A')) || ((keysym > 'Z') && (keysym < 'a'))) {
  192. buffer = String.Empty;
  193. res = 0;
  194. }
  195. }
  196. // X returns a char for delete key on extended keyboards, windows does not
  197. if (keysym == (int) TtyKeys.XK_Delete) {
  198. buffer = String.Empty;
  199. res = 0;
  200. }
  201. if (res != 0) {
  202. byte [] bytes = new byte [2];
  203. bytes [0] = Marshal.ReadByte (buf);
  204. bytes [1] = Marshal.ReadByte (buf, 1);
  205. Encoding encoding = Encoding.GetEncoding (layout.CodePage);
  206. buffer = new string (encoding.GetChars (bytes));
  207. }
  208. }
  209. return res;
  210. }
  211. private MSG SendKeyboardInput (VirtualKeys vkey, int scan, KeybdEventFlags dw_flags, int time)
  212. {
  213. Msg message;
  214. if ((dw_flags & KeybdEventFlags.KeyUp) != 0) {
  215. bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
  216. ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
  217. key_state_table [(int) vkey] &= unchecked ((byte) ~0x80);
  218. message = (sys_key ? Msg.WM_SYSKEYUP : Msg.WM_KEYUP);
  219. } else {
  220. if ((key_state_table [(int) vkey] & 0x80) == 0) {
  221. key_state_table [(int) vkey] ^= 0x01;
  222. }
  223. key_state_table [(int) vkey] |= 0x80;
  224. bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
  225. ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
  226. message = (sys_key ? Msg.WM_SYSKEYDOWN : Msg.WM_KEYDOWN);
  227. }
  228. MSG msg = new MSG ();
  229. msg.message = message;
  230. msg.wParam = (IntPtr) vkey;
  231. msg.lParam = IntPtr.Zero;
  232. return msg;
  233. }
  234. private void GenerateMessage (VirtualKeys vkey, int scan, XEventName type, int event_time)
  235. {
  236. bool state = (vkey == VirtualKeys.VK_NUMLOCK ? num_state : cap_state);
  237. KeybdEventFlags up, down;
  238. if (state) {
  239. // The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
  240. // don't treat it. It's from the same key press. Then the state goes to ON.
  241. // And from there, a 'release' event will switch off the toggle key.
  242. SetState (vkey, false);
  243. } else {
  244. down = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey : KeybdEventFlags.None);
  245. up = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey :
  246. KeybdEventFlags.None) | KeybdEventFlags.KeyUp;
  247. if ((key_state_table [(int) vkey] & 0x1) != 0) { // it was on
  248. if (type != XEventName.KeyPress) {
  249. SendKeyboardInput (vkey, scan, down, event_time);
  250. SendKeyboardInput (vkey, scan, up, event_time);
  251. SetState (vkey, false);
  252. key_state_table [(int) vkey] &= unchecked ((byte) ~0x01);
  253. }
  254. } else {
  255. if (type == XEventName.KeyPress) {
  256. SendKeyboardInput (vkey, scan, down, event_time);
  257. SendKeyboardInput (vkey, scan, up, event_time);
  258. SetState (vkey, true);
  259. key_state_table [(int) vkey] |= 0x01;
  260. }
  261. }
  262. }
  263. }
  264. private void SetState (VirtualKeys key, bool state)
  265. {
  266. if (VirtualKeys.VK_NUMLOCK == key)
  267. num_state = state;
  268. else
  269. cap_state = state;
  270. }
  271. public int EventToVkey (XEvent e)
  272. {
  273. XKeySym ks;
  274. XLookupString (ref e, IntPtr.Zero, 0, out ks, IntPtr.Zero);
  275. int keysym = (int) ks;
  276. if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
  277. && ((e.KeyEvent.state & NumLockMask) !=0)) {
  278. // Only the Keypad keys 0-9 and . send different keysyms
  279. // depending on the NumLock state
  280. return KeyboardLayouts.nonchar_key_vkey [keysym & 0xFF];
  281. }
  282. return keyc2vkey [e.KeyEvent.keycode];
  283. }
  284. public void CreateConversionArray (KeyboardLayout layout)
  285. {
  286. XEvent e2 = new XEvent ();
  287. int keysym = 0;
  288. int [] ckey = new int [] { 0, 0, 0, 0 };
  289. e2.KeyEvent.display = display;
  290. e2.KeyEvent.state = 0;
  291. int oem_vkey = (int) VirtualKeys.VK_OEM_7;
  292. for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
  293. int vkey = 0;
  294. int scan = 0;
  295. e2.KeyEvent.keycode = keyc;
  296. XKeySym t;
  297. XLookupString (ref e2, IntPtr.Zero, 0, out t, IntPtr.Zero);
  298. keysym = (int) t;
  299. if (keysym != 0) {
  300. if ((keysym >> 8) == 0xFF) {
  301. vkey = KeyboardLayouts.nonchar_key_vkey [keysym & 0xFF];
  302. scan = KeyboardLayouts.nonchar_key_scan [keysym & 0xFF];
  303. // Set extended bit
  304. if ((scan & 0x100) != 0)
  305. vkey |= 0x100;
  306. } else if (keysym == 0x20) { // spacebar
  307. vkey = (int) VirtualKeys.VK_SPACE;
  308. scan = 0x39;
  309. } else {
  310. // Search layout dependent scancodes
  311. int maxlen = 0;
  312. int maxval = -1;;
  313. int ok;
  314. for (int i = 0; i < syms; i++) {
  315. keysym = (int) XKeycodeToKeysym (display, keyc, i);
  316. if ((keysym < 0x800) && (keysym != ' '))
  317. ckey [i] = keysym & 0xFF;
  318. else
  319. ckey [i] = MapDeadKeySym (keysym);
  320. }
  321. for (int keyn = 0; keyn < layout.Key.Length; keyn++) {
  322. int i = 0;
  323. int ml = (layout.Key [keyn].Length > 4 ? 4 : layout.Key [keyn].Length);
  324. for (ok = layout.Key [keyn][i]; (ok != 0) && (i < ml); i++) {
  325. if (layout.Key [keyn][i] != ckey [i])
  326. ok = 0;
  327. if ((ok != 0) || (i > maxlen)) {
  328. maxlen = i;
  329. maxval = keyn;
  330. }
  331. if (ok != 0)
  332. break;
  333. }
  334. }
  335. if (maxval >= 0) {
  336. scan = layout.Scan [maxval];
  337. vkey = (int) layout.VKey [maxval];
  338. }
  339. }
  340. for (int i = 0; (i < keysyms_per_keycode) && (vkey == 0); i++) {
  341. keysym = (int) XLookupKeysym (ref e2, i);
  342. if ((keysym >= (int) VirtualKeys.VK_0 && keysym <= (int) VirtualKeys.VK_9) ||
  343. (keysym >= (int) VirtualKeys.VK_A && keysym <= (int) VirtualKeys.VK_Z)) {
  344. vkey = keysym;
  345. }
  346. }
  347. for (int i = 0; (i < keysyms_per_keycode) && (vkey != 0); i++) {
  348. keysym = (int) XLookupKeysym (ref e2, i);
  349. switch ((char) keysym) {
  350. case ';':
  351. vkey = (int) VirtualKeys.VK_OEM_1;
  352. break;
  353. case '/':
  354. vkey = (int) VirtualKeys.VK_OEM_2;
  355. break;
  356. case '`':
  357. vkey = (int) VirtualKeys.VK_OEM_3;
  358. break;
  359. case '[':
  360. vkey = (int) VirtualKeys.VK_OEM_4;
  361. break;
  362. case '\\':
  363. vkey = (int) VirtualKeys.VK_OEM_5;
  364. break;
  365. case ']':
  366. vkey = (int) VirtualKeys.VK_OEM_6;
  367. break;
  368. case '\'':
  369. vkey = (int) VirtualKeys.VK_OEM_7;
  370. break;
  371. case ',':
  372. vkey = (int) VirtualKeys.VK_OEM_COMMA;
  373. break;
  374. case '.':
  375. vkey = (int) VirtualKeys.VK_OEM_PERIOD;
  376. break;
  377. case '-':
  378. vkey = (int) VirtualKeys.VK_OEM_MINUS;
  379. break;
  380. case '+':
  381. vkey = (int) VirtualKeys.VK_OEM_PLUS;
  382. break;
  383. }
  384. }
  385. if (vkey == 0) {
  386. switch (++oem_vkey) {
  387. case 0xc1:
  388. oem_vkey = 0xDB;
  389. break;
  390. case 0xE5:
  391. oem_vkey = 0xE9;
  392. break;
  393. case 0xF6:
  394. oem_vkey = 0xF5;
  395. break;
  396. }
  397. vkey = oem_vkey;
  398. }
  399. }
  400. keyc2vkey [e2.KeyEvent.keycode] = vkey;
  401. keyc2scan [e2.KeyEvent.keycode] = scan;
  402. }
  403. }
  404. public void DetectLayout ()
  405. {
  406. XDisplayKeycodes (display, out min_keycode, out max_keycode);
  407. IntPtr ksp = XGetKeyboardMapping (display, (byte) min_keycode,
  408. max_keycode + 1 - min_keycode, out keysyms_per_keycode);
  409. XplatUIX11.XFree (ksp);
  410. syms = keysyms_per_keycode;
  411. if (syms > 4) {
  412. Console.Error.WriteLine ("{0} keysymbols per a keycode is not supported, setting to 4", syms);
  413. syms = 2;
  414. }
  415. IntPtr modmap_unmanaged;
  416. XModifierKeymap xmk = new XModifierKeymap ();
  417. modmap_unmanaged = XGetModifierMapping (display);
  418. xmk = (XModifierKeymap) Marshal.PtrToStructure (modmap_unmanaged, typeof (XModifierKeymap));
  419. int mmp = 0;
  420. for (int i = 0; i < 8; i++) {
  421. for (int j = 0; j < xmk.max_keypermod; j++, mmp++) {
  422. byte b = Marshal.ReadByte (xmk.modifiermap, mmp);
  423. if (b != 0) {
  424. for (int k = 0; k < keysyms_per_keycode; k++) {
  425. if ((int) XKeycodeToKeysym (display, b, k) == (int) MiscKeys.XK_Num_Lock)
  426. NumLockMask = 1 << i;
  427. }
  428. }
  429. }
  430. }
  431. XFreeModifiermap (modmap_unmanaged);
  432. int [] ckey = new int [4];
  433. KeyboardLayout layout = null;
  434. int max_score = 0;
  435. int max_seq = 0;
  436. foreach (KeyboardLayout current in KeyboardLayouts.Layouts) {
  437. int ok = 0;
  438. int score = 0;
  439. int match = 0;
  440. int seq = 0;
  441. int pkey = -1;
  442. int key = min_keycode;
  443. for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
  444. for (int i = 0; i < syms; i++) {
  445. int keysym = (int) XKeycodeToKeysym (display, keyc, i);
  446. if ((keysym != 0xFF1B) && (keysym < 0x800) && (keysym != ' ')) {
  447. ckey [i] = keysym & 0xFF;
  448. } else {
  449. ckey [i] = MapDeadKeySym (keysym);
  450. }
  451. }
  452. if (ckey [0] != 0) {
  453. for (key = 0; key < current.Key.Length; key++) {
  454. ok = 0;
  455. int ml = (current.Key [key].Length > syms ? syms : current.Key [key].Length);
  456. for (int i = 0; (ok >= 0) && (i < ml); i++) {
  457. if (ckey [i] != 0 && current.Key [key][i] == (char) ckey [i]) {
  458. ok++;
  459. }
  460. if (ckey [i] != 0 && current.Key [key][i] != (char) ckey [i])
  461. ok = -1;
  462. }
  463. if (ok >= 0) {
  464. score += ok;
  465. break;
  466. }
  467. }
  468. if (ok > 0) {
  469. match++;
  470. if (key > pkey)
  471. seq++;
  472. pkey = key;
  473. } else {
  474. score -= syms;
  475. }
  476. }
  477. }
  478. if ((score > max_score) || ((score == max_score) && (seq > max_seq))) {
  479. // best match so far
  480. layout = current;
  481. max_score = score;
  482. max_seq = seq;
  483. }
  484. }
  485. if (layout != null)
  486. Console.WriteLine ("done detecting keyboard: " + layout.Comment);
  487. else
  488. Console.WriteLine ("no keyboard detected");
  489. this.layout = layout;
  490. }
  491. // TODO
  492. private int MapDeadKeySym (int val)
  493. {
  494. switch (val) {
  495. case (int) DeadKeys.XK_dead_tilde :
  496. case 0x1000FE7E : // Xfree's Dtilde
  497. return '~';
  498. case (int) DeadKeys.XK_dead_acute :
  499. case 0x1000FE27 : // Xfree's XK_Dacute_accent
  500. return 0xb4;
  501. case (int) DeadKeys.XK_dead_circumflex:
  502. case 0x1000FE5E : // Xfree's XK_.Dcircumflex_accent
  503. return '^';
  504. case (int) DeadKeys.XK_dead_grave :
  505. case 0x1000FE60 : // Xfree's XK_.Dgrave_accent
  506. return '`';
  507. case (int) DeadKeys.XK_dead_diaeresis :
  508. case 0x1000FE22 : // Xfree's XK_.Ddiaeresis
  509. return 0xa8;
  510. case (int) DeadKeys.XK_dead_cedilla :
  511. return 0xb8;
  512. case (int) DeadKeys.XK_dead_macron :
  513. return '-';
  514. case (int) DeadKeys.XK_dead_breve :
  515. return 0xa2;
  516. case (int) DeadKeys.XK_dead_abovedot :
  517. return 0xff;
  518. case (int) DeadKeys.XK_dead_abovering :
  519. return '0';
  520. case (int) DeadKeys.XK_dead_doubleacute :
  521. return 0xbd;
  522. case (int) DeadKeys.XK_dead_caron :
  523. return 0xb7;
  524. case (int) DeadKeys.XK_dead_ogonek :
  525. return 0xb2;
  526. }
  527. return 0;
  528. }
  529. [DllImport ("libX11")]
  530. internal extern static int XLookupString(ref XEvent xevent, IntPtr buffer,
  531. int num_bytes, out XKeySym keysym, IntPtr status);
  532. [DllImport ("libX11")]
  533. private static extern XKeySym XLookupKeysym (ref XEvent xevent, int index);
  534. [DllImport ("libX11")]
  535. private static extern IntPtr XGetKeyboardMapping (IntPtr display, byte first_keycode, int keycode_count,
  536. out int keysyms_per_keycode_return);
  537. [DllImport ("libX11")]
  538. private static extern void XDisplayKeycodes (IntPtr display, out int min, out int max);
  539. [DllImport ("libX11")]
  540. private static extern XKeySym XKeycodeToKeysym (IntPtr display, int keycode, int index);
  541. [DllImport ("libX11")]
  542. private static extern int XKeysymToKeycode (IntPtr display, int keysym);
  543. [DllImport ("libX11")]
  544. internal extern static IntPtr XGetModifierMapping (IntPtr display);
  545. [DllImport ("libX11")]
  546. internal extern static int XFreeModifiermap (IntPtr modmap);
  547. }
  548. }