* TreeView.cs: Don't draw the selected node when we lose
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / X11Keyboard.cs
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 (jackson@ximian.com)
24 //
25 //
26
27
28 //
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.Text;
35 using System.Runtime.InteropServices;
36
37 namespace System.Windows.Forms {
38
39         internal class X11Keyboard {
40
41                 private IntPtr display;
42                 private int min_keycode, max_keycode, keysyms_per_keycode, syms;
43                 private int [] keyc2vkey = new int [256];
44                 private int [] keyc2scan = new int [256];
45                 private byte [] key_state_table = new byte [256];
46                 private bool num_state, cap_state;
47                 private KeyboardLayout layout = KeyboardLayouts.Layouts [0];
48
49                 // TODO
50                 private int NumLockMask;
51                 private int AltGrMask;
52                 
53                 public X11Keyboard (IntPtr display)
54                 {
55                         this.display = display;
56                         DetectLayout ();
57                         CreateConversionArray (layout);
58                 }
59
60                 public Keys ModifierKeys {
61                         get {
62                                 Keys keys = Keys.None;
63                                 if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0)
64                                         keys |= Keys.Shift;
65                                 if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0)
66                                         keys |= Keys.Control;
67                                 if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0)
68                                         keys |= Keys.Alt;
69                                 return keys;
70                         }
71                 }
72
73                 public void KeyEvent (IntPtr hwnd, XEvent xevent, ref MSG msg)
74                 {
75                         XKeySym keysym;
76
77                         XLookupString (ref xevent, IntPtr.Zero, 0, out keysym, IntPtr.Zero);
78                         if (((int) keysym >= (int) MiscKeys.XK_ISO_Lock && 
79                                 (int) keysym <= (int) MiscKeys.XK_ISO_Last_Group_Lock) ||
80                                 (int) keysym == (int) MiscKeys.XK_Mode_switch) {
81                                 UpdateKeyState (xevent);
82                                 return;
83                         }
84
85                         if ((xevent.KeyEvent.keycode >> 8) == 0x10)
86                                 xevent.KeyEvent.keycode = xevent.KeyEvent.keycode & 0xFF;
87
88                         int event_time = (int)xevent.KeyEvent.time;
89
90                         AltGrMask = xevent.KeyEvent.state & (0x6000 | (int) KeyMasks.ModMasks);
91                         int vkey = EventToVkey (xevent);
92                         if (vkey == 0)
93                                 return;
94
95                         switch ((VirtualKeys) (vkey & 0xFF)) {
96                         case VirtualKeys.VK_NUMLOCK:
97                                 GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.type, event_time);
98                                 break;
99                         case VirtualKeys.VK_CAPITAL:
100                                 GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.type, event_time);
101                                 break;
102                         default:
103
104                                 if (((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) == 0) != ((xevent.KeyEvent.state & NumLockMask) == 0)) {
105                                         GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, XEventName.KeyPress, event_time);
106                                         GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, XEventName.KeyRelease, event_time);
107                                 }
108
109                                 if (((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) == 0) != ((xevent.KeyEvent.state & (int) KeyMasks.LockMask) == 0)) {
110                                         GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, XEventName.KeyPress, event_time);
111                                         GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, XEventName.KeyRelease, event_time);
112                                 }
113
114                                 num_state = false;
115                                 cap_state = false;
116
117                                 int bscan = (keyc2scan [xevent.KeyEvent.keycode] & 0xFF);
118                                 KeybdEventFlags dw_flags = KeybdEventFlags.None;
119                                 if (xevent.type == XEventName.KeyRelease)
120                                         dw_flags |= KeybdEventFlags.KeyUp;
121                                 if ((vkey & 0x100) != 0)
122                                         dw_flags |= KeybdEventFlags.ExtendedKey;
123                                 msg = SendKeyboardInput ((VirtualKeys) (vkey & 0xFF), bscan, dw_flags, event_time);
124                                 msg.hwnd = hwnd;
125                                 break;
126                         }
127                 }
128
129                 public bool TranslateMessage (ref MSG msg)
130                 {
131                         bool res = false;
132
133                         if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
134                                 res = true;
135
136                         if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN)
137                                 return res;
138
139                         string buffer;
140                         Msg message;
141
142                         int tu = ToUnicode ((int) msg.wParam, Control.HighOrder ((int) msg.lParam), out buffer);
143                         switch (tu) {
144                         case 1:
145                                 message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_CHAR : Msg.WM_SYSCHAR);
146                                 XplatUIX11.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
147                                 break;
148                         case -1:
149                                 message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_DEADCHAR : Msg.WM_SYSDEADCHAR);
150                                 XplatUIX11.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
151                                 return true;
152                         }
153                         
154                         return res;
155                 }
156
157                 private int ToUnicode (int vkey, int scan, out string buffer)
158                 {
159                         if ((scan & 0x8000) != 0) {
160                                 buffer = String.Empty;
161                                 return 0;
162                         }
163
164                         XEvent e = new XEvent ();
165                         e.KeyEvent.display = display;
166                         e.KeyEvent.keycode = 0;
167                         e.KeyEvent.state = 0;
168
169                         if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) {
170                                 e.KeyEvent.state |= (int) KeyMasks.ShiftMask;
171                         }
172
173                         if ((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) != 0) {
174                                 e.KeyEvent.state |= (int) KeyMasks.LockMask;
175                         }
176
177                         if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) {
178                                 e.KeyEvent.state |= (int) KeyMasks.ControlMask;
179                         }
180
181                         if ((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) != 0) {
182                                 e.KeyEvent.state |= NumLockMask;
183                         }
184
185                         e.KeyEvent.state |= AltGrMask;
186
187                         for (int keyc = min_keycode; (keyc <= max_keycode) && (e.KeyEvent.keycode == 0); keyc++) {
188                                 // find keycode that could have generated this vkey
189                                 if ((keyc2vkey [keyc] & 0xFF) == vkey) {
190                                         // filter extended bit because it is not known
191                                         e.KeyEvent.keycode = keyc;
192                                         if ((EventToVkey (e) & 0xFF) != vkey) {
193                                                 // Wrong one (ex: because of num,lock state)
194                                                 e.KeyEvent.keycode = 0;
195                                         }
196                                 }
197                         }
198
199                         if ((vkey >= (int) VirtualKeys.VK_NUMPAD0) && (vkey <= (int) VirtualKeys.VK_NUMPAD9))
200                                 e.KeyEvent.keycode = XKeysymToKeycode (display, vkey - (int) VirtualKeys.VK_NUMPAD0 + (int) KeypadKeys.XK_KP_0);
201
202                         if (vkey == (int) VirtualKeys.VK_DECIMAL)
203                                 e.KeyEvent.keycode = XKeysymToKeycode (display, (int) KeypadKeys.XK_KP_Decimal);
204
205                         if (e.KeyEvent.keycode == 0) {
206                                 // And I couldn't find the keycode so i returned the vkey and was like whatever
207                                 Console.Error.WriteLine ("unknown virtual key {0:X}", vkey);
208                                 buffer = String.Empty;
209                                 return vkey; 
210                         }
211
212                         IntPtr  buf = Marshal.AllocHGlobal (2);
213                         XKeySym t;
214                         int res = XLookupString (ref e, buf, 2, out t, IntPtr.Zero);
215                         int keysym = (int) t;
216
217                         buffer = String.Empty;
218                         if (res == 0) {
219                                 int dead_char = MapDeadKeySym (keysym);
220                                 if (dead_char != 0) {
221                                         byte [] bytes = new byte [1];
222                                         bytes [0] = (byte) dead_char;
223                                         Encoding encoding = Encoding.GetEncoding (layout.CodePage);
224                                         buffer = new string (encoding.GetChars (bytes));
225                                         res = -1;
226                                 }
227                         } else {
228                                 // Shift + arrow, shift + home, ....
229                                 // X returns a char for it, but windows doesn't
230                                 if (((e.KeyEvent.state & NumLockMask) == 0) && ((e.KeyEvent.state & (int) KeyMasks.ShiftMask) != 0) &&
231                                                 (keysym >= (int) KeypadKeys.XK_KP_0) && (keysym <= (int) KeypadKeys.XK_KP_9)) {
232                                         buffer = String.Empty;
233                                         res = 0;
234                                 }
235
236                                 // CTRL + number, X returns chars, windows does not
237                                 if ((e.KeyEvent.state & (int) KeyMasks.ControlMask) != 0) {
238                                         if (((keysym >= 33) && (keysym < 'A')) || ((keysym > 'Z') && (keysym < 'a'))) {
239                                                 buffer = String.Empty;
240                                                 res = 0;
241                                         }
242                                 }
243
244                                 // X returns a char for delete key on extended keyboards, windows does not
245                                 if (keysym == (int) TtyKeys.XK_Delete) {
246                                         buffer = String.Empty;
247                                         res = 0;
248                                 }
249
250                                 if (res != 0) {
251                                         byte [] bytes = new byte [2];
252                                         bytes [0] = Marshal.ReadByte (buf);
253                                         bytes [1] = Marshal.ReadByte (buf, 1);
254                                         Encoding encoding = Encoding.GetEncoding (layout.CodePage);
255                                         buffer = new string (encoding.GetChars (bytes));
256                                 }
257                         }
258
259                         return res;
260                 }
261
262                 private MSG SendKeyboardInput (VirtualKeys vkey, int scan, KeybdEventFlags dw_flags, int time)
263                 {
264                         Msg message;
265
266                         if ((dw_flags & KeybdEventFlags.KeyUp) != 0) {
267                                 bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
268                                               ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
269                                 key_state_table [(int) vkey] &= unchecked ((byte) ~0x80);
270                                 message = (sys_key ? Msg.WM_SYSKEYUP : Msg.WM_KEYUP);
271                         } else {
272                                 if ((key_state_table [(int) vkey] & 0x80) == 0) {
273                                         key_state_table [(int) vkey] ^= 0x01;
274                                 }
275                                 key_state_table [(int) vkey] |= 0x80;
276                                 bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
277                                               ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
278                                 message = (sys_key ? Msg.WM_SYSKEYDOWN : Msg.WM_KEYDOWN);
279                         }
280
281                         MSG msg = new MSG ();
282                         msg.message = message;
283                         msg.wParam = (IntPtr) vkey;
284                         msg.lParam = IntPtr.Zero;
285
286                         return msg;
287                 }
288
289                 private void GenerateMessage (VirtualKeys vkey, int scan, XEventName type, int event_time)
290                 {
291                         bool state = (vkey == VirtualKeys.VK_NUMLOCK ? num_state : cap_state);
292                         KeybdEventFlags up, down;
293
294                         if (state) {
295                                 // The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
296                                 // don't treat it. It's from the same key press. Then the state goes to ON.
297                                 // And from there, a 'release' event will switch off the toggle key.
298                                 SetState (vkey, false);
299                         } else {
300                                 down = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey : KeybdEventFlags.None);
301                                 up = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey :
302                                                 KeybdEventFlags.None) | KeybdEventFlags.KeyUp;
303                                 if ((key_state_table [(int) vkey] & 0x1) != 0) { // it was on
304                                         if (type != XEventName.KeyPress) {
305                                                 SendKeyboardInput (vkey, scan, down, event_time);
306                                                 SendKeyboardInput (vkey, scan, up, event_time);
307                                                 SetState (vkey, false);
308                                                 key_state_table [(int) vkey] &= unchecked ((byte) ~0x01);
309                                         }
310                                 } else {
311                                         if (type == XEventName.KeyPress) {
312                                                 SendKeyboardInput (vkey, scan, down, event_time);
313                                                 SendKeyboardInput (vkey, scan, up, event_time);
314                                                 SetState (vkey, true);
315                                                 key_state_table [(int) vkey] |= 0x01;
316                                         }
317                                 }
318                         }
319                 }
320
321                 private void UpdateKeyState (XEvent xevent)
322                 {
323                         int vkey = EventToVkey (xevent);
324
325                         switch (xevent.type) {
326                         case XEventName.KeyRelease:
327                                 key_state_table [(int) vkey] &= unchecked ((byte) ~0x80);
328                                 break;
329                         case XEventName.KeyPress:
330                                 if ((key_state_table [(int) vkey] & 0x80) == 0) {
331                                         key_state_table [(int) vkey] ^= 0x01;
332                                 }
333                                 key_state_table [(int) vkey] |= 0x80;
334                                 break;
335                         }
336                 }
337
338                 private void SetState (VirtualKeys key, bool state)
339                 {
340                         if (VirtualKeys.VK_NUMLOCK == key)
341                                 num_state = state;
342                         else
343                                 cap_state = state;
344                 }
345
346                 public int EventToVkey (XEvent e)
347                 {
348                         XKeySym ks;
349
350                         XLookupString (ref e, IntPtr.Zero, 0, out ks, IntPtr.Zero);
351                         int keysym = (int) ks;
352
353                         if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
354                                         && ((e.KeyEvent.state & NumLockMask) !=0)) {
355                                 // Only the Keypad keys 0-9 and . send different keysyms
356                                 // depending on the NumLock state
357                                 return KeyboardLayouts.nonchar_key_vkey [keysym & 0xFF];
358                         }
359
360                         return keyc2vkey [e.KeyEvent.keycode];
361                 }
362
363                 public void CreateConversionArray (KeyboardLayout layout)
364                 {
365
366                         XEvent e2 = new XEvent ();
367                         int keysym = 0;
368                         int [] ckey = new int [] { 0, 0, 0, 0 };
369
370                         e2.KeyEvent.display = display;
371                         e2.KeyEvent.state = 0;
372
373                         int oem_vkey = (int) VirtualKeys.VK_OEM_7;
374                         for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
375                                 int vkey = 0;
376                                 int scan = 0;
377
378                                 e2.KeyEvent.keycode = keyc;
379                                 XKeySym t;
380                                 XLookupString (ref e2, IntPtr.Zero, 0, out t, IntPtr.Zero);
381                                 keysym = (int) t;
382                                 if (keysym != 0) {
383                                         if ((keysym >> 8) == 0xFF) {
384                                                 vkey = KeyboardLayouts.nonchar_key_vkey [keysym & 0xFF];
385                                                 scan = KeyboardLayouts.nonchar_key_scan [keysym & 0xFF];
386                                                 // Set extended bit
387                                                 if ((scan & 0x100) != 0)
388                                                         vkey |= 0x100;
389                                         } else if (keysym == 0x20) { // spacebar
390                                                 vkey = (int) VirtualKeys.VK_SPACE;
391                                                 scan = 0x39;
392                                         } else {
393                                                 // Search layout dependent scancodes
394                                                 int maxlen = 0;
395                                                 int maxval = -1;;
396                                                 int ok;
397                                                 
398                                                 for (int i = 0; i < syms; i++) {
399                                                         keysym = (int) XKeycodeToKeysym (display, keyc, i);
400                                                         if ((keysym < 0x800) && (keysym != ' '))
401                                                                 ckey [i] = keysym & 0xFF;
402                                                         else
403                                                                 ckey [i] = MapDeadKeySym (keysym);
404                                                 }
405                                                 
406                                                 for (int keyn = 0; keyn < layout.Key.Length; keyn++) {
407                                                         int i = 0;
408                                                         int ml = (layout.Key [keyn].Length > 4 ? 4 : layout.Key [keyn].Length);
409                                                         for (ok = layout.Key [keyn][i]; (ok != 0) && (i < ml); i++) {
410                                                                 if (layout.Key [keyn][i] != ckey [i])
411                                                                         ok = 0;
412                                                                 if ((ok != 0) || (i > maxlen)) {
413                                                                         maxlen = i;
414                                                                         maxval = keyn;
415                                                                 }
416                                                                 if (ok != 0)
417                                                                         break;
418                                                         }
419                                                 }
420                                                 if (maxval >= 0) {
421                                                         scan = layout.Scan [maxval];
422                                                         vkey = (int) layout.VKey [maxval];
423                                                 }
424                                                 
425                                         }
426
427                                         for (int i = 0; (i < keysyms_per_keycode) && (vkey == 0); i++) {
428                                                 keysym = (int) XLookupKeysym (ref e2, i);
429                                                 if ((keysym >= (int) VirtualKeys.VK_0 && keysym <= (int) VirtualKeys.VK_9) ||
430                                                                 (keysym >= (int) VirtualKeys.VK_A && keysym <= (int) VirtualKeys.VK_Z)) {
431                                                         vkey = keysym;
432                                                 }
433                                         }
434
435                                         for (int i = 0; (i < keysyms_per_keycode) && (vkey == 0); i++) {
436                                                 keysym = (int) XLookupKeysym (ref e2, i);
437                                                 switch ((char) keysym) {
438                                                 case ';':
439                                                         vkey = (int) VirtualKeys.VK_OEM_1;
440                                                         break;
441                                                 case '/':
442                                                         vkey = (int) VirtualKeys.VK_OEM_2;
443                                                         break;
444                                                 case '`':
445                                                         vkey = (int) VirtualKeys.VK_OEM_3;
446                                                         break;
447                                                 case '[':
448                                                         vkey = (int) VirtualKeys.VK_OEM_4;
449                                                         break;
450                                                 case '\\':
451                                                         vkey = (int) VirtualKeys.VK_OEM_5;
452                                                         break;
453                                                 case ']':
454                                                         vkey = (int) VirtualKeys.VK_OEM_6;
455                                                         break;
456                                                 case '\'':
457                                                         vkey = (int) VirtualKeys.VK_OEM_7;
458                                                         break;
459                                                 case ',':
460                                                         vkey = (int) VirtualKeys.VK_OEM_COMMA;
461                                                         break;
462                                                 case '.':
463                                                         vkey = (int) VirtualKeys.VK_OEM_PERIOD;
464                                                         break;
465                                                 case '-':
466                                                         vkey = (int) VirtualKeys.VK_OEM_MINUS;
467                                                         break;
468                                                 case '+':
469                                                         vkey = (int) VirtualKeys.VK_OEM_PLUS;
470                                                         break;
471
472                                                 }
473                                         }
474
475                                         if (vkey == 0) {
476                                                 switch (++oem_vkey) {
477                                                 case 0xc1:
478                                                         oem_vkey = 0xDB;
479                                                         break;
480                                                 case 0xE5:
481                                                         oem_vkey = 0xE9;
482                                                         break;
483                                                 case 0xF6:
484                                                         oem_vkey = 0xF5;
485                                                         break;
486                                                 }
487                                                 vkey = oem_vkey;
488                                         }
489                                 }
490                                 keyc2vkey [e2.KeyEvent.keycode] = vkey;
491                                 keyc2scan [e2.KeyEvent.keycode] = scan;
492                         }
493                         
494                         
495                 }
496
497                 public void DetectLayout ()
498                 {
499                         XDisplayKeycodes (display, out min_keycode, out max_keycode);
500                         IntPtr ksp = XGetKeyboardMapping (display, (byte) min_keycode,
501                                         max_keycode + 1 - min_keycode, out keysyms_per_keycode);
502                         XplatUIX11.XFree (ksp);
503
504                         syms = keysyms_per_keycode;
505                         if (syms > 4) {
506                                 //Console.Error.WriteLine ("{0} keysymbols per a keycode is not supported, setting to 4", syms);
507                                 syms = 2;
508                         }
509
510                         IntPtr  modmap_unmanaged;
511                         XModifierKeymap xmk = new XModifierKeymap ();
512
513                         modmap_unmanaged = XGetModifierMapping (display);
514                         xmk = (XModifierKeymap) Marshal.PtrToStructure (modmap_unmanaged, typeof (XModifierKeymap));
515
516                         int mmp = 0;
517                         for (int i = 0; i < 8; i++) {
518                                 for (int j = 0; j < xmk.max_keypermod; j++, mmp++) {
519                                         byte b = Marshal.ReadByte (xmk.modifiermap, mmp);
520                                         if (b != 0) {
521                                                 for (int k = 0; k < keysyms_per_keycode; k++) {
522                                                         if ((int) XKeycodeToKeysym (display, b, k) == (int) MiscKeys.XK_Num_Lock)
523                                                                 NumLockMask = 1 << i;
524                                                 }
525                                         }
526                                 }
527                         }
528                         XFreeModifiermap (modmap_unmanaged);
529
530                         int [] ckey = new int [4];
531                         KeyboardLayout layout = null;
532                         int max_score = 0;
533                         int max_seq = 0;
534                         
535                         foreach (KeyboardLayout current in KeyboardLayouts.Layouts) {
536                                 int ok = 0;
537                                 int score = 0;
538                                 int match = 0;
539                                 int seq = 0;
540                                 int pkey = -1;
541                                 int key = min_keycode;
542
543                                 for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
544                                         for (int i = 0; i < syms; i++) {
545                                                 int keysym = (int) XKeycodeToKeysym (display, keyc, i);
546                                                 
547                                                 if ((keysym != 0xFF1B) && (keysym < 0x800) && (keysym != ' ')) {
548                                                         ckey [i] = keysym & 0xFF;
549                                                 } else {
550                                                         ckey [i] = MapDeadKeySym (keysym);
551                                                 }
552                                         }
553                                         if (ckey [0] != 0) {
554
555                                                 for (key = 0; key < current.Key.Length; key++) {
556                                                         ok = 0;
557                                                         int ml = (current.Key [key].Length > syms ? syms : current.Key [key].Length);
558                                                         for (int i = 0; (ok >= 0) && (i < ml); i++) {
559                                                                 if (ckey [i] != 0 && current.Key [key][i] == (char) ckey [i]) {
560                                                                         ok++;
561                                                                 }
562                                                                 if (ckey [i] != 0 && current.Key [key][i] != (char) ckey [i])
563                                                                         ok = -1;
564                                                         }
565                                                         if (ok >= 0) {
566                                                                 score += ok;
567                                                                 break;
568                                                         }
569                                                 }
570                                                 if (ok > 0) {
571                                                         match++;
572                                                         if (key > pkey)
573                                                                 seq++;
574                                                         pkey = key;
575                                                 } else {
576                                                         score -= syms;
577                                                 }
578                                         }
579                                 }
580
581                                 if ((score > max_score) || ((score == max_score) && (seq > max_seq))) {
582                                         // best match so far
583                                         layout = current;
584                                         max_score = score;
585                                         max_seq = seq;
586                                 }
587                         }
588
589                         if (layout != null)  {
590                                 this.layout = layout;
591                                 Console.WriteLine (Locale.GetText("Keyboard") + ": " + layout.Comment);
592                         } else {
593                                 Console.WriteLine (Locale.GetText("Keyboard layout not recognized, using default layout: " + layout.Comment));
594                         }
595                 }
596
597                 // TODO
598                 private int MapDeadKeySym (int val)
599                 {
600                         switch (val) {
601                         case (int) DeadKeys.XK_dead_tilde :
602                         case 0x1000FE7E : // Xfree's Dtilde
603                                 return '~';
604                         case (int) DeadKeys.XK_dead_acute :
605                         case 0x1000FE27 : // Xfree's XK_Dacute_accent
606                                 return 0xb4;
607                         case (int) DeadKeys.XK_dead_circumflex:
608                         case 0x1000FE5E : // Xfree's XK_.Dcircumflex_accent
609                                 return '^';
610                         case (int) DeadKeys.XK_dead_grave :
611                         case 0x1000FE60 : // Xfree's XK_.Dgrave_accent
612                                 return '`';
613                         case (int) DeadKeys.XK_dead_diaeresis :
614                         case 0x1000FE22 : // Xfree's XK_.Ddiaeresis
615                                 return 0xa8;
616                         case (int) DeadKeys.XK_dead_cedilla :
617                                 return 0xb8;
618                         case (int) DeadKeys.XK_dead_macron :
619                                 return '-';
620                         case (int) DeadKeys.XK_dead_breve :
621                                 return 0xa2;
622                         case (int) DeadKeys.XK_dead_abovedot :
623                                 return 0xff;
624                         case (int) DeadKeys.XK_dead_abovering :
625                                 return '0';
626                         case (int) DeadKeys.XK_dead_doubleacute :
627                                 return 0xbd;
628                         case (int) DeadKeys.XK_dead_caron :
629                                 return 0xb7;
630                         case (int) DeadKeys.XK_dead_ogonek :
631                                 return 0xb2;
632                         }
633
634                         return 0;
635                 }
636
637                 [DllImport ("libX11")]
638                 internal extern static int XLookupString(ref XEvent xevent, IntPtr buffer, int num_bytes, out IntPtr keysym, IntPtr status);
639                 internal static int XLookupString (ref XEvent xevent, IntPtr buffer, int num_bytes, out XKeySym keysym, IntPtr status) {
640                         IntPtr  keysym_ret;
641                         int     ret;
642
643                         ret = XLookupString (ref xevent, buffer, num_bytes, out keysym_ret, status);
644                         keysym = (XKeySym)keysym_ret.ToInt32();
645
646                         return ret;
647                 }
648
649                 [DllImport ("libX11", EntryPoint="XLookupKeysym")]
650                 private static extern IntPtr XLookupKeysymX11(ref XEvent xevent, int index);
651                 private static XKeySym XLookupKeysym(ref XEvent xevent, int index) {
652                         return (XKeySym)XLookupKeysymX11(ref xevent, index).ToInt32();
653                 }
654
655                 [DllImport ("libX11")]
656                 private static extern IntPtr XGetKeyboardMapping (IntPtr display, byte first_keycode, int keycode_count, 
657                                 out int keysyms_per_keycode_return);
658
659                 [DllImport ("libX11")]
660                 private static extern void XDisplayKeycodes (IntPtr display, out int min, out int max);
661
662                 [DllImport ("libX11", EntryPoint="XKeycodeToKeysym")]
663                 private static extern IntPtr XKeycodeToKeysymX11(IntPtr display, int keycode, int index);
664                 private static XKeySym XKeycodeToKeysym(IntPtr display, int keycode, int index) {
665                         return (XKeySym)XKeycodeToKeysymX11(display, keycode, index).ToInt32();
666                 }
667
668                 [DllImport ("libX11")]
669                 private static extern int XKeysymToKeycode (IntPtr display, IntPtr keysym);
670                 private static int XKeysymToKeycode (IntPtr display, int keysym) {
671                         return XKeysymToKeycode(display, (IntPtr)keysym);
672                 }
673
674                 [DllImport ("libX11")]
675                 internal extern static IntPtr XGetModifierMapping (IntPtr display);
676
677                 [DllImport ("libX11")]
678                 internal extern static int XFreeModifiermap (IntPtr modmap);
679                 
680         }
681
682 }
683