Blame synfig-osx/launcher/darwin-new-keymap.c

Carlos Lopez a09598
/* darwin-new-keymap.c -- code to build a keymap from the system
Carlos Lopez a09598
   $Id: darwin-new-keymap.c,v 1.7 2003/02/21 22:33:19 jharper Exp $
Carlos Lopez a09598
Carlos Lopez a09598
   Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
Carlos Lopez a09598
Carlos Lopez a09598
   Permission is hereby granted, free of charge, to any person
Carlos Lopez a09598
   obtaining a copy of this software and associated documentation files
Carlos Lopez a09598
   (the "Software"), to deal in the Software without restriction,
Carlos Lopez a09598
   including without limitation the rights to use, copy, modify, merge,
Carlos Lopez a09598
   publish, distribute, sublicense, and/or sell copies of the Software,
Carlos Lopez a09598
   and to permit persons to whom the Software is furnished to do so,
Carlos Lopez a09598
   subject to the following conditions:
Carlos Lopez a09598
Carlos Lopez a09598
   The above copyright notice and this permission notice shall be
Carlos Lopez a09598
   included in all copies or substantial portions of the Software.
Carlos Lopez a09598
Carlos Lopez a09598
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Carlos Lopez a09598
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Carlos Lopez a09598
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Carlos Lopez a09598
   NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
Carlos Lopez a09598
   HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
Carlos Lopez a09598
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
Carlos Lopez a09598
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
Carlos Lopez a09598
   DEALINGS IN THE SOFTWARE.
Carlos Lopez a09598
Carlos Lopez a09598
   Except as contained in this notice, the name(s) of the above
Carlos Lopez a09598
   copyright holders shall not be used in advertising or otherwise to
Carlos Lopez a09598
   promote the sale, use or other dealings in this Software without
Carlos Lopez a09598
   prior written authorization. */
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
#define Cursor X_Cursor
Carlos Lopez a09598
# include "darwin-keyboard.h"
Carlos Lopez a09598
# include "keysym.h"
Carlos Lopez a09598
#undef Cursor
Carlos Lopez a09598
Carlos Lopez a09598
#include <coreservices coreservices.h=""></coreservices>
Carlos Lopez a09598
#include <carbon carbon.h=""></carbon>
Carlos Lopez a09598
Carlos Lopez a09598
#include "keysym2ucs.h"
Carlos Lopez a09598
Carlos Lopez a09598
#define HACK_MISSING 1
Carlos Lopez a09598
#define HACK_KEYPAD 1
Carlos Lopez a09598
Carlos Lopez a09598
enum {
Carlos Lopez a09598
    MOD_COMMAND = 256,
Carlos Lopez a09598
    MOD_SHIFT = 512,
Carlos Lopez a09598
    MOD_OPTION = 2048,
Carlos Lopez a09598
    MOD_CONTROL = 4096,
Carlos Lopez a09598
};
Carlos Lopez a09598
Carlos Lopez a09598
#define UKEYSYM(u) ((u) | 0x01000000)
Carlos Lopez a09598
Carlos Lopez a09598
/* Table of keycode->keysym mappings we use to fallback on for important
Carlos Lopez a09598
   keys that are often not in the Unicode mapping. */
Carlos Lopez a09598
Carlos Lopez a09598
const static struct {
Carlos Lopez a09598
    unsigned short keycode;
Carlos Lopez a09598
    KeySym keysym;
Carlos Lopez a09598
} known_keys[] = {
Carlos Lopez a09598
    {55,  XK_Meta_L},
Carlos Lopez a09598
    {56,  XK_Shift_L},
Carlos Lopez a09598
    {57,  XK_Caps_Lock},
Carlos Lopez a09598
    {58,  XK_Alt_L},
Carlos Lopez a09598
    {59,  XK_Control_L},
Carlos Lopez a09598
    {60,  XK_Shift_R},
Carlos Lopez a09598
    {61,  XK_Alt_R},
Carlos Lopez a09598
    {62,  XK_Control_R},
Carlos Lopez a09598
Carlos Lopez a09598
    {122, XK_F1},
Carlos Lopez a09598
    {120, XK_F2},
Carlos Lopez a09598
    {99,  XK_F3},
Carlos Lopez a09598
    {118, XK_F4},
Carlos Lopez a09598
    {96,  XK_F5},
Carlos Lopez a09598
    {97,  XK_F6},
Carlos Lopez a09598
    {98,  XK_F7},
Carlos Lopez a09598
    {100, XK_F8},
Carlos Lopez a09598
    {101, XK_F9},
Carlos Lopez a09598
    {109, XK_F10},
Carlos Lopez a09598
    {103, XK_F11},
Carlos Lopez a09598
    {111, XK_F12},
Carlos Lopez a09598
    {105, XK_F13},
Carlos Lopez a09598
    {107, XK_F14},
Carlos Lopez a09598
    {113, XK_F15},
Carlos Lopez a09598
};
Carlos Lopez a09598
Carlos Lopez a09598
/* Table of keycode->old,new-keysym mappings we use to fixup the numeric
Carlos Lopez a09598
   keypad entries. */
