forked from AuroraMiddleware/gtk
1097260aa7
2005-11-21 Anders Carlsson <andersca@imendio.com> * configure.in: * gtk/Makefile.am: * gdk/Makefile.am: * gdk/quartz/*: Add quartz backend. * docs/tools/Makefile.am: Only build docshooter when the X11 backend is used. * gtk/gtkplug-stub.c: Include gtkplug.h here. * gtk/gtksocket-stub.c: Include gtksocket.h here.
488 lines
13 KiB
C
488 lines
13 KiB
C
/* gdkkeys-quartz.c
|
|
*
|
|
* Copyright (C) 2000 Red Hat, Inc.
|
|
* Copyright (C) 2005 Imendio AB
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
/* Some parts of this code come from quartzKeyboard.c,
|
|
* from the Apple X11 Server.
|
|
*
|
|
* Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <Carbon/Carbon.h>
|
|
#include "gdk.h"
|
|
#include "gdkkeysyms.h"
|
|
|
|
#define NUM_KEYCODES 128
|
|
#define KEYVALS_PER_KEYCODE 4
|
|
|
|
static GdkKeymap *default_keymap = NULL;
|
|
|
|
static KeyboardLayoutRef current_layout = NULL;
|
|
|
|
/* This is a table of all keyvals. Each keycode gets KEYVALS_PER_KEYCODE entries.
|
|
* TThere is 1 keyval per modifier (Nothing, Shift, Alt, Shift+Alt);
|
|
*/
|
|
static guint *keyval_array = NULL;
|
|
|
|
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];
|
|
}
|
|
|
|
const static struct {
|
|
guint keycode;
|
|
guint keyval;
|
|
} known_keys[] = {
|
|
{ 55, GDK_Meta_L },
|
|
{ 56, GDK_Shift_L },
|
|
{ 57, GDK_Caps_Lock },
|
|
{ 58, GDK_Alt_L },
|
|
{ 59, GDK_Control_L },
|
|
{ 60, GDK_Shift_R },
|
|
{ 61, GDK_Alt_R },
|
|
{ 62, GDK_Control_R },
|
|
{ 122, GDK_F1 },
|
|
{ 120, GDK_F2 },
|
|
{ 99, GDK_F3 },
|
|
{ 118, GDK_F4 },
|
|
{ 96, GDK_F5 },
|
|
{ 97, GDK_F6 },
|
|
{ 98, GDK_F7 },
|
|
{ 100, GDK_F8 },
|
|
{ 101, GDK_F9 },
|
|
{ 109, GDK_F10 },
|
|
{ 103, GDK_F11 },
|
|
{ 111, GDK_F12 },
|
|
{ 105, GDK_F13 },
|
|
{ 107, GDK_F14 },
|
|
{ 113, GDK_F15 },
|
|
};
|
|
|
|
const static struct {
|
|
guint keycode;
|
|
guint normal_keyval, keypad_keyval;
|
|
} known_numeric_keys[] = {
|
|
{ 65, GDK_period, GDK_KP_Decimal },
|
|
{ 67, GDK_asterisk, GDK_KP_Multiply },
|
|
{ 69, GDK_plus, GDK_KP_Add },
|
|
{ 75, GDK_slash, GDK_KP_Divide },
|
|
{ 76, 0x01000003, GDK_KP_Enter },
|
|
{ 78, GDK_minus, GDK_KP_Subtract },
|
|
{ 81, GDK_equal, GDK_KP_Equal },
|
|
{ 82, GDK_0, GDK_KP_0 },
|
|
{ 83, GDK_1, GDK_KP_1 },
|
|
{ 84, GDK_2, GDK_KP_2 },
|
|
{ 85, GDK_3, GDK_KP_3 },
|
|
{ 86, GDK_4, GDK_KP_4 },
|
|
{ 87, GDK_5, GDK_KP_5 },
|
|
{ 88, GDK_6, GDK_KP_6 },
|
|
{ 89, GDK_7, GDK_KP_7 },
|
|
{ 91, GDK_8, GDK_KP_8 },
|
|
{ 92, GDK_9, GDK_KP_9 },
|
|
};
|
|
|
|
/* These values aren't covered by gdk_unicode_to_keyval */
|
|
const static struct {
|
|
gunichar ucs_value;
|
|
guint keyval;
|
|
} special_ucs_table [] = {
|
|
{ 0x0001, GDK_Home },
|
|
{ 0x0008, GDK_BackSpace },
|
|
{ 0x0009, GDK_Tab },
|
|
{ 0x000d, GDK_Return },
|
|
{ 0x001c, GDK_Left },
|
|
{ 0x001d, GDK_Right },
|
|
{ 0x001e, GDK_Up },
|
|
{ 0x001f, GDK_Down },
|
|
};
|
|
|
|
static void
|
|
maybe_update_keymap (void)
|
|
{
|
|
KeyboardLayoutRef new_layout;
|
|
|
|
KLGetCurrentKeyboardLayout (&new_layout);
|
|
|
|
if (new_layout != current_layout)
|
|
{
|
|
guint *p;
|
|
int i;
|
|
|
|
KeyboardLayoutKind layout_kind;
|
|
|
|
g_free (keyval_array);
|
|
keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
|
|
|
|
/* Get the layout kind */
|
|
KLGetKeyboardLayoutProperty (new_layout, kKLKind, &layout_kind);
|
|
|
|
/* FIXME: When we have UCHR support, I think that should be preffered
|
|
* if a keymap has both.
|
|
*/
|
|
if (layout_kind == kKLKCHRuchrKind || layout_kind == kKLKCHRKind)
|
|
{
|
|
const void *chr_data;
|
|
|
|
/* Get chr data */
|
|
KLGetKeyboardLayoutProperty (new_layout, kKLKCHRData, (void **)&chr_data);
|
|
|
|
for (i = 0; i < NUM_KEYCODES; i++)
|
|
{
|
|
int j;
|
|
UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey|optionKey};
|
|
|
|
p = keyval_array + i * KEYVALS_PER_KEYCODE;
|
|
|
|
for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
|
|
{
|
|
UInt32 c, state = 0;
|
|
UInt16 key_code;
|
|
UniChar uc;
|
|
|
|
key_code = modifiers[j]|i;
|
|
c = KeyTranslate (chr_data, key_code, &state);
|
|
|
|
if (state != 0)
|
|
{
|
|
UInt32 state2 = 0;
|
|
c = KeyTranslate (chr_data, key_code | 128, &state2);
|
|
}
|
|
|
|
if (c != 0 && c != 0x10)
|
|
{
|
|
guint keyval;
|
|
int k;
|
|
gboolean found = FALSE;
|
|
|
|
uc = macroman2ucs (c);
|
|
|
|
for (k = 0; k < G_N_ELEMENTS (special_ucs_table); k++)
|
|
{
|
|
if (special_ucs_table[k].ucs_value == uc)
|
|
{
|
|
p[j] = special_ucs_table[k].keyval;
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
p[j] = gdk_unicode_to_keyval (uc);
|
|
}
|
|
}
|
|
|
|
if (p[3] == p[2])
|
|
p[3] = 0;
|
|
if (p[2] == p[1])
|
|
p[2] = 0;
|
|
if (p[1] == p[0])
|
|
p[1] = 0;
|
|
if (p[0] == p[2] &&
|
|
p[1] == p[3])
|
|
p[2] = p[3] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_error ("uchr type layouts aren't supported right now");
|
|
}
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (known_keys); i++)
|
|
{
|
|
p = keyval_array + known_keys[i].keycode * KEYVALS_PER_KEYCODE;
|
|
|
|
if (p[0] == 0 && p[1] == 0 &&
|
|
p[2] == 0 && p[3] == 0)
|
|
p[0] = known_keys[i].keyval;
|
|
}
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (known_numeric_keys); i++)
|
|
{
|
|
p = keyval_array + known_numeric_keys[i].keycode * KEYVALS_PER_KEYCODE;
|
|
|
|
if (p[0] == known_numeric_keys[i].normal_keyval);
|
|
p[0] = known_numeric_keys[i].keypad_keyval;
|
|
}
|
|
|
|
if (current_layout)
|
|
g_signal_emit_by_name (default_keymap, "keys_changed");
|
|
|
|
current_layout = new_layout;
|
|
}
|
|
}
|
|
|
|
GdkKeymap *
|
|
gdk_keymap_get_for_display (GdkDisplay *display)
|
|
{
|
|
g_return_val_if_fail (display == gdk_display_get_default (), NULL);
|
|
|
|
if (default_keymap == NULL)
|
|
default_keymap = g_object_new (gdk_keymap_get_type (), NULL);
|
|
|
|
return default_keymap;
|
|
}
|
|
|
|
PangoDirection
|
|
gdk_keymap_get_direction (GdkKeymap *keymap)
|
|
{
|
|
return PANGO_DIRECTION_NEUTRAL;
|
|
}
|
|
|
|
gboolean
|
|
gdk_keymap_get_entries_for_keyval (GdkKeymap *keymap,
|
|
guint keyval,
|
|
GdkKeymapKey **keys,
|
|
gint *n_keys)
|
|
{
|
|
GArray *keys_array;
|
|
int i;
|
|
|
|
g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
|
|
g_return_val_if_fail (keys != NULL, FALSE);
|
|
g_return_val_if_fail (n_keys != NULL, FALSE);
|
|
g_return_val_if_fail (keyval != 0, FALSE);
|
|
|
|
maybe_update_keymap ();
|
|
|
|
*n_keys = 0;
|
|
keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
|
|
|
|
for (i = 0; i < NUM_KEYCODES * KEYVALS_PER_KEYCODE; i++)
|
|
{
|
|
GdkKeymapKey key;
|
|
|
|
if (keyval_array[i] != keyval)
|
|
continue;
|
|
|
|
(*n_keys)++;
|
|
|
|
key.keycode = i / KEYVALS_PER_KEYCODE;
|
|
key.group = 0;
|
|
key.level = i % KEYVALS_PER_KEYCODE;
|
|
|
|
g_array_append_val (keys_array, key);
|
|
}
|
|
|
|
*keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
|
|
|
|
return *n_keys > 0;;
|
|
}
|
|
|
|
gboolean
|
|
gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap,
|
|
guint hardware_keycode,
|
|
GdkKeymapKey **keys,
|
|
guint **keyvals,
|
|
gint *n_entries)
|
|
{
|
|
GArray *keys_array, *keyvals_array;
|
|
int i;
|
|
guint *p;
|
|
|
|
g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
|
|
g_return_val_if_fail (n_entries != NULL, FALSE);
|
|
|
|
maybe_update_keymap ();
|
|
|
|
*n_entries = 0;
|
|
|
|
if (hardware_keycode > NUM_KEYCODES)
|
|
return FALSE;
|
|
|
|
if (keys)
|
|
keys_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
|
|
else
|
|
keys_array = NULL;
|
|
|
|
if (keyvals)
|
|
keyvals_array = g_array_new (FALSE, FALSE, sizeof (guint));
|
|
else
|
|
keyvals_array = NULL;
|
|
|
|
p = keyval_array + hardware_keycode * KEYVALS_PER_KEYCODE;
|
|
|
|
for (i = 0; i < KEYVALS_PER_KEYCODE; i++)
|
|
{
|
|
if (!p[i])
|
|
continue;
|
|
|
|
(*n_entries)++;
|
|
|
|
if (keyvals_array)
|
|
g_array_append_val (keyvals_array, p[i]);
|
|
|
|
if (keys_array)
|
|
{
|
|
GdkKeymapKey key;
|
|
|
|
key.keycode = hardware_keycode;
|
|
key.group = i / 2;
|
|
key.level = i % 2;
|
|
|
|
g_array_append_val (keys_array, key);
|
|
}
|
|
}
|
|
|
|
if (keys)
|
|
*keys = (GdkKeymapKey *)g_array_free (keys_array, FALSE);
|
|
|
|
if (keyvals)
|
|
*keyvals = (guint *)g_array_free (keyvals_array, FALSE);
|
|
|
|
return *n_entries > 0;
|
|
}
|
|
|
|
#define GET_KEYVAL(keycode, group, level) (keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
|
|
|
|
static guint
|
|
translate_keysym (guint hardware_keycode,
|
|
gint group,
|
|
GdkModifierType state,
|
|
guint *effective_group,
|
|
guint *effective_level)
|
|
{
|
|
gint level;
|
|
guint tmp_keyval;
|
|
|
|
level = (state & GDK_SHIFT_MASK) ? 1 : 0;
|
|
|
|
if (!(GET_KEYVAL (hardware_keycode, group, 0) || GET_KEYVAL (hardware_keycode, group, 1)) &&
|
|
(GET_KEYVAL (hardware_keycode, 0, 0) || GET_KEYVAL (hardware_keycode, 0, 1)))
|
|
group = 0;
|
|
|
|
if (!GET_KEYVAL (hardware_keycode, group, level) &&
|
|
GET_KEYVAL (hardware_keycode, group, 0))
|
|
level = 0;
|
|
|
|
tmp_keyval = GET_KEYVAL (hardware_keycode, group, level);
|
|
|
|
if (state & GDK_LOCK_MASK)
|
|
{
|
|
guint upper = gdk_keyval_to_upper (tmp_keyval);
|
|
if (upper != tmp_keyval)
|
|
tmp_keyval = upper;
|
|
}
|
|
|
|
return tmp_keyval;
|
|
}
|
|
|
|
gboolean
|
|
gdk_keymap_translate_keyboard_state (GdkKeymap *keymap,
|
|
guint hardware_keycode,
|
|
GdkModifierType state,
|
|
gint group,
|
|
guint *keyval,
|
|
gint *effective_group,
|
|
gint *level,
|
|
GdkModifierType *consumed_modifiers)
|
|
{
|
|
guint tmp_keyval;
|
|
GdkModifierType bit;
|
|
guint tmp_modifiers = 0;
|
|
|
|
g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
|
|
g_return_val_if_fail (group >= 0 && group <= 1, FALSE);
|
|
|
|
maybe_update_keymap ();
|
|
|
|
if (keyval)
|
|
*keyval = 0;
|
|
if (effective_group)
|
|
*effective_group = 0;
|
|
if (level)
|
|
*level = 0;
|
|
if (consumed_modifiers)
|
|
*consumed_modifiers = 0;
|
|
|
|
if (hardware_keycode < 0 || hardware_keycode >= NUM_KEYCODES)
|
|
return FALSE;
|
|
|
|
/* Check if shift or capslock modify the keyval */
|
|
for (bit = GDK_SHIFT_MASK; bit < GDK_CONTROL_MASK; bit <<= 1)
|
|
{
|
|
if (translate_keysym (hardware_keycode, group, state & ~bit, NULL, NULL) !=
|
|
translate_keysym (hardware_keycode, group, state | bit, NULL, NULL))
|
|
tmp_modifiers |= bit;
|
|
}
|
|
|
|
tmp_keyval = translate_keysym (hardware_keycode, group, state, level, effective_group);
|
|
|
|
if (consumed_modifiers)
|
|
*consumed_modifiers = tmp_modifiers;
|
|
|
|
if (keyval)
|
|
*keyval = tmp_keyval;
|
|
|
|
return TRUE;
|
|
}
|