diff options
Diffstat (limited to 'hw/xquartz/quartzKeyboard.c')
-rw-r--r-- | hw/xquartz/quartzKeyboard.c | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/hw/xquartz/quartzKeyboard.c b/hw/xquartz/quartzKeyboard.c new file mode 100644 index 000000000..9b899ca67 --- /dev/null +++ b/hw/xquartz/quartzKeyboard.c @@ -0,0 +1,324 @@ +/* + quartzKeyboard.c + + Code to build a keymap using the Carbon Keyboard Layout API. + + Copyright (c) 2003-2007 Apple Inc. + + 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 ABOVE LISTED COPYRIGHT + HOLDER(S) 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. + + Except as contained in this notice, the name(s) of the above + copyright holders shall not be used in advertising or otherwise to + promote the sale, use or other dealings in this Software without + prior written authorization. +*/ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include "quartzCommon.h" + +#include <CoreServices/CoreServices.h> +#include <Carbon/Carbon.h> + +#include "quartzKeyboard.h" +#include "X11/keysym.h" +#include "keysym2ucs.h" + +#define HACK_MISSING 1 +#define HACK_KEYPAD 1 + +enum { + MOD_COMMAND = 256, + MOD_SHIFT = 512, + MOD_OPTION = 2048, + MOD_CONTROL = 4096, +}; + +#define UKEYSYM(u) ((u) | 0x01000000) + +/* Table of keycode->keysym mappings we use to fallback on for important + keys that are often not in the Unicode mapping. */ + +const static struct { + unsigned short keycode; + KeySym keysym; +} known_keys[] = { + {55, XK_Meta_L}, + {56, XK_Shift_L}, + {57, XK_Caps_Lock}, + {58, XK_Alt_L}, + {59, XK_Control_L}, + + {60, XK_Shift_R}, + {61, XK_Alt_R}, + {62, XK_Control_R}, + {63, XK_Meta_R}, + + {122, XK_F1}, + {120, XK_F2}, + {99, XK_F3}, + {118, XK_F4}, + {96, XK_F5}, + {97, XK_F6}, + {98, XK_F7}, + {100, XK_F8}, + {101, XK_F9}, + {109, XK_F10}, + {103, XK_F11}, + {111, XK_F12}, + {105, XK_F13}, + {107, XK_F14}, + {113, XK_F15}, +}; + +/* Table of keycode->old,new-keysym mappings we use to fixup the numeric + keypad entries. */ + +const static struct { + unsigned short keycode; + KeySym normal, keypad; +} known_numeric_keys[] = { + {65, XK_period, XK_KP_Decimal}, + {67, XK_asterisk, XK_KP_Multiply}, + {69, XK_plus, XK_KP_Add}, + {75, XK_slash, XK_KP_Divide}, + {76, 0x01000003, XK_KP_Enter}, + {78, XK_minus, XK_KP_Subtract}, + {81, XK_equal, XK_KP_Equal}, + {82, XK_0, XK_KP_0}, + {83, XK_1, XK_KP_1}, + {84, XK_2, XK_KP_2}, + {85, XK_3, XK_KP_3}, + {86, XK_4, XK_KP_4}, + {87, XK_5, XK_KP_5}, + {88, XK_6, XK_KP_6}, + {89, XK_7, XK_KP_7}, + {91, XK_8, XK_KP_8}, + {92, XK_9, XK_KP_9}, +}; + +/* Table mapping normal keysyms to their dead equivalents. + FIXME: all the unicode keysyms (apart from circumflex) were guessed. */ + +const static struct { + KeySym normal, dead; +} dead_keys[] = { + {XK_grave, XK_dead_grave}, + {XK_acute, XK_dead_acute}, + {XK_asciicircum, XK_dead_circumflex}, + {UKEYSYM (0x2c6), XK_dead_circumflex}, /* MODIFIER LETTER CIRCUMFLEX ACCENT */ + {XK_asciitilde, XK_dead_tilde}, + {UKEYSYM (0x2dc), XK_dead_tilde}, /* SMALL TILDE */ + {XK_macron, XK_dead_macron}, + {XK_breve, XK_dead_breve}, + {XK_abovedot, XK_dead_abovedot}, + {XK_diaeresis, XK_dead_diaeresis}, + {UKEYSYM (0x2da), XK_dead_abovering}, /* DOT ABOVE */ + {XK_doubleacute, XK_dead_doubleacute}, + {XK_caron, XK_dead_caron}, + {XK_cedilla, XK_dead_cedilla}, + {XK_ogonek, XK_dead_ogonek}, + {UKEYSYM (0x269), XK_dead_iota}, /* LATIN SMALL LETTER IOTA */ + {UKEYSYM (0x2ec), XK_dead_voiced_sound}, /* MODIFIER LETTER VOICING */ +/* {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */ + {UKEYSYM (0x323), XK_dead_belowdot}, /* COMBINING DOT BELOW */ + {UKEYSYM (0x309), XK_dead_hook}, /* COMBINING HOOK ABOVE */ + {UKEYSYM (0x31b), XK_dead_horn}, /* COMBINING HORN */ +}; + +unsigned int QuartzSystemKeymapSeed(void) { + static unsigned int seed; + static KeyboardLayoutRef last_key_layout; + KeyboardLayoutRef key_layout; + + KLGetCurrentKeyboardLayout (&key_layout); + if (key_layout != last_key_layout) seed++; + last_key_layout = key_layout; + + return seed; +} + +static inline UniChar macroman2ucs(unsigned char c) { + /* Precalculated table mapping MacRoman-128 to Unicode. Generated + by creating single element CFStringRefs then extracting the + first character. */ + + static const unsigned short table[128] = { + 0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, + 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, + 0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, + 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, + 0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf, + 0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8, + 0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211, + 0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8, + 0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab, + 0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153, + 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca, + 0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02, + 0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1, + 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, + 0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc, + 0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7, + }; + + if (c < 128) return c; + else return table[c - 128]; +} + +static KeySym make_dead_key(KeySym in) { + int i; + + for (i = 0; i < sizeof (dead_keys) / sizeof (dead_keys[0]); i++) + if (dead_keys[i].normal == in) return dead_keys[i].dead; + + return in; +} + +Bool QuartzReadSystemKeymap(darwinKeyboardInfo *info) { + KeyboardLayoutRef key_layout; + const void *chr_data = NULL; + int num_keycodes = NUM_KEYCODES; + UInt32 keyboard_type = 0; + int is_uchr = 1, i, j; + OSStatus err; + KeySym *k; + + TISInputSourceRef currentKeyLayoutRef = TISCopyCurrentKeyboardLayoutInputSource(); + keyboard_type = LMGetKbdType (); + if (currentKeyLayoutRef) { + CFDataRef currentKeyLayoutDataRef = (CFDataRef )TISGetInputSourceProperty(currentKeyLayoutRef, kTISPropertyUnicodeKeyLayoutData); + if (currentKeyLayoutDataRef) chr_data = CFDataGetBytePtr(currentKeyLayoutDataRef); + } + + if (chr_data == NULL) { + KLGetCurrentKeyboardLayout (&key_layout); + KLGetKeyboardLayoutProperty (key_layout, kKLuchrData, &chr_data); + } + + if (chr_data == NULL) { + KLGetKeyboardLayoutProperty (key_layout, kKLKCHRData, &chr_data); + is_uchr = 0; + num_keycodes = 128; + } + + if (chr_data == NULL) { + ErrorF ( "Couldn't get uchr or kchr resource\n"); + return FALSE; + } + + /* Scan the keycode range for the Unicode character that each + key produces in the four shift states. Then convert that to + an X11 keysym (which may just the bit that says "this is + Unicode" if it can't find the real symbol.) */ + + for (i = 0; i < num_keycodes; i++) { + static const int mods[4] = {0, MOD_SHIFT, MOD_OPTION, + MOD_OPTION | MOD_SHIFT}; + + k = info->keyMap + i * GLYPHS_PER_KEY; + + for (j = 0; j < 4; j++) { + if (is_uchr) { + UniChar s[8]; + UniCharCount len; + UInt32 dead_key_state = 0, extra_dead = 0; + + err = UCKeyTranslate (chr_data, i, kUCKeyActionDown, + mods[j] >> 8, keyboard_type, 0, + &dead_key_state, 8, &len, s); + if (err != noErr) continue; + + if (len == 0 && dead_key_state != 0) { + /* Found a dead key. Work out which one it is, but + remembering that it's dead. */ + err = UCKeyTranslate (chr_data, i, kUCKeyActionDown, + mods[j] >> 8, keyboard_type, + kUCKeyTranslateNoDeadKeysMask, + &extra_dead, 8, &len, s); + if (err != noErr) continue; + } + + if (len > 0 && s[0] != 0x0010) { + k[j] = ucs2keysym (s[0]); + if (dead_key_state != 0) k[j] = make_dead_key (k[j]); + } + } else { // kchr + UInt32 c, state = 0, state2 = 0; + UInt16 code; + + code = i | mods[j]; + c = KeyTranslate (chr_data, code, &state); + + /* Dead keys are only processed on key-down, so ask + to translate those events. When we find a dead key, + translating the matching key up event will give + us the actual dead character. */ + + if (state != 0) + c = KeyTranslate (chr_data, code | 128, &state2); + + /* Characters seem to be in MacRoman encoding. */ + + if (c != 0 && c != 0x0010) { + k[j] = ucs2keysym (macroman2ucs (c & 255)); + + if (state != 0) k[j] = make_dead_key (k[j]); + } + } + } + + if (k[3] == k[2]) k[3] = NoSymbol; + if (k[2] == k[1]) k[2] = NoSymbol; + if (k[1] == k[0]) k[1] = NoSymbol; + if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; + } + + /* Fix up some things that are normally missing.. */ + + if (HACK_MISSING) { + for (i = 0; i < sizeof (known_keys) / sizeof (known_keys[0]); i++) { + k = info->keyMap + known_keys[i].keycode * GLYPHS_PER_KEY; + + if (k[0] == NoSymbol && k[1] == NoSymbol + && k[2] == NoSymbol && k[3] == NoSymbol) + k[0] = known_keys[i].keysym; + } + } + + /* And some more things. We find the right symbols for the numeric + keypad, but not the KP_ keysyms. So try to convert known keycodes. */ + + if (HACK_KEYPAD) { + for (i = 0; i < sizeof (known_numeric_keys) + / sizeof (known_numeric_keys[0]); i++) { + k = info->keyMap + known_numeric_keys[i].keycode * GLYPHS_PER_KEY; + + if (k[0] == known_numeric_keys[i].normal) + k[0] = known_numeric_keys[i].keypad; + } + } + if(currentKeyLayoutRef) CFRelease(currentKeyLayoutRef); + + return TRUE; +} |