Carlos Lopez a09598
Carlos Lopez a09598
const static struct {
Carlos Lopez a09598
    unsigned short keycode;
Carlos Lopez a09598
    KeySym normal, keypad;
Carlos Lopez a09598
} known_numeric_keys[] = {
Carlos Lopez a09598
    {65, XK_period, XK_KP_Decimal},
Carlos Lopez a09598
    {67, XK_asterisk, XK_KP_Multiply},
Carlos Lopez a09598
    {69, XK_plus, XK_KP_Add},
Carlos Lopez a09598
    {75, XK_slash, XK_KP_Divide},
Carlos Lopez a09598
    {76, 0x01000003, XK_KP_Enter},
Carlos Lopez a09598
    {78, XK_minus, XK_KP_Subtract},
Carlos Lopez a09598
    {81, XK_equal, XK_KP_Equal},
Carlos Lopez a09598
    {82, XK_0, XK_KP_0},
Carlos Lopez a09598
    {83, XK_1, XK_KP_1},
Carlos Lopez a09598
    {84, XK_2, XK_KP_2},
Carlos Lopez a09598
    {85, XK_3, XK_KP_3},
Carlos Lopez a09598
    {86, XK_4, XK_KP_4},
Carlos Lopez a09598
    {87, XK_5, XK_KP_5},
Carlos Lopez a09598
    {88, XK_6, XK_KP_6},
Carlos Lopez a09598
    {89, XK_7, XK_KP_7},
Carlos Lopez a09598
    {91, XK_8, XK_KP_8},
Carlos Lopez a09598
    {92, XK_9, XK_KP_9},
Carlos Lopez a09598
};
Carlos Lopez a09598
Carlos Lopez a09598
/* Table mapping normal keysyms to their dead equivalents.
Carlos Lopez a09598
   FIXME: all the unicode keysyms (apart from circumflex) were guessed. */
