/*
* Copyright © 2000-2020 Red Hat, Inc.
* Copyright © 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.1 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, see .
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
/* 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
#include
#include
#include "gdkkeysprivate.h"
#include "gdkkeysyms.h"
#include "gdkmacoskeymap-private.h"
struct _GdkMacosKeymap
{
GdkKeymap parent_instance;
};
struct _GdkMacosKeymapClass
{
GdkKeymapClass parent_instance;
};
G_DEFINE_TYPE (GdkMacosKeymap, gdk_macos_keymap, GDK_TYPE_KEYMAP)
/* 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;
#define NUM_KEYCODES 128
#define KEYVALS_PER_KEYCODE 4
#define GET_KEYVAL(keycode, group, level) \
(keyval_array[(keycode * KEYVALS_PER_KEYCODE + group * 2 + level)])
const static struct {
guint keycode;
guint keyval;
unsigned int modmask; /* So we can tell when a mod key is pressed/released */
} modifier_keys[] = {
{ 54, GDK_KEY_Meta_R, NSEventModifierFlagCommand },
{ 55, GDK_KEY_Meta_L, NSEventModifierFlagCommand },
{ 56, GDK_KEY_Shift_L, NSEventModifierFlagShift },
{ 57, GDK_KEY_Caps_Lock, NSEventModifierFlagCapsLock },
{ 58, GDK_KEY_Alt_L, NSEventModifierFlagOption },
{ 59, GDK_KEY_Control_L, NSEventModifierFlagControl },
{ 60, GDK_KEY_Shift_R, NSEventModifierFlagShift },
{ 61, GDK_KEY_Alt_R, NSEventModifierFlagOption },
{ 62, GDK_KEY_Control_R, NSEventModifierFlagControl }
};
const static struct {
guint keycode;
guint keyval;
} function_keys[] = {
{ 122, GDK_KEY_F1 },
{ 120, GDK_KEY_F2 },
{ 99, GDK_KEY_F3 },
{ 118, GDK_KEY_F4 },
{ 96, GDK_KEY_F5 },
{ 97, GDK_KEY_F6 },
{ 98, GDK_KEY_F7 },
{ 100, GDK_KEY_F8 },
{ 101, GDK_KEY_F9 },
{ 109, GDK_KEY_F10 },
{ 103, GDK_KEY_F11 },
{ 111, GDK_KEY_F12 },
{ 105, GDK_KEY_F13 },
{ 107, GDK_KEY_F14 },
{ 113, GDK_KEY_F15 },
{ 106, GDK_KEY_F16 }
};
const static struct {
guint keycode;
guint normal_keyval, keypad_keyval;
} known_numeric_keys[] = {
{ 65, GDK_KEY_period, GDK_KEY_KP_Decimal },
{ 67, GDK_KEY_asterisk, GDK_KEY_KP_Multiply },
{ 69, GDK_KEY_plus, GDK_KEY_KP_Add },
{ 75, GDK_KEY_slash, GDK_KEY_KP_Divide },
{ 76, GDK_KEY_Return, GDK_KEY_KP_Enter },
{ 78, GDK_KEY_minus, GDK_KEY_KP_Subtract },
{ 81, GDK_KEY_equal, GDK_KEY_KP_Equal },
{ 82, GDK_KEY_0, GDK_KEY_KP_0 },
{ 83, GDK_KEY_1, GDK_KEY_KP_1 },
{ 84, GDK_KEY_2, GDK_KEY_KP_2 },
{ 85, GDK_KEY_3, GDK_KEY_KP_3 },
{ 86, GDK_KEY_4, GDK_KEY_KP_4 },
{ 87, GDK_KEY_5, GDK_KEY_KP_5 },
{ 88, GDK_KEY_6, GDK_KEY_KP_6 },
{ 89, GDK_KEY_7, GDK_KEY_KP_7 },
{ 91, GDK_KEY_8, GDK_KEY_KP_8 },
{ 92, GDK_KEY_9, GDK_KEY_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_KEY_Home },
{ 0x0003, GDK_KEY_Return },
{ 0x0004, GDK_KEY_End },
{ 0x0008, GDK_KEY_BackSpace },
{ 0x0009, GDK_KEY_Tab },
{ 0x000b, GDK_KEY_Page_Up },
{ 0x000c, GDK_KEY_Page_Down },
{ 0x000d, GDK_KEY_Return },
{ 0x001b, GDK_KEY_Escape },
{ 0x001c, GDK_KEY_Left },
{ 0x001d, GDK_KEY_Right },
{ 0x001e, GDK_KEY_Up },
{ 0x001f, GDK_KEY_Down },
{ 0x007f, GDK_KEY_Delete },
{ 0xf027, GDK_KEY_dead_acute },
{ 0xf060, GDK_KEY_dead_grave },
{ 0xf300, GDK_KEY_dead_grave },
{ 0xf0b4, GDK_KEY_dead_acute },
{ 0xf301, GDK_KEY_dead_acute },
{ 0xf385, GDK_KEY_dead_acute },
{ 0xf05e, GDK_KEY_dead_circumflex },
{ 0xf2c6, GDK_KEY_dead_circumflex },
{ 0xf302, GDK_KEY_dead_circumflex },
{ 0xf07e, GDK_KEY_dead_tilde },
{ 0xf2dc, GDK_KEY_dead_tilde },
{ 0xf303, GDK_KEY_dead_tilde },
{ 0xf342, GDK_KEY_dead_perispomeni },
{ 0xf0af, GDK_KEY_dead_macron },
{ 0xf304, GDK_KEY_dead_macron },
{ 0xf2d8, GDK_KEY_dead_breve },
{ 0xf306, GDK_KEY_dead_breve },
{ 0xf2d9, GDK_KEY_dead_abovedot },
{ 0xf307, GDK_KEY_dead_abovedot },
{ 0xf0a8, GDK_KEY_dead_diaeresis },
{ 0xf308, GDK_KEY_dead_diaeresis },
{ 0xf2da, GDK_KEY_dead_abovering },
{ 0xf30A, GDK_KEY_dead_abovering },
{ 0xf022, GDK_KEY_dead_doubleacute },
{ 0xf2dd, GDK_KEY_dead_doubleacute },
{ 0xf30B, GDK_KEY_dead_doubleacute },
{ 0xf2c7, GDK_KEY_dead_caron },
{ 0xf30C, GDK_KEY_dead_caron },
{ 0xf0be, GDK_KEY_dead_cedilla },
{ 0xf327, GDK_KEY_dead_cedilla },
{ 0xf2db, GDK_KEY_dead_ogonek },
{ 0xf328, GDK_KEY_dead_ogonek },
{ 0xfe5d, GDK_KEY_dead_iota },
{ 0xf323, GDK_KEY_dead_belowdot },
{ 0xf309, GDK_KEY_dead_hook },
{ 0xf31B, GDK_KEY_dead_horn },
{ 0xf02d, GDK_KEY_dead_stroke },
{ 0xf335, GDK_KEY_dead_stroke },
{ 0xf336, GDK_KEY_dead_stroke },
{ 0xf313, GDK_KEY_dead_abovecomma },
/* { 0xf313, GDK_KEY_dead_psili }, */
{ 0xf314, GDK_KEY_dead_abovereversedcomma },
/* { 0xf314, GDK_KEY_dead_dasia }, */
{ 0xf30F, GDK_KEY_dead_doublegrave },
{ 0xf325, GDK_KEY_dead_belowring },
{ 0xf2cd, GDK_KEY_dead_belowmacron },
{ 0xf331, GDK_KEY_dead_belowmacron },
{ 0xf32D, GDK_KEY_dead_belowcircumflex },
{ 0xf330, GDK_KEY_dead_belowtilde },
{ 0xf32E, GDK_KEY_dead_belowbreve },
{ 0xf324, GDK_KEY_dead_belowdiaeresis },
{ 0xf311, GDK_KEY_dead_invertedbreve },
{ 0xf02c, GDK_KEY_dead_belowcomma },
{ 0xf326, GDK_KEY_dead_belowcomma }
};
static void
gdk_macos_keymap_update (GdkMacosKeymap *self)
{
const void *chr_data = NULL;
guint *p;
int i;
TISInputSourceRef new_layout = TISCopyCurrentKeyboardLayoutInputSource ();
CFDataRef layout_data_ref;
g_free (keyval_array);
keyval_array = g_new0 (guint, NUM_KEYCODES * KEYVALS_PER_KEYCODE);
layout_data_ref = (CFDataRef)TISGetInputSourceProperty (new_layout, kTISPropertyUnicodeKeyLayoutData);
if (layout_data_ref)
chr_data = CFDataGetBytePtr (layout_data_ref);
if (chr_data == NULL)
{
g_error ("cannot get keyboard layout data");
return;
}
for (i = 0; i < NUM_KEYCODES; i++)
{
int j;
UInt32 modifiers[] = {0, shiftKey, optionKey, shiftKey | optionKey};
UniChar chars[4];
UniCharCount nChars;
p = keyval_array + i * KEYVALS_PER_KEYCODE;
for (j = 0; j < KEYVALS_PER_KEYCODE; j++)
{
UInt32 state = 0;
OSStatus err;
UInt16 key_code;
UniChar uc;
key_code = modifiers[j] | i;
err = UCKeyTranslate (chr_data, i, kUCKeyActionDisplay,
(modifiers[j] >> 8) & 0xFF,
LMGetKbdType(),
0,
&state, 4, &nChars, chars);
/* FIXME: Theoretically, we can get multiple UTF-16
* values; we should convert them to proper unicode and
* figure out whether there are really keyboard layouts
* that give us more than one character for one
* keypress.
*/
if (err == noErr && nChars == 1)
{
int k;
gboolean found = FALSE;
/* A few