aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xquartz/quartzKeyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xquartz/quartzKeyboard.c')
-rw-r--r--xorg-server/hw/xquartz/quartzKeyboard.c324
1 files changed, 324 insertions, 0 deletions
diff --git a/xorg-server/hw/xquartz/quartzKeyboard.c b/xorg-server/hw/xquartz/quartzKeyboard.c
new file mode 100644
index 000000000..9b899ca67
--- /dev/null
+++ b/xorg-server/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;
+}