| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- // Copyright (c) 2004 Novell, Inc.
- //
- // Authors:
- // Jackson Harper ([email protected])
- //
- //
- //
- // TODO:
- // - dead chars are not translated properly
- // - There is a lot of potential for optimmization in here
- //
- using System;
- using System.Text;
- using System.Runtime.InteropServices;
- namespace System.Windows.Forms {
- internal class X11Keyboard {
- private IntPtr display;
- private int min_keycode, max_keycode, keysyms_per_keycode, syms;
- private int [] keyc2vkey = new int [256];
- private int [] keyc2scan = new int [256];
- private byte [] key_state_table = new byte [256];
- private bool num_state, cap_state;
- private KeyboardLayout layout;
- // TODO
- private int NumLockMask;
- private int AltGrMask;
-
- public X11Keyboard (IntPtr display)
- {
- this.display = display;
- DetectLayout ();
- CreateConversionArray (layout);
- }
- public Keys ModifierKeys {
- get {
- Keys keys = Keys.None;
- if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0)
- keys |= Keys.Shift;
- if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0)
- keys |= Keys.Control;
- if ((key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0)
- keys |= Keys.Alt;
- return keys;
- }
- }
- public void KeyEvent (IntPtr hwnd, XEvent xevent, ref MSG msg)
- {
- if ((xevent.KeyEvent.keycode >> 8) == 0x10)
- xevent.KeyEvent.keycode = xevent.KeyEvent.keycode & 0xFF;
- int event_time = (int)xevent.KeyEvent.time;
- int vkey = EventToVkey (xevent);
- if (vkey == 0)
- return;
- switch ((VirtualKeys) (vkey & 0xFF)) {
- case VirtualKeys.VK_NUMLOCK:
- GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, xevent.type, event_time);
- break;
- case VirtualKeys.VK_CAPITAL:
- GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, xevent.type, event_time);
- break;
- default:
- if (((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) == 0) != ((xevent.KeyEvent.state & NumLockMask) == 0)) {
- GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, XEventName.KeyPress, event_time);
- GenerateMessage (VirtualKeys.VK_NUMLOCK, 0x45, XEventName.KeyRelease, event_time);
- }
- if (((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) == 0) != ((xevent.KeyEvent.state & (int) KeyMasks.LockMask) == 0)) {
- GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, XEventName.KeyPress, event_time);
- GenerateMessage (VirtualKeys.VK_CAPITAL, 0x3A, XEventName.KeyRelease, event_time);
- }
- num_state = false;
- cap_state = false;
- int bscan = (keyc2scan [xevent.KeyEvent.keycode] & 0xFF);
- KeybdEventFlags dw_flags = KeybdEventFlags.None;
- if (xevent.type == XEventName.KeyRelease)
- dw_flags |= KeybdEventFlags.KeyUp;
- if ((vkey & 0x100) != 0)
- dw_flags |= KeybdEventFlags.ExtendedKey;
- msg = SendKeyboardInput ((VirtualKeys) (vkey & 0xFF), bscan, dw_flags, event_time);
- msg.hwnd = hwnd;
- break;
- }
- }
- public bool TranslateMessage (ref MSG msg)
- {
- bool res = false;
- if (msg.message >= Msg.WM_KEYFIRST && msg.message <= Msg.WM_KEYLAST)
- res = true;
- if (msg.message != Msg.WM_KEYDOWN && msg.message != Msg.WM_SYSKEYDOWN)
- return res;
- string buffer;
- Msg message;
- int tu = ToUnicode ((int) msg.wParam, Control.HighOrder ((int) msg.lParam), out buffer);
- switch (tu) {
- case 1:
- message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_CHAR : Msg.WM_SYSCHAR);
- XplatUIX11.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
- break;
- case -1:
- message = (msg.message == Msg.WM_KEYDOWN ? Msg.WM_DEADCHAR : Msg.WM_SYSDEADCHAR);
- XplatUIX11.PostMessage (msg.hwnd, message, (IntPtr) buffer [0], msg.lParam);
- return true;
- }
-
- return res;
- }
- private int ToUnicode (int vkey, int scan, out string buffer)
- {
- if ((scan & 0x8000) != 0) {
- buffer = String.Empty;
- return 0;
- }
- XEvent e = new XEvent ();
- e.KeyEvent.display = display;
- e.KeyEvent.keycode = 0;
- e.KeyEvent.state = 0;
- if ((key_state_table [(int) VirtualKeys.VK_SHIFT] & 0x80) != 0) {
- e.KeyEvent.state |= (int) KeyMasks.ShiftMask;
- }
- if ((key_state_table [(int) VirtualKeys.VK_CAPITAL] & 0x01) != 0) {
- e.KeyEvent.state |= (int) KeyMasks.LockMask;
- }
- if ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) != 0) {
- e.KeyEvent.state |= (int) KeyMasks.ControlMask;
- }
- if ((key_state_table [(int) VirtualKeys.VK_NUMLOCK] & 0x01) != 0) {
- e.KeyEvent.state |= NumLockMask;
- }
- e.KeyEvent.state |= AltGrMask;
- for (int keyc = min_keycode; (keyc <= max_keycode) && (e.KeyEvent.keycode == 0); keyc++) {
- // find keycode that could have generated this vkey
- if ((keyc2vkey [keyc] & 0xFF) == vkey) {
- // filter extended bit because it is not known
- e.KeyEvent.keycode = keyc;
- if ((EventToVkey (e) & 0xFF) != vkey) {
- // Wrong one (ex: because of num,lock state)
- e.KeyEvent.keycode = 0;
- }
- }
- }
- if ((vkey >= (int) VirtualKeys.VK_NUMPAD0) && (vkey <= (int) VirtualKeys.VK_NUMPAD9))
- e.KeyEvent.keycode = XKeysymToKeycode (display, vkey - (int) VirtualKeys.VK_NUMPAD0 + (int) KeypadKeys.XK_KP_0);
- if (vkey == (int) VirtualKeys.VK_DECIMAL)
- e.KeyEvent.keycode = XKeysymToKeycode (display, (int) KeypadKeys.XK_KP_Decimal);
- if (e.KeyEvent.keycode == 0) {
- // And I couldn't find the keycode so i returned the vkey and was like whatever
- Console.Error.WriteLine ("unknown virtual key {0:X}", vkey);
- buffer = String.Empty;
- return vkey;
- }
- IntPtr buf = Marshal.AllocHGlobal (2);
- XKeySym t;
- int res = XLookupString (ref e, buf, 2, out t, IntPtr.Zero);
- int keysym = (int) t;
- buffer = String.Empty;
- if (res == 0) {
- int dead_char = MapDeadKeySym (keysym);
- if (dead_char != 0) {
- byte [] bytes = new byte [1];
- bytes [0] = (byte) dead_char;
- Encoding encoding = Encoding.GetEncoding (layout.CodePage);
- buffer = new string (encoding.GetChars (bytes));
- res = -1;
- }
- } else {
- // Shift + arrow, shift + home, ....
- // X returns a char for it, but windows doesn't
- if (((e.KeyEvent.state & NumLockMask) == 0) && ((e.KeyEvent.state & (int) KeyMasks.ShiftMask) != 0) &&
- (keysym >= (int) KeypadKeys.XK_KP_0) && (keysym <= (int) KeypadKeys.XK_KP_9)) {
- buffer = String.Empty;
- res = 0;
- }
- // CTRL + number, X returns chars, windows does not
- if ((e.KeyEvent.state & (int) KeyMasks.ControlMask) != 0) {
- if (((keysym >= 33) && (keysym < 'A')) || ((keysym > 'Z') && (keysym < 'a'))) {
- buffer = String.Empty;
- res = 0;
- }
- }
- // X returns a char for delete key on extended keyboards, windows does not
- if (keysym == (int) TtyKeys.XK_Delete) {
- buffer = String.Empty;
- res = 0;
- }
- if (res != 0) {
- byte [] bytes = new byte [2];
- bytes [0] = Marshal.ReadByte (buf);
- bytes [1] = Marshal.ReadByte (buf, 1);
- Encoding encoding = Encoding.GetEncoding (layout.CodePage);
- buffer = new string (encoding.GetChars (bytes));
- }
- }
- return res;
- }
- private MSG SendKeyboardInput (VirtualKeys vkey, int scan, KeybdEventFlags dw_flags, int time)
- {
- Msg message;
- if ((dw_flags & KeybdEventFlags.KeyUp) != 0) {
- bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
- ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
- key_state_table [(int) vkey] &= unchecked ((byte) ~0x80);
- message = (sys_key ? Msg.WM_SYSKEYUP : Msg.WM_KEYUP);
- } else {
- if ((key_state_table [(int) vkey] & 0x80) == 0) {
- key_state_table [(int) vkey] ^= 0x01;
- }
- key_state_table [(int) vkey] |= 0x80;
- bool sys_key = (key_state_table [(int) VirtualKeys.VK_MENU] & 0x80) != 0 &&
- ((key_state_table [(int) VirtualKeys.VK_CONTROL] & 0x80) == 0);
- message = (sys_key ? Msg.WM_SYSKEYDOWN : Msg.WM_KEYDOWN);
- }
- MSG msg = new MSG ();
- msg.message = message;
- msg.wParam = (IntPtr) vkey;
- msg.lParam = IntPtr.Zero;
- return msg;
- }
- private void GenerateMessage (VirtualKeys vkey, int scan, XEventName type, int event_time)
- {
- bool state = (vkey == VirtualKeys.VK_NUMLOCK ? num_state : cap_state);
- KeybdEventFlags up, down;
- if (state) {
- // The INTERMEDIARY state means : just after a 'press' event, if a 'release' event comes,
- // don't treat it. It's from the same key press. Then the state goes to ON.
- // And from there, a 'release' event will switch off the toggle key.
- SetState (vkey, false);
- } else {
- down = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey : KeybdEventFlags.None);
- up = (vkey == VirtualKeys.VK_NUMLOCK ? KeybdEventFlags.ExtendedKey :
- KeybdEventFlags.None) | KeybdEventFlags.KeyUp;
- if ((key_state_table [(int) vkey] & 0x1) != 0) { // it was on
- if (type != XEventName.KeyPress) {
- SendKeyboardInput (vkey, scan, down, event_time);
- SendKeyboardInput (vkey, scan, up, event_time);
- SetState (vkey, false);
- key_state_table [(int) vkey] &= unchecked ((byte) ~0x01);
- }
- } else {
- if (type == XEventName.KeyPress) {
- SendKeyboardInput (vkey, scan, down, event_time);
- SendKeyboardInput (vkey, scan, up, event_time);
- SetState (vkey, true);
- key_state_table [(int) vkey] |= 0x01;
- }
- }
- }
- }
- private void SetState (VirtualKeys key, bool state)
- {
- if (VirtualKeys.VK_NUMLOCK == key)
- num_state = state;
- else
- cap_state = state;
- }
- public int EventToVkey (XEvent e)
- {
- XKeySym ks;
- XLookupString (ref e, IntPtr.Zero, 0, out ks, IntPtr.Zero);
- int keysym = (int) ks;
- if ((keysym >= 0xFFAE) && (keysym <= 0xFFB9) && (keysym != 0xFFAF)
- && ((e.KeyEvent.state & NumLockMask) !=0)) {
- // Only the Keypad keys 0-9 and . send different keysyms
- // depending on the NumLock state
- return KeyboardLayouts.nonchar_key_vkey [keysym & 0xFF];
- }
- return keyc2vkey [e.KeyEvent.keycode];
- }
- public void CreateConversionArray (KeyboardLayout layout)
- {
- XEvent e2 = new XEvent ();
- int keysym = 0;
- int [] ckey = new int [] { 0, 0, 0, 0 };
- e2.KeyEvent.display = display;
- e2.KeyEvent.state = 0;
- int oem_vkey = (int) VirtualKeys.VK_OEM_7;
- for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
- int vkey = 0;
- int scan = 0;
- e2.KeyEvent.keycode = keyc;
- XKeySym t;
- XLookupString (ref e2, IntPtr.Zero, 0, out t, IntPtr.Zero);
- keysym = (int) t;
- if (keysym != 0) {
- if ((keysym >> 8) == 0xFF) {
- vkey = KeyboardLayouts.nonchar_key_vkey [keysym & 0xFF];
- scan = KeyboardLayouts.nonchar_key_scan [keysym & 0xFF];
- // Set extended bit
- if ((scan & 0x100) != 0)
- vkey |= 0x100;
- } else if (keysym == 0x20) { // spacebar
- vkey = (int) VirtualKeys.VK_SPACE;
- scan = 0x39;
- } else {
- // Search layout dependent scancodes
- int maxlen = 0;
- int maxval = -1;;
- int ok;
-
- for (int i = 0; i < syms; i++) {
- keysym = (int) XKeycodeToKeysym (display, keyc, i);
- if ((keysym < 0x800) && (keysym != ' '))
- ckey [i] = keysym & 0xFF;
- else
- ckey [i] = MapDeadKeySym (keysym);
- }
-
- for (int keyn = 0; keyn < layout.Key.Length; keyn++) {
- int i = 0;
- int ml = (layout.Key [keyn].Length > 4 ? 4 : layout.Key [keyn].Length);
- for (ok = layout.Key [keyn][i]; (ok != 0) && (i < ml); i++) {
- if (layout.Key [keyn][i] != ckey [i])
- ok = 0;
- if ((ok != 0) || (i > maxlen)) {
- maxlen = i;
- maxval = keyn;
- }
- if (ok != 0)
- break;
- }
- }
- if (maxval >= 0) {
- scan = layout.Scan [maxval];
- vkey = (int) layout.VKey [maxval];
- }
-
- }
- for (int i = 0; (i < keysyms_per_keycode) && (vkey == 0); i++) {
- keysym = (int) XLookupKeysym (ref e2, i);
- if ((keysym >= (int) VirtualKeys.VK_0 && keysym <= (int) VirtualKeys.VK_9) ||
- (keysym >= (int) VirtualKeys.VK_A && keysym <= (int) VirtualKeys.VK_Z)) {
- vkey = keysym;
- }
- }
- for (int i = 0; (i < keysyms_per_keycode) && (vkey != 0); i++) {
- keysym = (int) XLookupKeysym (ref e2, i);
- switch ((char) keysym) {
- case ';':
- vkey = (int) VirtualKeys.VK_OEM_1;
- break;
- case '/':
- vkey = (int) VirtualKeys.VK_OEM_2;
- break;
- case '`':
- vkey = (int) VirtualKeys.VK_OEM_3;
- break;
- case '[':
- vkey = (int) VirtualKeys.VK_OEM_4;
- break;
- case '\\':
- vkey = (int) VirtualKeys.VK_OEM_5;
- break;
- case ']':
- vkey = (int) VirtualKeys.VK_OEM_6;
- break;
- case '\'':
- vkey = (int) VirtualKeys.VK_OEM_7;
- break;
- case ',':
- vkey = (int) VirtualKeys.VK_OEM_COMMA;
- break;
- case '.':
- vkey = (int) VirtualKeys.VK_OEM_PERIOD;
- break;
- case '-':
- vkey = (int) VirtualKeys.VK_OEM_MINUS;
- break;
- case '+':
- vkey = (int) VirtualKeys.VK_OEM_PLUS;
- break;
- }
- }
- if (vkey == 0) {
- switch (++oem_vkey) {
- case 0xc1:
- oem_vkey = 0xDB;
- break;
- case 0xE5:
- oem_vkey = 0xE9;
- break;
- case 0xF6:
- oem_vkey = 0xF5;
- break;
- }
- vkey = oem_vkey;
- }
- }
- keyc2vkey [e2.KeyEvent.keycode] = vkey;
- keyc2scan [e2.KeyEvent.keycode] = scan;
- }
-
-
- }
- public void DetectLayout ()
- {
- XDisplayKeycodes (display, out min_keycode, out max_keycode);
- IntPtr ksp = XGetKeyboardMapping (display, (byte) min_keycode,
- max_keycode + 1 - min_keycode, out keysyms_per_keycode);
- XplatUIX11.XFree (ksp);
- syms = keysyms_per_keycode;
- if (syms > 4) {
- Console.Error.WriteLine ("{0} keysymbols per a keycode is not supported, setting to 4", syms);
- syms = 2;
- }
- IntPtr modmap_unmanaged;
- XModifierKeymap xmk = new XModifierKeymap ();
- modmap_unmanaged = XGetModifierMapping (display);
- xmk = (XModifierKeymap) Marshal.PtrToStructure (modmap_unmanaged, typeof (XModifierKeymap));
- int mmp = 0;
- for (int i = 0; i < 8; i++) {
- for (int j = 0; j < xmk.max_keypermod; j++, mmp++) {
- byte b = Marshal.ReadByte (xmk.modifiermap, mmp);
- if (b != 0) {
- for (int k = 0; k < keysyms_per_keycode; k++) {
- if ((int) XKeycodeToKeysym (display, b, k) == (int) MiscKeys.XK_Num_Lock)
- NumLockMask = 1 << i;
- }
- }
- }
- }
- XFreeModifiermap (modmap_unmanaged);
- int [] ckey = new int [4];
- KeyboardLayout layout = null;
- int max_score = 0;
- int max_seq = 0;
-
- foreach (KeyboardLayout current in KeyboardLayouts.Layouts) {
- int ok = 0;
- int score = 0;
- int match = 0;
- int seq = 0;
- int pkey = -1;
- int key = min_keycode;
- for (int keyc = min_keycode; keyc <= max_keycode; keyc++) {
- for (int i = 0; i < syms; i++) {
- int keysym = (int) XKeycodeToKeysym (display, keyc, i);
-
- if ((keysym != 0xFF1B) && (keysym < 0x800) && (keysym != ' ')) {
- ckey [i] = keysym & 0xFF;
- } else {
- ckey [i] = MapDeadKeySym (keysym);
- }
- }
- if (ckey [0] != 0) {
- for (key = 0; key < current.Key.Length; key++) {
- ok = 0;
- int ml = (current.Key [key].Length > syms ? syms : current.Key [key].Length);
- for (int i = 0; (ok >= 0) && (i < ml); i++) {
- if (ckey [i] != 0 && current.Key [key][i] == (char) ckey [i]) {
- ok++;
- }
- if (ckey [i] != 0 && current.Key [key][i] != (char) ckey [i])
- ok = -1;
- }
- if (ok >= 0) {
- score += ok;
- break;
- }
- }
- if (ok > 0) {
- match++;
- if (key > pkey)
- seq++;
- pkey = key;
- } else {
- score -= syms;
- }
- }
- }
- if ((score > max_score) || ((score == max_score) && (seq > max_seq))) {
- // best match so far
- layout = current;
- max_score = score;
- max_seq = seq;
- }
- }
- if (layout != null)
- Console.WriteLine ("done detecting keyboard: " + layout.Comment);
- else
- Console.WriteLine ("no keyboard detected");
- this.layout = layout;
- }
- // TODO
- private int MapDeadKeySym (int val)
- {
- switch (val) {
- case (int) DeadKeys.XK_dead_tilde :
- case 0x1000FE7E : // Xfree's Dtilde
- return '~';
- case (int) DeadKeys.XK_dead_acute :
- case 0x1000FE27 : // Xfree's XK_Dacute_accent
- return 0xb4;
- case (int) DeadKeys.XK_dead_circumflex:
- case 0x1000FE5E : // Xfree's XK_.Dcircumflex_accent
- return '^';
- case (int) DeadKeys.XK_dead_grave :
- case 0x1000FE60 : // Xfree's XK_.Dgrave_accent
- return '`';
- case (int) DeadKeys.XK_dead_diaeresis :
- case 0x1000FE22 : // Xfree's XK_.Ddiaeresis
- return 0xa8;
- case (int) DeadKeys.XK_dead_cedilla :
- return 0xb8;
- case (int) DeadKeys.XK_dead_macron :
- return '-';
- case (int) DeadKeys.XK_dead_breve :
- return 0xa2;
- case (int) DeadKeys.XK_dead_abovedot :
- return 0xff;
- case (int) DeadKeys.XK_dead_abovering :
- return '0';
- case (int) DeadKeys.XK_dead_doubleacute :
- return 0xbd;
- case (int) DeadKeys.XK_dead_caron :
- return 0xb7;
- case (int) DeadKeys.XK_dead_ogonek :
- return 0xb2;
- }
- return 0;
- }
- [DllImport ("libX11")]
- internal extern static int XLookupString(ref XEvent xevent, IntPtr buffer,
- int num_bytes, out XKeySym keysym, IntPtr status);
- [DllImport ("libX11")]
- private static extern XKeySym XLookupKeysym (ref XEvent xevent, int index);
- [DllImport ("libX11")]
- private static extern IntPtr XGetKeyboardMapping (IntPtr display, byte first_keycode, int keycode_count,
- out int keysyms_per_keycode_return);
- [DllImport ("libX11")]
- private static extern void XDisplayKeycodes (IntPtr display, out int min, out int max);
- [DllImport ("libX11")]
- private static extern XKeySym XKeycodeToKeysym (IntPtr display, int keycode, int index);
- [DllImport ("libX11")]
- private static extern int XKeysymToKeycode (IntPtr display, int keysym);
- [DllImport ("libX11")]
- internal extern static IntPtr XGetModifierMapping (IntPtr display);
- [DllImport ("libX11")]
- internal extern static int XFreeModifiermap (IntPtr modmap);
-
- }
- }
|