Carlos Lopez a09598
Carlos Lopez a09598
const static struct {
Carlos Lopez a09598
    KeySym normal, dead;
Carlos Lopez a09598
} dead_keys[] = {
Carlos Lopez a09598
    {XK_grave, XK_dead_grave},
Carlos Lopez a09598
    {XK_acute, XK_dead_acute},
Carlos Lopez a09598
    {XK_asciicircum, XK_dead_circumflex},
Carlos Lopez a09598
    {UKEYSYM (0x2c6), XK_dead_circumflex},	/* MODIFIER LETTER CIRCUMFLEX ACCENT */
Carlos Lopez a09598
    {XK_asciitilde, XK_dead_tilde},
Carlos Lopez a09598
    {UKEYSYM (0x2dc), XK_dead_tilde},		/* SMALL TILDE */
Carlos Lopez a09598
    {XK_macron, XK_dead_macron},
Carlos Lopez a09598
    {XK_breve, XK_dead_breve},
Carlos Lopez a09598
    {XK_abovedot, XK_dead_abovedot},
Carlos Lopez a09598
    {XK_diaeresis, XK_dead_diaeresis},
Carlos Lopez a09598
    {UKEYSYM (0x2da), XK_dead_abovering},	/* DOT ABOVE */
Carlos Lopez a09598
    {XK_doubleacute, XK_dead_doubleacute},
Carlos Lopez a09598
    {XK_caron, XK_dead_caron},
Carlos Lopez a09598
    {XK_cedilla, XK_dead_cedilla},
Carlos Lopez a09598
    {XK_ogonek, XK_dead_ogonek},
Carlos Lopez a09598
    {UKEYSYM (0x269), XK_dead_iota},		/* LATIN SMALL LETTER IOTA */
Carlos Lopez a09598
    {UKEYSYM (0x2ec), XK_dead_voiced_sound},	/* MODIFIER LETTER VOICING */
Carlos Lopez a09598
/*  {XK_semivoiced_sound, XK_dead_semivoiced_sound}, */
Carlos Lopez a09598
    {UKEYSYM (0x323), XK_dead_belowdot},	/* COMBINING DOT BELOW */
Carlos Lopez a09598
    {UKEYSYM (0x309), XK_dead_hook}, 		/* COMBINING HOOK ABOVE */
Carlos Lopez a09598
    {UKEYSYM (0x31b), XK_dead_horn},		/* COMBINING HORN */
Carlos Lopez a09598
};
Carlos Lopez a09598
Carlos Lopez a09598
unsigned int
Carlos Lopez a09598
DarwinSystemKeymapSeed (void)
Carlos Lopez a09598
{
Carlos Lopez a09598
    static unsigned int seed;
Carlos Lopez a09598
Carlos Lopez a09598
    static KeyboardLayoutRef last_key_layout;
Carlos Lopez a09598
    KeyboardLayoutRef key_layout;
Carlos Lopez a09598
Carlos Lopez a09598
    KLGetCurrentKeyboardLayout (&key_layout);
Carlos Lopez a09598
Carlos Lopez a09598
    if (key_layout != last_key_layout)
Carlos Lopez a09598
	seed++;
Carlos Lopez a09598
Carlos Lopez a09598
    last_key_layout = key_layout;
Carlos Lopez a09598
Carlos Lopez a09598
    return seed;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static inline UniChar
Carlos Lopez a09598
macroman2ucs (unsigned char c)
Carlos Lopez a09598
{
Carlos Lopez a09598
    /* Precalculated table mapping MacRoman-128 to Unicode. Generated
Carlos Lopez a09598
       by creating single element CFStringRefs then extracting the
Carlos Lopez a09598
       first character. */
Carlos Lopez a09598
Carlos Lopez a09598
    static const unsigned short table[128] = {
Carlos Lopez a09598
	0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1,
Carlos Lopez a09598
	0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8,
Carlos Lopez a09598
	0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3,
Carlos Lopez a09598
	0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc,
Carlos Lopez a09598
	0x2020, 0xb0, 0xa2, 0xa3, 0xa7, 0x2022, 0xb6, 0xdf,
Carlos Lopez a09598
	0xae, 0xa9, 0x2122, 0xb4, 0xa8, 0x2260, 0xc6, 0xd8,
Carlos Lopez a09598
	0x221e, 0xb1, 0x2264, 0x2265, 0xa5, 0xb5, 0x2202, 0x2211,
Carlos Lopez a09598
	0x220f, 0x3c0, 0x222b, 0xaa, 0xba, 0x3a9, 0xe6, 0xf8,
Carlos Lopez a09598
	0xbf, 0xa1, 0xac, 0x221a, 0x192, 0x2248, 0x2206, 0xab,
Carlos Lopez a09598
	0xbb, 0x2026, 0xa0, 0xc0, 0xc3, 0xd5, 0x152, 0x153,
Carlos Lopez a09598
	0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0xf7, 0x25ca,
Carlos Lopez a09598
	0xff, 0x178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02,
Carlos Lopez a09598
	0x2021, 0xb7, 0x201a, 0x201e, 0x2030, 0xc2, 0xca, 0xc1,
Carlos Lopez a09598
	0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4,
Carlos Lopez a09598
	0xf8ff, 0xd2, 0xda, 0xdb, 0xd9, 0x131, 0x2c6, 0x2dc,
Carlos Lopez a09598
	0xaf, 0x2d8, 0x2d9, 0x2da, 0xb8, 0x2dd, 0x2db, 0x2c7,
Carlos Lopez a09598
    };
Carlos Lopez a09598
Carlos Lopez a09598
    if (c < 128)
Carlos Lopez a09598
	return c;
Carlos Lopez a09598
    else
Carlos Lopez a09598
	return table[c - 128];
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
static KeySym
Carlos Lopez a09598
make_dead_key (KeySym in)
Carlos Lopez a09598
{
Carlos Lopez a09598
    int i;
Carlos Lopez a09598
Carlos Lopez a09598
    for (i = 0; i < sizeof (dead_keys) / sizeof (dead_keys[0]); i++)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	if (dead_keys[i].normal == in)
Carlos Lopez a09598
	    return dead_keys[i].dead;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    return in;
Carlos Lopez a09598
}
Carlos Lopez a09598
Carlos Lopez a09598
int
Carlos Lopez a09598
DarwinReadSystemKeymap (darwin_keyboard_info *info)
Carlos Lopez a09598
{
Carlos Lopez a09598
    KeyboardLayoutRef key_layout;
Carlos Lopez a09598
    const void *chr_data;
Carlos Lopez a09598
    int num_keycodes = NUM_KEYCODES;
Carlos Lopez a09598
    UInt32 keyboard_type = 0;
Carlos Lopez a09598
    int is_uchr, i, j;
Carlos Lopez a09598
    OSStatus err;
Carlos Lopez a09598
    KeySym *k;
Carlos Lopez a09598
Carlos Lopez a09598
    KLGetCurrentKeyboardLayout (&key_layout);
Carlos Lopez a09598
    KLGetKeyboardLayoutProperty (key_layout, kKLuchrData, &chr_data);
Carlos Lopez a09598
Carlos Lopez a09598
    if (chr_data != NULL)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	is_uchr = 1;
Carlos Lopez a09598
	keyboard_type = LMGetKbdType ();
Carlos Lopez a09598
    }
Carlos Lopez a09598
    else
Carlos Lopez a09598
    {
Carlos Lopez a09598
	KLGetKeyboardLayoutProperty (key_layout, kKLKCHRData, &chr_data);
Carlos Lopez a09598
Carlos Lopez a09598
	if (chr_data == NULL)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    fprintf (stderr, "couldn't get uchr or kchr resource\n");
Carlos Lopez a09598
	    return FALSE;
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	is_uchr = 0;
Carlos Lopez a09598
	num_keycodes = 128;
Carlos Lopez a09598
    }    
Carlos Lopez a09598
Carlos Lopez a09598
Carlos Lopez a09598
    /* Scan the keycode range for the Unicode character that each
Carlos Lopez a09598
       key produces in the four shift states. Then convert that to
Carlos Lopez a09598
       an X11 keysym (which may just the bit that says "this is
Carlos Lopez a09598
       Unicode" if it can't find the real symbol.) */
Carlos Lopez a09598
Carlos Lopez a09598
    for (i = 0; i < num_keycodes; i++)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	static const int mods[4] = {0, MOD_SHIFT, MOD_OPTION,
Carlos Lopez a09598
				    MOD_OPTION | MOD_SHIFT};
Carlos Lopez a09598
Carlos Lopez a09598
	k = info->key_map + i * GLYPHS_PER_KEY;
Carlos Lopez a09598
Carlos Lopez a09598
	for (j = 0; j < 4; j++)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    if (is_uchr)
Carlos Lopez a09598
	    {
Carlos Lopez a09598
		UniChar s[8];
Carlos Lopez a09598
		UniCharCount len;
Carlos Lopez a09598
		UInt32 dead_key_state, extra_dead;
Carlos Lopez a09598
Carlos Lopez a09598
		dead_key_state = 0;
Carlos Lopez a09598
		err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
Carlos Lopez a09598
				      mods[j] >> 8, keyboard_type, 0,
Carlos Lopez a09598
				      &dead_key_state, 8, &len, s);
Carlos Lopez a09598
		if (err != noErr)
Carlos Lopez a09598
		    continue;
Carlos Lopez a09598
Carlos Lopez a09598
		if (len == 0 && dead_key_state != 0)
Carlos Lopez a09598
		{
Carlos Lopez a09598
		    /* Found a dead key. Work out which one it is, but
Carlos Lopez a09598
		       remembering that it's dead. */
Carlos Lopez a09598
Carlos Lopez a09598
		    extra_dead = 0;
Carlos Lopez a09598
		    err = UCKeyTranslate (chr_data, i, kUCKeyActionDown,
Carlos Lopez a09598
					  mods[j] >> 8, keyboard_type,
Carlos Lopez a09598
					  kUCKeyTranslateNoDeadKeysMask,
Carlos Lopez a09598
					  &extra_dead, 8, &len, s);
Carlos Lopez a09598
		    if (err != noErr)
Carlos Lopez a09598
			continue;
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
		if (len > 0 && s[0] != 0x0010)
Carlos Lopez a09598
		{
Carlos Lopez a09598
		    k[j] = ucs2keysym (s[0]);
Carlos Lopez a09598
Carlos Lopez a09598
		    if (dead_key_state != 0)
Carlos Lopez a09598
			k[j] = make_dead_key (k[j]);
Carlos Lopez a09598
		}
Carlos Lopez a09598
	    }
Carlos Lopez a09598
	    else
Carlos Lopez a09598
	    {
Carlos Lopez a09598
		UInt32 c, state = 0;
Carlos Lopez a09598
		UInt16 code;
Carlos Lopez a09598
Carlos Lopez a09598
		code = i | mods[j];
Carlos Lopez a09598
		c = KeyTranslate (chr_data, code, &state);
Carlos Lopez a09598
Carlos Lopez a09598
		/* Dead keys are only processed on key-down, so ask
Carlos Lopez a09598
		   to translate those events. When we find a dead key,
Carlos Lopez a09598
		   translating the matching key up event will give
Carlos Lopez a09598
		   us the actual dead character. */
Carlos Lopez a09598
Carlos Lopez a09598
		if (state != 0)
Carlos Lopez a09598
		{
Carlos Lopez a09598
		    UInt32 state2 = 0;
Carlos Lopez a09598
		    c = KeyTranslate (chr_data, code | 128, &state2);
Carlos Lopez a09598
		}
Carlos Lopez a09598
Carlos Lopez a09598
		/* Characters seem to be in MacRoman encoding. */
Carlos Lopez a09598
Carlos Lopez a09598
		if (c != 0 && c != 0x0010)
Carlos Lopez a09598
		{
Carlos Lopez a09598
		    k[j] = ucs2keysym (macroman2ucs (c & 255));
Carlos Lopez a09598
Carlos Lopez a09598
		    if (state != 0)
Carlos Lopez a09598
			k[j] = make_dead_key (k[j]);
Carlos Lopez a09598
		}
Carlos Lopez a09598
	    }
Carlos Lopez a09598
	}
Carlos Lopez a09598
Carlos Lopez a09598
	if (k[3] == k[2])
Carlos Lopez a09598
	    k[3] = NoSymbol;
Carlos Lopez a09598
	if (k[2] == k[1])
Carlos Lopez a09598
	    k[2] = NoSymbol;
Carlos Lopez a09598
	if (k[1] == k[0])
Carlos Lopez a09598
	    k[1] = NoSymbol;
Carlos Lopez a09598
	if (k[0] == k[2] && k[1] == k[3])
Carlos Lopez a09598
	    k[2] = k[3] = NoSymbol;
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    /* Fix up some things that are normally missing.. */
Carlos Lopez a09598
Carlos Lopez a09598
    if (HACK_MISSING)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	for (i = 0; i < sizeof (known_keys) / sizeof (known_keys[0]); i++)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    k = info->key_map + known_keys[i].keycode * GLYPHS_PER_KEY;
Carlos Lopez a09598
Carlos Lopez a09598
	    if (k[0] == NoSymbol && k[1] == NoSymbol
Carlos Lopez a09598
		&& k[2] == NoSymbol && k[3] == NoSymbol)
Carlos Lopez a09598
	    {
Carlos Lopez a09598
		k[0] = known_keys[i].keysym;
Carlos Lopez a09598
	    }
Carlos Lopez a09598
	}
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    /* And some more things. We find the right symbols for the numeric
Carlos Lopez a09598
       keypad, but not the KP_ keysyms. So try to convert known keycodes. */
Carlos Lopez a09598
Carlos Lopez a09598
    if (HACK_KEYPAD)
Carlos Lopez a09598
    {
Carlos Lopez a09598
	for (i = 0; i < sizeof (known_numeric_keys)
Carlos Lopez a09598
	     / sizeof (known_numeric_keys[0]); i++)
Carlos Lopez a09598
	{
Carlos Lopez a09598
	    k = info->key_map + known_numeric_keys[i].keycode * GLYPHS_PER_KEY;
Carlos Lopez a09598
Carlos Lopez a09598
	    if (k[0] == known_numeric_keys[i].normal)
Carlos Lopez a09598
	    {
Carlos Lopez a09598
		k[0] = known_numeric_keys[i].keypad;
Carlos Lopez a09598
	    }
Carlos Lopez a09598
	}
Carlos Lopez a09598
    }
Carlos Lopez a09598
Carlos Lopez a09598
    return TRUE;
Carlos Lopez a09598
}