* TextBoxBase.cs: Use the new SuspendRecalc/ResumeRecalc methods
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / X11Keyboard.cs
blobda986c7de7812dd10e577e263c56175621c09164
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.
20 // Copyright (c) 2004 Novell, Inc.
22 // Authors:
23 // Jackson Harper (jackson@ximian.com)
29 // TODO:
30 // - dead chars are not translated properly
31 // - There is a lot of potential for optimmization in here
32 //
33 using System;
34 using System.Collections;
35 using System.Text;
36 using System.Globalization;
37 using System.Runtime.InteropServices;
39 namespace System.Windows.Forms {
41 internal class X11Keyboard {
43 private IntPtr display;
44 private IntPtr window;
45 private IntPtr xic;
46 private StringBuilder lookup_buffer;
47 private int min_keycode, max_keycode, keysyms_per_keycode, syms;
48 private int [] keyc2vkey = new int [256];
49 private int [] keyc2scan = new int [256];
50 private byte [] key_state_table = new byte [256];
51 private int lcid;
52 private bool num_state, cap_state;
53 private bool initialized;
55 private int NumLockMask;
56 private int AltGrMask;
58 public X11Keyboard (IntPtr display, IntPtr window)
60 this.display = display;
61 this.window = window;
62 lookup_buffer = new StringBuilder (24);
65 public void EnsureLayoutInitialized ()
67 if (initialized)
68 return;
70 KeyboardLayouts layouts = new KeyboardLayouts ();
71 KeyboardLayout layout = DetectLayout (layouts);
72 lcid = layout.Lcid;
73 CreateConversionArray (layouts, layout);
75 if (!XSupportsLocale ()) {
76 Console.Error.WriteLine ("X does not support your locale");
79 if (!XSetLocaleModifiers (String.Empty)) {
80 Console.Error.WriteLine ("Could not set X locale modifiers");
83 IntPtr xim = XOpenIM (display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
84 if (xim == IntPtr.Zero)
85 Console.Error.WriteLine ("Could not get XIM");
86 else
87 xic = CreateXic (window, xim);
89 initialized = true;
92 public Keys ModifierKeys {
93 get {
94 Keys keys = Keys.None;
95 if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0)
96 keys |= Keys.Shift;
97 if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0)
98 keys |= Keys.Control;
99 if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0)
100 keys |= Keys.Alt;
101 return keys;
105 public void FocusIn (IntPtr focus_window)
107 if (xic != IntPtr.Zero)
108 XSetICFocus (xic);
111 public void FocusOut (IntPtr focus_window)
113 if (xic != IntPtr.Zero)
114 XUnsetICFocus (xic);
117 public bool ResetKeyState(IntPtr hwnd, ref MSG msg) {
118 // FIXME - keep defining events/msg and return true until we've 'restored' all
119 // pending keypresses
120 if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) {
121 key_state_table [(int) VirtualKeys.VK_SHIFT] &= unchecked((byte)~0x80);
124 if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) {
125 key_state_table [(int) VirtualKeys.VK_CONTROL] &= unchecked((byte)~0x80);
128 if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0) {
129 key_state_table [(int) VirtualKeys.VK_MENU] &= unchecked((byte)~0x80);
131 return false;
134 public void KeyEvent (IntPtr hwnd, XEvent xevent, ref MSG msg)
136 EnsureLayoutInitialized ();
138 XKeySym keysym;
139 int ascii_chars;
141 IntPtr status = IntPtr.Zero;
142 ascii_chars = LookupString (ref xevent, 24, out keysym, out status);
144 if (((int) keysym >= (int) MiscKeys.XK_ISO_Lock &&
145 (int) keysym <= (int) MiscKeys.XK_ISO_Last_Group_Lock) ||
146 (int) keysym == (int) MiscKeys.XK_Mode_switch) {
147 UpdateKeyState (xevent);
148 return;
151 if ((xevent.KeyEvent.keycode >> 8) == 0x10)
152 xevent.KeyEvent.keycode = xevent.KeyEvent.keycode & 0xFF;
154 int event_time = (int)xevent.KeyEvent.time;
156 if (status == (IntPtr) 2) {
157 // Copy chars into a globally accessible var, i don't think
158 // this var is exposed anywhere though, so we can just ignore this
159 return;
162 AltGrMask = xevent.KeyEvent.state & (0x6000 | (int) KeyMasks.ModMasks);
163 int vkey = EventToVkey (xevent);
164 if (vkey == 0 && ascii_chars != 0) {
165 vkey = (int) VirtualKeys.VK_NONAME;
168 switch ((VirtualKeys) (vkey & 0xFF)) {
169 case VirtualKeys.VK_NUMLOCK:
170 GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.type, event_time);
171 break;
172 case VirtualKeys.VK_CAPITAL:
173 GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.type, event_time);
174 break;
175 default:
176 if (((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) == 0) != ((xevent.KeyEvent.state & NumLockMask) == 0)) {
177 GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, XEventName.KeyPress, event_time);
178 GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, XEventName.KeyRelease, event_time);
181 if (((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) == 0) != ((xevent.KeyEvent.state & (int) KeyMasks.LockMask) == 0)) {
182 GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, XEventName.KeyPress, event_time);
183 GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, XEventName.KeyRelease, event_time);
186 num_state = false;
187 cap_state = false;
189 int bscan = (keyc2scan [xevent.KeyEvent.keycode] & 0xFF);
190 KeybdEventFlags dw_flags = KeybdEventFlags.None;
191 if (xevent.type == XEventName.KeyRelease)
192 dw_flags |= KeybdEventFlags.KeyUp;
193 if ((vkey & 0x100) != 0)
194 dw_flags |= KeybdEventFlags.ExtendedKey;
195 msg = SendKeyboardInput ((VirtualKeys) (vkey & 0xFF), bscan, dw_flags, event_time);
196 msg.hwnd = hwnd;
197 break;
201 public bool TranslateMessage (ref MSG msg)
203 bool res = false;
205 if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
206 res = true;
208 if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN)
209 return res;
211 EnsureLayoutInitialized ();
213 string buffer;
214 Msg message;
215 int tu = ToUnicode ((int) msg.wParam, Control.HighOrder ((int) msg.lParam), out buffer);
216 switch (tu) {
217 case 1:
218 message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_CHAR : Msg.WM_SYSCHAR);
219 XplatUI.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
220 break;
221 case -1:
222 message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_DEADCHAR : Msg.WM_SYSDEADCHAR);
223 XplatUI.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
224 return true;
227 return res;
230 public int ToKeycode(int key)
232 int keycode = 0;
234 if (nonchar_vkey_key[key] > 0)
235 keycode = XKeysymToKeycode (display, nonchar_vkey_key[key]);
237 if (keycode == 0)
238 keycode = XKeysymToKeycode (display, key);
240 return keycode;
243 public int ToUnicode (int vkey, int scan, out string buffer)
245 if ((scan & 0x8000) != 0) {
246 buffer = String.Empty;
247 return 0;
250 XEvent e = new XEvent ();
251 e.AnyEvent.type = XEventName.KeyPress;
252 e.KeyEvent.display = display;
253 e.KeyEvent.keycode = 0;
254 e.KeyEvent.state = 0;
256 if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) {
257 e.KeyEvent.state |= (int) KeyMasks.ShiftMask;
260 if ((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) != 0) {
261 e.KeyEvent.state |= (int) KeyMasks.LockMask;
264 if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) {
265 e.KeyEvent.state |= (int) KeyMasks.ControlMask;
268 if ((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) != 0) {
269 e.KeyEvent.state |= NumLockMask;
272 e.KeyEvent.state |= AltGrMask;
274 for (int keyc = min_keycode; (keyc <= max_keycode) && (e.KeyEvent.keycode == 0); keyc++) {
275 // find keycode that could have generated this vkey
276 if ((keyc2vkey [keyc] & 0xFF) == vkey) {
277 // filter extended bit because it is not known
278 e.KeyEvent.keycode = keyc;
279 if ((EventToVkey (e) & 0xFF) != vkey) {
280 // Wrong one (ex: because of num,lock state)
281 e.KeyEvent.keycode = 0;
286 if ((vkey >= (int) VirtualKeys.VK_NUMPAD0) && (vkey <= (int) VirtualKeys.VK_NUMPAD9))
287 e.KeyEvent.keycode = XKeysymToKeycode (display, vkey - (int) VirtualKeys.VK_NUMPAD0 + (int) KeypadKeys.XK_KP_0);
289 if (vkey == (int) VirtualKeys.VK_DECIMAL)
290 e.KeyEvent.keycode = XKeysymToKeycode (display, (int) KeypadKeys.XK_KP_Decimal);
292 if (vkey == (int) VirtualKeys.VK_SEPARATOR)
293 e.KeyEvent.keycode = XKeysymToKeycode(display, (int) KeypadKeys.XK_KP_Separator);
295 if (e.KeyEvent.keycode == 0 && vkey != (int) VirtualKeys.VK_NONAME) {
296 // And I couldn't find the keycode so i returned the vkey and was like whatever
297 Console.Error.WriteLine ("unknown virtual key {0:X}", vkey);
298 buffer = String.Empty;
299 return vkey;
302 XKeySym t;
303 IntPtr status;
304 int res = LookupString (ref e, 24, out t, out status);
305 int keysym = (int) t;
307 buffer = String.Empty;
308 if (res == 0) {
309 int dead_char = MapDeadKeySym (keysym);
310 if (dead_char != 0) {
311 byte [] bytes = new byte [1];
312 bytes [0] = (byte) dead_char;
313 Encoding encoding = Encoding.GetEncoding (new CultureInfo (lcid).TextInfo.ANSICodePage);
314 buffer = new string (encoding.GetChars (bytes));
315 res = -1;
317 } else {
318 // Shift + arrow, shift + home, ....
319 // X returns a char for it, but windows doesn't
320 if (((e.KeyEvent.state & NumLockMask) == 0) && ((e.KeyEvent.state & (int) KeyMasks.ShiftMask) != 0) &&
321 (keysym >= (int) KeypadKeys.XK_KP_0) && (keysym <= (int) KeypadKeys.XK_KP_9)) {
322 buffer = String.Empty;
323 res = 0;
326 // CTRL + number, X returns chars, windows does not
327 if ((e.KeyEvent.state & (int) KeyMasks.ControlMask) != 0) {
328 if (((keysym >= 33) && (keysym < 'A')) || ((keysym > 'Z') && (keysym < 'a'))) {
329 buffer = String.Empty;
330 res = 0;
334 // X returns a char for delete key on extended keyboards, windows does not
335 if (keysym == (int) TtyKeys.XK_Delete) {
336 buffer = String.Empty;
337 res = 0;
340 if (res != 0) {
341 buffer = lookup_buffer.ToString ();
342 res = buffer.Length;
346 return res;
349 private MSG SendKeyboardInput (VirtualKeys vkey, int scan, KeybdEventFlags dw_flags, int time)
351 Msg message;
353 if ((dw_flags & KeybdEventFlags.KeyUp) != 0) {
354 bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
355 ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
356 key_state_table [(int) vkey] &= unchecked ((byte) ~0x80);
357 message = (sys_key ? Msg.WM_SYSKEYUP : Msg.WM_KEYUP);
358 } else {
359 if ((key_state_table [(int) vkey] & 0x80) == 0) {
360 key_state_table [(int) vkey] ^= 0x01;
362 key_state_table [(int) vkey] |= 0x80;
363 bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
364 ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
365 message = (sys_key ? Msg.WM_SYSKEYDOWN : Msg.WM_KEYDOWN);
368 MSG msg = new MSG ();
369 msg.message = message;
370 msg.wParam = (IntPtr) vkey;
371 if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0)
372 msg.lParam = new IntPtr (0x20000000);
373 else
374 msg.lParam = IntPtr.Zero;
376 return msg;
379 private void GenerateMessage (VirtualKeys vkey, int scan, XEventName type, int event_time)
381 bool state = (vkey == VirtualKeys.VK_NUMLOCK ? num_state : cap_state);
382 KeybdEventFlags up, down;
384 if (state) {
385 // The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
386 // don't treat it. It's from the same key press. Then the state goes to ON.
387 // And from there, a 'release' event will switch off the toggle key.
388 SetState (vkey, false);
389 } else {
390 down = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey : KeybdEventFlags.None);
391 up = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey :
392 KeybdEventFlags.None) | KeybdEventFlags.KeyUp;
393 if ((key_state_table [(int) vkey] & 0x1) != 0) { // it was on
394 if (type != XEventName.KeyPress) {
395 SendKeyboardInput (vkey, scan, down, event_time);
396 SendKeyboardInput (vkey, scan, up, event_time);
397 SetState (vkey, false);
398 key_state_table [(int) vkey] &= unchecked ((byte) ~0x01);
400 } else {
401 if (type == XEventName.KeyPress) {
402 SendKeyboardInput (vkey, scan, down, event_time);
403 SendKeyboardInput (vkey, scan, up, event_time);
404 SetState (vkey, true);
405 key_state_table [(int) vkey] |= 0x01;
411 private void UpdateKeyState (XEvent xevent)
413 int vkey = EventToVkey (xevent);
415 switch (xevent.type) {
416 case XEventName.KeyRelease:
417 key_state_table [vkey & 0xff] &= unchecked ((byte) ~0x80);
418 break;
419 case XEventName.KeyPress:
420 if ((key_state_table [vkey & 0xff] & 0x80) == 0) {
421 key_state_table [vkey & 0xff] ^= 0x01;
423 key_state_table [vkey & 0xff] |= 0x80;
424 break;
428 private void SetState (VirtualKeys key, bool state)
430 if (VirtualKeys.VK_NUMLOCK == key)
431 num_state = state;
432 else
433 cap_state = state;
436 public int EventToVkey (XEvent e)
438 EnsureLayoutInitialized ();
440 IntPtr status;
441 XKeySym ks;
443 LookupString (ref e, 0, out ks, out status);
444 int keysym = (int) ks;
446 if (((e.KeyEvent.state & NumLockMask) != 0) &&
447 (keysym == (int)KeypadKeys.XK_KP_Separator || keysym == (int)KeypadKeys.XK_KP_Decimal ||
448 (keysym >= (int)KeypadKeys.XK_KP_0 && keysym <= (int)KeypadKeys.XK_KP_9))) {
449 // Only the Keypad keys 0-9 and . send different keysyms
450 // depending on the NumLock state
451 return nonchar_key_vkey [keysym & 0xFF];
454 return keyc2vkey [e.KeyEvent.keycode];
457 private void CreateConversionArray (KeyboardLayouts layouts, KeyboardLayout layout)
459 XEvent e2 = new XEvent ();
460 uint keysym = 0;
461 int [] ckey = new int [] { 0, 0, 0, 0 };
463 e2.KeyEvent.display = display;
464 e2.KeyEvent.state = 0;
466 for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
467 int vkey = 0;
468 int scan = 0;
470 e2.KeyEvent.keycode = keyc;
471 XKeySym t;
473 IntPtr status;
474 LookupString (ref e2, 0, out t, out status);
476 keysym = (uint) t;
477 if (keysym != 0) {
478 if ((keysym >> 8) == 0xFF) {
479 vkey = nonchar_key_vkey [keysym & 0xFF];
480 scan = nonchar_key_scan [keysym & 0xFF];
481 // Set extended bit
482 if ((scan & 0x100) != 0)
483 vkey |= 0x100;
484 } else if (keysym == 0x20) { // spacebar
485 vkey = (int) VirtualKeys.VK_SPACE;
486 scan = 0x39;
487 } else {
488 // Search layout dependent scancodes
489 int maxlen = 0;
490 int maxval = -1;;
492 for (int i = 0; i < syms; i++) {
493 keysym = XKeycodeToKeysym (display, keyc, i);
494 if ((keysym < 0x800) && (keysym != ' '))
495 ckey [i] = (sbyte) (keysym & 0xFF);
496 else
497 ckey [i] = (sbyte) MapDeadKeySym ((int) keysym);
500 for (int keyn = 0; keyn < layout.Keys.Length; keyn++) {
501 int ml = Math.Min (layout.Keys [keyn].Length, 4);
502 int ok = -1;
503 for (int i = 0; (ok != 0) && (i < ml); i++) {
504 sbyte ck = (sbyte) layout.Keys [keyn][i];
505 if (ck != ckey [i])
506 ok = 0;
507 if ((ok != 0) || (i > maxlen)) {
508 maxlen = i;
509 maxval = keyn;
511 if (ok != 0)
512 break;
515 if (maxval >= 0) {
516 scan = layouts.scan_table [(int) layout.ScanIndex][maxval];
517 vkey = layouts.vkey_table [(int) layout.VKeyIndex][maxval];
522 keyc2vkey [e2.KeyEvent.keycode] = vkey;
523 keyc2scan [e2.KeyEvent.keycode] = scan;
529 private KeyboardLayout DetectLayout (KeyboardLayouts layouts)
531 XDisplayKeycodes (display, out min_keycode, out max_keycode);
532 IntPtr ksp = XGetKeyboardMapping (display, (byte) min_keycode,
533 max_keycode + 1 - min_keycode, out keysyms_per_keycode);
534 XplatUIX11.XFree (ksp);
536 syms = keysyms_per_keycode;
537 if (syms > 4) {
538 //Console.Error.WriteLine ("{0} keysymbols per a keycode is not supported, setting to 4", syms);
539 syms = 2;
542 IntPtr modmap_unmanaged;
543 XModifierKeymap xmk = new XModifierKeymap ();
545 modmap_unmanaged = XGetModifierMapping (display);
546 xmk = (XModifierKeymap) Marshal.PtrToStructure (modmap_unmanaged, typeof (XModifierKeymap));
548 int mmp = 0;
549 for (int i = 0; i < 8; i++) {
550 for (int j = 0; j < xmk.max_keypermod; j++, mmp++) {
551 byte b = Marshal.ReadByte (xmk.modifiermap, mmp);
552 if (b != 0) {
553 for (int k = 0; k < keysyms_per_keycode; k++) {
554 if ((int) XKeycodeToKeysym (display, b, k) == (int) MiscKeys.XK_Num_Lock)
555 NumLockMask = 1 << i;
560 XFreeModifiermap (modmap_unmanaged);
562 int [] ckey = new int [4];
563 KeyboardLayout layout = null;
564 int max_score = 0;
565 int max_seq = 0;
567 foreach (KeyboardLayout current in layouts.Layouts) {
568 int ok = 0;
569 int score = 0;
570 int match = 0;
571 int mismatch = 0;
572 int seq = 0;
573 int pkey = -1;
574 int key = min_keycode;
575 int i;
577 for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
578 for (i = 0; i < syms; i++) {
579 uint keysym = XKeycodeToKeysym (display, keyc, i);
581 if ((keysym < 0x800) && (keysym != ' ')) {
582 ckey [i] = (sbyte) (keysym & 0xFF);
583 } else {
584 ckey [i] = (sbyte) MapDeadKeySym ((int) keysym);
587 if (ckey [0] != 0) {
588 for (key = 0; key < current.Keys.Length; key++) {
589 int ml = Math.Min (syms, current.Keys [key].Length);
590 for (ok = 0, i = 0; (ok >= 0) && (i < ml); i++) {
591 sbyte ck = (sbyte) current.Keys [key][i];
592 if (ck != 0 && ck == ckey[i])
593 ok++;
594 if (ck != 0 && ck != ckey[i])
595 ok = -1;
597 if (ok > 0) {
598 score += ok;
599 break;
602 if (ok > 0) {
603 match++;
604 /* and how much the keycode order matches */
605 if (key > pkey)
606 seq++;
607 pkey = key;
608 } else {
609 /* print spaces instead of \0's */
610 mismatch++;
611 score -= syms;
616 if ((score > max_score) || ((score == max_score) && (seq > max_seq))) {
617 // best match so far
618 layout = current;
619 max_score = score;
620 max_seq = seq;
624 if (layout != null) {
625 return layout;
626 } else {
627 Console.WriteLine (Locale.GetText("Keyboard layout not recognized, using default layout: " +
628 layouts.Layouts [0].Name));
631 return layouts.Layouts [0];
634 // TODO
635 private int MapDeadKeySym (int val)
637 switch (val) {
638 case (int) DeadKeys.XK_dead_tilde :
639 case 0x1000FE7E : // Xfree's Dtilde
640 return '~';
641 case (int) DeadKeys.XK_dead_acute :
642 case 0x1000FE27 : // Xfree's XK_Dacute_accent
643 return 0xb4;
644 case (int) DeadKeys.XK_dead_circumflex:
645 case 0x1000FE5E : // Xfree's XK_.Dcircumflex_accent
646 return '^';
647 case (int) DeadKeys.XK_dead_grave :
648 case 0x1000FE60 : // Xfree's XK_.Dgrave_accent
649 return '`';
650 case (int) DeadKeys.XK_dead_diaeresis :
651 case 0x1000FE22 : // Xfree's XK_.Ddiaeresis
652 return 0xa8;
653 case (int) DeadKeys.XK_dead_cedilla :
654 return 0xb8;
655 case (int) DeadKeys.XK_dead_macron :
656 return '-';
657 case (int) DeadKeys.XK_dead_breve :
658 return 0xa2;
659 case (int) DeadKeys.XK_dead_abovedot :
660 return 0xff;
661 case (int) DeadKeys.XK_dead_abovering :
662 return '0';
663 case (int) DeadKeys.XK_dead_doubleacute :
664 return 0xbd;
665 case (int) DeadKeys.XK_dead_caron :
666 return 0xb7;
667 case (int) DeadKeys.XK_dead_ogonek :
668 return 0xb2;
671 return 0;
674 private IntPtr CreateXic (IntPtr window, IntPtr xim)
676 xic = XCreateIC (xim,
677 "inputStyle", XIMProperties.XIMPreeditNothing | XIMProperties.XIMStatusNothing,
678 "clientWindow", window,
679 "focusWindow", window,
680 IntPtr.Zero);
681 return xic;
684 private int LookupString (ref XEvent xevent, int len, out XKeySym keysym, out IntPtr status)
686 IntPtr keysym_res;
687 int res;
689 status = IntPtr.Zero;
690 lookup_buffer.Length = 0;
691 if (xic != IntPtr.Zero)
692 res = XmbLookupString (xic, ref xevent, lookup_buffer, len, out keysym_res, out status);
693 else
694 res = XLookupString (ref xevent, lookup_buffer, len, out keysym_res, IntPtr.Zero);
696 keysym = (XKeySym) keysym_res.ToInt32 ();
697 return res;
700 [DllImport ("libX11")]
701 private static extern IntPtr XOpenIM (IntPtr display, IntPtr rdb, IntPtr res_name, IntPtr res_class);
703 [DllImport ("libX11")]
704 private static extern IntPtr XCreateIC (IntPtr xim, string name, XIMProperties im_style, string name2, IntPtr value2, string name3, IntPtr value3, IntPtr terminator);
706 [DllImport ("libX11")]
707 private static extern void XSetICFocus (IntPtr xic);
709 [DllImport ("libX11")]
710 private static extern void XUnsetICFocus (IntPtr xic);
712 [DllImport ("libX11")]
713 private static extern bool XSupportsLocale ();
715 [DllImport ("libX11")]
716 private static extern bool XSetLocaleModifiers (string mods);
718 [DllImport ("libX11")]
719 internal extern static int XLookupString(ref XEvent xevent, StringBuilder buffer, int num_bytes, out IntPtr keysym, IntPtr status);
720 [DllImport ("libX11")]
721 internal extern static int XmbLookupString(IntPtr xic, ref XEvent xevent, StringBuilder buffer, int num_bytes, out IntPtr keysym, out IntPtr status);
723 internal static int XmbLookupString (IntPtr xic, ref XEvent xevent, StringBuilder buffer, int num_bytes, out XKeySym keysym, out IntPtr status) {
724 IntPtr keysym_ret;
725 int ret;
727 ret = XmbLookupString (xic, ref xevent, buffer, num_bytes, out keysym_ret, out status);
729 keysym = (XKeySym)keysym_ret.ToInt32();
731 return ret;
734 internal static int XLookupString (ref XEvent xevent, StringBuilder buffer, int num_bytes, out XKeySym keysym, IntPtr status) {
735 IntPtr keysym_ret;
736 int ret;
738 ret = XLookupString (ref xevent, buffer, num_bytes, out keysym_ret, status);
739 keysym = (XKeySym)keysym_ret.ToInt32();
741 return ret;
744 [DllImport ("libX11")]
745 private static extern IntPtr XGetKeyboardMapping (IntPtr display, byte first_keycode, int keycode_count,
746 out int keysyms_per_keycode_return);
748 [DllImport ("libX11")]
749 private static extern void XDisplayKeycodes (IntPtr display, out int min, out int max);
751 [DllImport ("libX11", EntryPoint="XKeycodeToKeysym")]
752 private static extern uint XKeycodeToKeysym (IntPtr display, int keycode, int index);
754 [DllImport ("libX11")]
755 private static extern int XKeysymToKeycode (IntPtr display, IntPtr keysym);
756 private static int XKeysymToKeycode (IntPtr display, int keysym) {
757 return XKeysymToKeycode(display, (IntPtr)keysym);
760 [DllImport ("libX11")]
761 internal extern static IntPtr XGetModifierMapping (IntPtr display);
763 [DllImport ("libX11")]
764 internal extern static int XFreeModifiermap (IntPtr modmap);
767 private readonly static int [] nonchar_key_vkey = new int []
769 /* unused */
770 0, 0, 0, 0, 0, 0, 0, 0, /* FF00 */
771 /* special keys */
772 (int) VirtualKeys.VK_BACK, (int) VirtualKeys.VK_TAB, 0, (int) VirtualKeys.VK_CLEAR, 0, (int) VirtualKeys.VK_RETURN, 0, 0, /* FF08 */
773 0, 0, 0, (int) VirtualKeys.VK_PAUSE, (int) VirtualKeys.VK_SCROLL, 0, 0, 0, /* FF10 */
774 0, 0, 0, (int) VirtualKeys.VK_ESCAPE, 0, 0, 0, 0, /* FF18 */
775 /* unused */
776 0, 0, 0, 0, 0, 0, 0, 0, /* FF20 */
777 0, 0, 0, 0, 0, 0, 0, 0, /* FF28 */
778 0, 0, 0, 0, 0, 0, 0, 0, /* FF30 */
779 0, 0, 0, 0, 0, 0, 0, 0, /* FF38 */
780 0, 0, 0, 0, 0, 0, 0, 0, /* FF40 */
781 0, 0, 0, 0, 0, 0, 0, 0, /* FF48 */
782 /* cursor keys */
783 (int) VirtualKeys.VK_HOME, (int) VirtualKeys.VK_LEFT, (int) VirtualKeys.VK_UP, (int) VirtualKeys.VK_RIGHT, /* FF50 */
784 (int) VirtualKeys.VK_DOWN, (int) VirtualKeys.VK_PRIOR, (int) VirtualKeys.VK_NEXT, (int) VirtualKeys.VK_END,
785 0, 0, 0, 0, 0, 0, 0, 0, /* FF58 */
786 /* misc keys */
787 (int) VirtualKeys.VK_SELECT, (int) VirtualKeys.VK_SNAPSHOT, (int) VirtualKeys.VK_EXECUTE, (int) VirtualKeys.VK_INSERT, 0, 0, 0, 0, /* FF60 */
788 (int) VirtualKeys.VK_CANCEL, (int) VirtualKeys.VK_HELP, (int) VirtualKeys.VK_CANCEL, (int) VirtualKeys.VK_CANCEL, 0, 0, 0, 0, /* FF68 */
789 0, 0, 0, 0, 0, 0, 0, 0, /* FF70 */
790 /* keypad keys */
791 0, 0, 0, 0, 0, 0, 0, (int) VirtualKeys.VK_NUMLOCK, /* FF78 */
792 0, 0, 0, 0, 0, 0, 0, 0, /* FF80 */
793 0, 0, 0, 0, 0, (int) VirtualKeys.VK_RETURN, 0, 0, /* FF88 */
794 0, 0, 0, 0, 0, (int) VirtualKeys.VK_HOME, (int) VirtualKeys.VK_LEFT, (int) VirtualKeys.VK_UP, /* FF90 */
795 (int) VirtualKeys.VK_RIGHT, (int) VirtualKeys.VK_DOWN, (int) VirtualKeys.VK_PRIOR, (int) VirtualKeys.VK_NEXT, /* FF98 */
796 (int) VirtualKeys.VK_END, 0, (int) VirtualKeys.VK_INSERT, (int) VirtualKeys.VK_DELETE,
797 0, 0, 0, 0, 0, 0, 0, 0, /* FFA0 */
798 0, 0, (int) VirtualKeys.VK_MULTIPLY, (int) VirtualKeys.VK_ADD, /* FFA8 */
799 (int) VirtualKeys.VK_SEPARATOR, (int) VirtualKeys.VK_SUBTRACT, (int) VirtualKeys.VK_DECIMAL, (int) VirtualKeys.VK_DIVIDE,
800 (int) VirtualKeys.VK_NUMPAD0, (int) VirtualKeys.VK_NUMPAD1, (int) VirtualKeys.VK_NUMPAD2, (int) VirtualKeys.VK_NUMPAD3, /* FFB0 */
801 (int) VirtualKeys.VK_NUMPAD4, (int) VirtualKeys.VK_NUMPAD5, (int) VirtualKeys.VK_NUMPAD6, (int) VirtualKeys.VK_NUMPAD7,
802 (int) VirtualKeys.VK_NUMPAD8, (int) VirtualKeys.VK_NUMPAD9, 0, 0, 0, 0, /* FFB8 */
803 /* function keys */
804 (int) VirtualKeys.VK_F1, (int) VirtualKeys.VK_F2,
805 (int) VirtualKeys.VK_F3, (int) VirtualKeys.VK_F4, (int) VirtualKeys.VK_F5, (int) VirtualKeys.VK_F6, (int) VirtualKeys.VK_F7, (int) VirtualKeys.VK_F8, (int) VirtualKeys.VK_F9, (int) VirtualKeys.VK_F10, /* FFC0 */
806 (int) VirtualKeys.VK_F11, (int) VirtualKeys.VK_F12, (int) VirtualKeys.VK_F13, (int) VirtualKeys.VK_F14, (int) VirtualKeys.VK_F15, (int) VirtualKeys.VK_F16, 0, 0, /* FFC8 */
807 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */
808 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */
809 /* modifier keys */
810 0, (int) VirtualKeys.VK_SHIFT, (int) VirtualKeys.VK_SHIFT, (int) VirtualKeys.VK_CONTROL, /* FFE0 */
811 (int) VirtualKeys.VK_CONTROL, (int) VirtualKeys.VK_CAPITAL, 0, (int) VirtualKeys.VK_MENU,
812 (int) VirtualKeys.VK_MENU, (int) VirtualKeys.VK_MENU, (int) VirtualKeys.VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */
813 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */
814 0, 0, 0, 0, 0, 0, 0, (int) VirtualKeys.VK_DELETE /* FFF8 */
817 private static readonly int [] nonchar_key_scan = new int []
819 /* unused */
820 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF00 */
821 /* special keys */
822 0x0E, 0x0F, 0x00, /*?*/ 0, 0x00, 0x1C, 0x00, 0x00, /* FF08 */
823 0x00, 0x00, 0x00, 0x45, 0x46, 0x00, 0x00, 0x00, /* FF10 */
824 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, /* FF18 */
825 /* unused */
826 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF20 */
827 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF28 */
828 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF30 */
829 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF38 */
830 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF40 */
831 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF48 */
832 /* cursor keys */
833 0x147, 0x14B, 0x148, 0x14D, 0x150, 0x149, 0x151, 0x14F, /* FF50 */
834 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF58 */
835 /* misc keys */
836 /*?*/ 0, 0x137, /*?*/ 0, 0x152, 0x00, 0x00, 0x00, 0x00, /* FF60 */
837 /*?*/ 0, /*?*/ 0, 0x38, 0x146, 0x00, 0x00, 0x00, 0x00, /* FF68 */
838 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF70 */
839 /* keypad keys */
840 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x138, 0x145, /* FF78 */
841 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FF80 */
842 0x00, 0x00, 0x00, 0x00, 0x00, 0x11C, 0x00, 0x00, /* FF88 */
843 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4B, 0x48, /* FF90 */
844 0x4D, 0x50, 0x49, 0x51, 0x4F, 0x4C, 0x52, 0x53, /* FF98 */
845 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFA0 */
846 0x00, 0x00, 0x37, 0x4E, /*?*/ 0, 0x4A, 0x53, 0x135, /* FFA8 */
847 0x52, 0x4F, 0x50, 0x51, 0x4B, 0x4C, 0x4D, 0x47, /* FFB0 */
848 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, /* FFB8 */
849 /* function keys */
850 0x3B, 0x3C,
851 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, /* FFC0 */
852 0x57, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFC8 */
853 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */
854 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */
855 /* modifier keys */
856 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */
857 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */
858 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */
859 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */
862 private readonly static int [] nonchar_vkey_key = new int []
864 0, 0, 0, 0, 0, /* 00-04 */
865 0, 0, 0, (int)XKeySym.XK_BackSpace, (int)XKeySym.XK_Tab, /* 05-09 */
866 0, 0, (int)XKeySym.XK_Clear, (int)XKeySym.XK_Return, 0, 0, /* 0A-0F */
867 (int)XKeySym.XK_Shift_L, (int)XKeySym.XK_Control_L, (int)XKeySym.XK_Menu, 0, (int)XKeySym.XK_Caps_Lock, /* 10-14 */
868 0, 0, 0, 0, 0, /* 15-19 */
869 0, 0, 0, 0, 0, 0, /* 1A-1F */
870 0, 0, 0, (int)XKeySym.XK_End, (int)XKeySym.XK_Home, /* 20-24 */
871 (int)XKeySym.XK_Left, (int)XKeySym.XK_Up, (int)XKeySym.XK_Right, (int)XKeySym.XK_Down, 0, /* 25-29 */
872 0, 0, 0, 0, 0, 0, /* 2A-2F */
873 0, 0, 0, 0, 0, /* 30-34 */
874 0, 0, 0, 0, 0, /* 35-39 */
875 0, 0, 0, 0, 0, 0, /* 3A-3F */
876 0, 0, 0, 0, 0, /* 40-44 */
877 0, 0, 0, 0, 0, /* 45-49 */
878 0, 0, 0, 0, 0, 0, /* 4A-4F */
879 0, 0, 0, 0, 0, /* 50-54 */
880 0, 0, 0, 0, 0, /* 55-59 */
881 0, (int)XKeySym.XK_Meta_L, (int)XKeySym.XK_Meta_R, 0, 0, 0, /* 5A-5F */
882 0, 0, 0, 0, 0, /* 60-64 */
883 0, 0, 0, 0, 0, /* 65-69 */
884 0, 0, 0, 0, 0, 0, /* 6A-6F */
885 0, 0, 0, 0, 0, /* 70-74 */
886 0, 0, 0, 0, 0, /* 75-79 */
887 0, 0, 0, 0, 0, 0, /* 7A-7F */
888 0, 0, 0, 0, 0, /* 80-84 */
889 0, 0, 0, 0, 0, /* 85-89 */
890 0, 0, 0, 0, 0, 0, /* 8A-8F */
891 0, 0, 0, 0, 0, /* 90-94 */
892 0, 0, 0, 0, 0, /* 95-99 */
893 0, 0, 0, 0, 0, 0, /* 9A-9F */
894 (int)XKeySym.XK_Shift_L, (int)XKeySym.XK_Shift_R, (int)XKeySym.XK_Control_L, (int)XKeySym.XK_Control_R, (int)XKeySym.XK_Alt_L, /* A0-A4 */
895 (int)XKeySym.XK_Alt_R, 0, 0, 0, 0, /* A5-A9 */
896 0, 0, 0, 0, 0, 0, /* AA-AF */
897 0, 0, 0, 0, 0, /* B0-B4 */
898 0, 0, 0, 0, 0, /* B5-B9 */
899 0, 0, 0, 0, 0, 0, /* BA-BF */
900 0, 0, 0, 0, 0, /* C0-C4 */
901 0, 0, 0, 0, 0, /* C5-C9 */
902 0, 0, 0, 0, 0, 0, /* CA-CF */
903 0, 0, 0, 0, 0, /* D0-D4 */
904 0, 0, 0, 0, 0, /* D5-D9 */
905 0, 0, 0, 0, 0, 0, /* DA-DF */
906 0, 0, 0, 0, 0, /* E0-E4 */
907 0, 0, 0, 0, 0, /* E5-E9 */
908 0, 0, 0, 0, 0, 0, /* EA-EF */
909 0, 0, 0, 0, 0, /* F0-F4 */
910 0, 0, 0, 0, 0, /* F5-F9 */
911 0, 0, 0, 0, 0, 0 /* FA-FF */