Files
cpython-source-deps/macosx/tkMacOSXKeyboard.c
2021-03-30 00:54:10 +01:00

970 lines
29 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* tkMacOSXKeyboard.c --
*
* Routines to support keyboard events on the Macintosh.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
* Copyright 2001-2009, Apple Inc.
* Copyright (c) 2005-2009 Daniel A. Steffen <das@users.sourceforge.net>
* Copyright (c) 2020 Marc Culler
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tkMacOSXPrivate.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXConstants.h"
#include "tkMacOSXKeysyms.h"
/*
* About keyboards
* ---------------
* Keyboards are complicated. This long comment is an attempt to provide
* enough information about them to make it possible to read and understand
* the code in this file.
*
* Every key on a keyboard is identified by a number between 0 and 127. In
* macOS, pressing or releasing a key on the keyboard generates an NSEvent of
* type KeyDown, KeyUp or FlagsChanged. The 8-bit identifier of the key that
* was involved in this event is provided in the attribute [NSEvent keyCode].
* Apple also refers to this number as a "Virtual KeyCode". In this file, to
* avoid confusion with other uses of the word keycode, we will refer to this
* key identifier as a "virtual keycode", usually the value of a variable named
* "virtual".
*
* Some of the keys on a keyboard, such as the Shift, Option, Command or
* Control keys, are "modifier" keys. The effect of pressing or releasing a
* key depends on three quantities:
* - which key is being pressed or released
* - which modifier keys are being held down at the moment
* - the current keyboard layout
* If the key is a modifier key then the effect of pressing or releasing it is
* only to change the list of which modifier keys are being held down. Apple
* reports this by sending an NSEvent of type FlagsChanged. X11 reports this
* as a KeyPress or KeyRelease event for the modifier key. Note that there may
* be combinations of modifier key states and key presses which have no effect.
*
* In X11 every meaningful effect from a key action is identified by a 16 bit
* value known as a keysym. Every keysym has an associated string name, also
* known as a keysym. The Tk bind command uses the X11 keysym string to
* specify a key event which should invoke a certain action and it provides the
* numeric and symbolic keysyms to the bound proc as %N and %K respectively.
* An X11 XEvent which reports a KeyPress or KeyRelease does not include the
* keysym. Instead it includes a platform-specific numerical value called a
* keycode which is available to the bound procedure as %k. A platform port of
* Tk must provide functions which convert between keycodes and numerical
* keysyms. Conversion between numerical and symbolic keysyms is provided by
* the generic Tk code, although platforms are allowed to provide their own by
* defining the XKeysymToString and XStringToKeysym functions and undefining
* the macro REDO_KEYSYM_LOOKUP. This macOS port uses the conversion provided
* by the generic code.
*
* When the keyboard focus is on a Tk widget which provides text input, there
* are some X11 KeyPress events which cause text to be inserted. We will call
* these "printable" events. The UCS-32 character stored in the keycode field
* of an XKeyEvent depends on more than the three items above. It may also
* depend on the sequence of keypresses that preceded the one being reported by
* the XKeyEvent. For example, on macOS an <Alt-e> event does not cause text
* to be inserted but a following <a> event causes an accented 'a' to be
* inserted. The events in such a composition sequence, other than the final
* one, are known as "dead-key" events.
*
* MacOS packages the information described above in a different way. Every
* meaningful effect from a key action *other than changing the state of
* modifier keys* is identified by a unicode string which is provided as the
* [NSEvent characters] attribute of a KeyDown or KeyUp event. FlagsChanged
* events do not have characters. In principle, the characters attribute could
* be an arbitrary unicode string but in practice it is always a single UTF-16
* character which we usually store in a variable named keychar. While the
* keychar is a legal unicode code point, it does not necessarily represent a
* glyph. MacOS uses unicode code points in the private-use range 0xF700-0xF8FF
* for non-printable events which have no associated ASCII code point. For
* example, pressing the F2 key generates an NSEvent with the character 0xF705,
* the Backspace key produces 0x7F (ASCII del) and the Delete key produces
* 0xF728.
*
* With the exception of modifier keys, it is possible to translate between
* numerical X11 keysyms and macOS keychars; this file constructs Tcl hash
* tables to do this job, using data defined in the file tkMacOSXKeysyms.h.
* The code here adopts the convention that the keychar of any modifier key
* is MOD_KEYCHAR. Keys which do not appear on any Macintosh keyboard, such
* as the Menu key on PC keyboards, are assigned UNKNOWN_KEYCHAR.
*
* The macosx platform-specific scheme for generating a keycode when mapping an
* NSEvent of type KeyUp, KeyDown or FlagsChanged to an XEvent of type KeyPress
* or KeyRelease is as follows:
* keycode = (virtual << 24) | index << 22 | keychar
* where index is a 2-bit quantity whose bits indicate the state of the Option
* and Shift keys.
*
* A few remarks are in order. First, we are using 32 bits for the keycode and
* we are allowing room for up to 22 bits for the keychar. This means that
* there is enough room in the keycode to hold a UTF-32 character, which only
* requires 21 bits. Second, the KeyCode type for the keycode field in an
* XEvent is currently defined as unsigned int, which was modified from the
* unsigned short used in X11 in order to accomodate macOS. Finally, there is
* no obstruction to generating KeyPress events for keys that represent letters
* which do not exist on the current keyboard layout. And different keyboard
* layouts can assign a given letter to different keys. So we need a
* convention for what value to assign to "virtual" when computing the keycode
* for a generated event. The convention used here is as follows: If there is
* a key on the current keyboard which produces the keychar, use the virtual
* keycode of that key. Otherwise set virtual = NO_VIRTUAL.
*/
/*
* See tkMacOSXPrivate.h for macros and structures related to key event processing.
*/
/*
* Hash tables and array used to translate between various key attributes.
*/
static Tcl_HashTable special2keysym; /* Special virtual keycode to keysym */
static Tcl_HashTable keysym2keycode; /* keysym to XEvent keycode */
static Tcl_HashTable keysym2unichar; /* keysym to unichar */
static Tcl_HashTable unichar2keysym; /* unichar to X11 keysym */
static Tcl_HashTable unichar2xvirtual; /* unichar to virtual with index */
static UniChar xvirtual2unichar[512]; /* virtual with index to unichar */
/*
* Flags.
*/
static BOOL initialized = NO;
static BOOL keyboardChanged = YES;
/*
* Prototypes for static functions used in this file.
*/
static void InitHashTables(void);
static void UpdateKeymaps(void);
static int KeyDataToUnicode(UniChar *uniChars, int maxChars,
UInt16 keyaction, UInt32 virtual, UInt32 modifiers,
UInt32 * deadKeyStatePtr);
#pragma mark TKApplication(TKKeyboard)
@implementation TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification
{
(void)notification;
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#else
(void)notification;
#endif
keyboardChanged = YES;
UpdateKeymaps();
}
@end
#pragma mark -
/*
*----------------------------------------------------------------------
*
* InitHashTables --
*
* Creates hash tables used by some of the functions in this file.
*
* Results:
* None.
*
* Side effects:
* Allocates memory & creates some hash tables.
*
*----------------------------------------------------------------------
*/
static void
InitHashTables(void)
{
Tcl_HashEntry *hPtr;
const KeyInfo *kPtr;
const KeysymInfo *ksPtr;
int dummy, index;
Tcl_InitHashTable(&special2keysym, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&keysym2keycode, TCL_ONE_WORD_KEYS);
for (kPtr = keyArray; kPtr->virtual != 0; kPtr++) {
MacKeycode macKC;
macKC.v.o_s = 0;
hPtr = Tcl_CreateHashEntry(&special2keysym, INT2PTR(kPtr->virtual),
&dummy);
Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym));
hPtr = Tcl_CreateHashEntry(&keysym2keycode, INT2PTR(kPtr->keysym),
&dummy);
macKC.v.virtual = kPtr->virtual;
macKC.v.keychar = kPtr->keychar;
Tcl_SetHashValue(hPtr, INT2PTR(macKC.uint));
/*
* The Carbon framework does not work for finding the unicode character
* of a special key. But that does not depend on the keyboard layout,
* so we can record the information here.
*/
for (index = 3; index >= 0; index--) {
macKC.v.o_s = index;
xvirtual2unichar[macKC.x.xvirtual] = macKC.x.keychar;
}
}
Tcl_InitHashTable(&keysym2unichar, TCL_ONE_WORD_KEYS);
Tcl_InitHashTable(&unichar2keysym, TCL_ONE_WORD_KEYS);
for (ksPtr = keysymTable; ksPtr->keysym != 0; ksPtr++) {
hPtr = Tcl_CreateHashEntry(&keysym2unichar, INT2PTR(ksPtr->keysym),
&dummy);
Tcl_SetHashValue(hPtr, INT2PTR(ksPtr->keycode));
hPtr = Tcl_CreateHashEntry(&unichar2keysym, INT2PTR(ksPtr->keycode),
&dummy);
Tcl_SetHashValue(hPtr, INT2PTR(ksPtr->keysym));
}
UpdateKeymaps();
initialized = YES;
}
/*
*----------------------------------------------------------------------
*
* UpdateKeymaps --
*
* Called when the keyboard changes to update the hash tables that provide
* maps between unicode characters and virtual keycodes with indexes. In
* order for the map from characters to virtual keycodes to be
* well-defined we have to ignore virtual keycodes for keypad keys, since
* each keypad key has the same character as the corresponding key on the
* main keyboard.
*
* Results:
* None.
*
* Side effects:
* Initializes, if necessary, and updates the unichar2xvirtual hash table
* and the xvirtual2unichar array.
*
*----------------------------------------------------------------------
*/
static void
UpdateKeymaps()
{
static Bool keymapInitialized = false;
Tcl_HashEntry *hPtr;
int virtual, index, dummy;
if (!keymapInitialized) {
Tcl_InitHashTable(&unichar2xvirtual, TCL_ONE_WORD_KEYS);
keymapInitialized = true;
} else {
Tcl_DeleteHashTable(&unichar2xvirtual);
Tcl_InitHashTable(&unichar2xvirtual, TCL_ONE_WORD_KEYS);
}
/*
* This loop goes backwards so that a lookup by keychar will provide the
* minimal modifier mask. Simpler combinations will overwrite more complex
* ones when constructing the table.
*/
for (index = 3; index >= 0; index--) {
for (virtual = 0; virtual < 128; virtual++) {
MacKeycode macKC;
macKC.v = (keycode_v) {.virtual = virtual, .o_s = index, .keychar = 0};
int modifiers = INDEX2CARBON(index), result;
UniChar keychar = 0;
result = KeyDataToUnicode(&keychar, 1, kUCKeyActionDown, virtual,
modifiers, NULL);
if (keychar == 0x10) {
/*
* This is a special key, handled in InitHashTables.
*/
continue;
}
macKC.v.keychar = keychar;
if (! ON_KEYPAD(virtual)) {
hPtr = Tcl_CreateHashEntry(&unichar2xvirtual,
INT2PTR(macKC.x.keychar), &dummy);
Tcl_SetHashValue(hPtr, INT2PTR(macKC.x.xvirtual));
}
xvirtual2unichar[macKC.x.xvirtual] = macKC.x.keychar;
}
}
}
/*
*----------------------------------------------------------------------
*
* KeyDataToUnicode --
*
* Given MacOS key event data this function generates the keychar. It
* does this by using OS resources from the Carbon framework. Note that
* the Carbon functions used here are not aware of the keychars in the
* private-use range which macOS now uses for special keys. For those
* keys this function returns 0x10 (ASCII dle).
*
* The parameter deadKeyStatePtr can be NULL, if no deadkey handling is
* needed (which is always the case here).
*
* This function is called in XKeycodeToKeysym and UpdateKeymaps.
*
* Results:
* The number of characters generated if any, 0 if we are waiting for
* another byte of a dead-key sequence.
*
* Side Effects:
* Fills in the uniChars array with a Unicode string.
*
*----------------------------------------------------------------------
*/
static int
KeyDataToUnicode(
UniChar *uniChars,
int maxChars,
UInt16 keyaction,
UInt32 virtual,
UInt32 modifiers,
UInt32 *deadKeyStatePtr)
{
static const void *layoutData = NULL;
static UInt32 keyboardType = 0;
UniCharCount actuallength = 0;
if (keyboardChanged) {
TISInputSourceRef currentKeyboardLayout =
TISCopyCurrentKeyboardLayoutInputSource();
if (currentKeyboardLayout) {
CFDataRef keyLayoutData = (CFDataRef) TISGetInputSourceProperty(
currentKeyboardLayout, kTISPropertyUnicodeKeyLayoutData);
if (keyLayoutData) {
layoutData = CFDataGetBytePtr(keyLayoutData);
keyboardType = LMGetKbdType();
}
CFRelease(currentKeyboardLayout);
}
keyboardChanged = 0;
}
if (layoutData) {
OptionBits options = 0;
UInt32 dummyState;
OSStatus err;
virtual &= 0xFF;
modifiers = (modifiers >> 8) & 0xFF;
if (!deadKeyStatePtr) {
options = kUCKeyTranslateNoDeadKeysMask;
dummyState = 0;
deadKeyStatePtr = &dummyState;
}
err = ChkErr(UCKeyTranslate, layoutData, virtual, keyaction, modifiers,
keyboardType, options, deadKeyStatePtr, maxChars,
&actuallength, uniChars);
if (!actuallength && *deadKeyStatePtr) {
/*
* We are waiting for another key.
*/
return 0;
}
*deadKeyStatePtr = 0;
if (err != noErr) {
actuallength = 0;
}
}
return actuallength;
}
/*
*----------------------------------------------------------------------
*
* XKeycodeToKeysym --
*
* This is a stub function which translates from the keycode used in an
* XEvent to a numerical keysym. On macOS, the display parameter is
* ignored and only the the virtual keycode stored in the .virtual bitfield
* of a MacKeycode.v.
*
* Results:
* Returns the corresponding numerical keysym, or NoSymbol if the keysym
* cannot be found.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
KeySym
XkbKeycodeToKeysym(
TCL_UNUSED(Display *),
unsigned int keycode,
TCL_UNUSED(int),
int index)
{
Tcl_HashEntry *hPtr;
MacKeycode macKC;
int modifiers, result;
UniChar keychar = 0;
if (!initialized) {
InitHashTables();
}
macKC.uint = keycode;
macKC.v.o_s = index;
/*
* First check if the virtual keycode corresponds to a special key, such as
* an Fn function key or Tab, Backspace, Home, End, etc.
*/
hPtr = Tcl_FindHashEntry(&special2keysym, INT2PTR(macKC.v.virtual));
if (hPtr != NULL) {
return (KeySym) Tcl_GetHashValue(hPtr);
}
/*
* If the virtual value in this keycode does not correspond to an actual
* key in the current keyboard layout, try using its keychar to look up a
* keysym.
*/
if (macKC.v.virtual > 127) {
hPtr = Tcl_FindHashEntry(&unichar2keysym, INT2PTR(macKC.v.keychar));
if (hPtr != NULL) {
return (KeySym) Tcl_GetHashValue(hPtr);
}
}
/*
* If the virtual keycode does belong to a key, use the virtual and the
* Option-Shift from index to look up a keychar by using the Carbon
* Framework; then translate the keychar to a keysym using the
* unicode2keysym hash table.
*/
modifiers = INDEX2CARBON(macKC.v.o_s);
result = KeyDataToUnicode(&keychar, 1, kUCKeyActionDown, macKC.v.virtual,
modifiers, NULL);
if (result) {
hPtr = Tcl_FindHashEntry(&unichar2keysym, INT2PTR(keychar));
if (hPtr != NULL) {
return (KeySym) Tcl_GetHashValue(hPtr);
}
}
return NoSymbol;
}
KeySym
XKeycodeToKeysym(
TCL_UNUSED(Display *),
KeyCode keycode,
int index)
{
return XkbKeycodeToKeysym(NULL, keycode, 0, index);
}
/*
*----------------------------------------------------------------------
*
* TkpGetString --
*
* This is a stub function which retrieves the string stored in the
* transchars field of an XEvent and converts it to a Tcl_DString.
*
* Results:
* Returns a pointer to the string value of the DString.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
const char *
TkpGetString(
TCL_UNUSED(TkWindow *), /* Window where event occurred: Needed to get
* input context. */
XEvent *eventPtr, /* X keyboard event. */
Tcl_DString *dsPtr) /* Uninitialized or empty string to hold
* result. */
{
MacKeycode macKC;
char utfChars[8];
int length = 0;
macKC.uint = eventPtr->xkey.keycode;
if (IS_PRINTABLE(macKC.v.keychar)) {
length = TkUniCharToUtf(macKC.v.keychar, utfChars);
}
utfChars[length] = 0;
Tcl_DStringInit(dsPtr);
return Tcl_DStringAppend(dsPtr, utfChars, length);
}
/*
*----------------------------------------------------------------------
*
* XGetModifierMapping --
*
* X11 stub function to get the keycodes used as modifiers. This
* is never called by the macOS port.
*
* Results:
* Returns a newly allocated modifier map.
*
* Side effects:
* Allocates a new modifier map data structure.
*
*----------------------------------------------------------------------
*/
XModifierKeymap *
XGetModifierMapping(
TCL_UNUSED(Display *))
{
XModifierKeymap *modmap;
modmap = (XModifierKeymap *)ckalloc(sizeof(XModifierKeymap));
modmap->max_keypermod = 0;
modmap->modifiermap = NULL;
return modmap;
}
/*
*----------------------------------------------------------------------
*
* XFreeModifiermap --
*
* Deallocates a modifier map that was created by XGetModifierMapping.
* This is also never called by the macOS port.
*
* Results:
* None.
*
* Side effects:
* Frees the datastructure referenced by modmap.
*
*----------------------------------------------------------------------
*/
int
XFreeModifiermap(
XModifierKeymap *modmap)
{
if (modmap->modifiermap != NULL) {
ckfree(modmap->modifiermap);
}
ckfree(modmap);
return Success;
}
/*
*----------------------------------------------------------------------
*
* XKeysymToString, XStringToKeysym --
*
* These X11 stub functions map keysyms to strings & strings to keysyms.
* A platform can do its own conversion by defining these and undefining
* REDO_KEYSYM_LOOKUP. The macOS port defines REDO_KEYSYM_LOOKUP so these
* are never called and Tk does the conversion for us.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
char *
XKeysymToString(
TCL_UNUSED(KeySym))
{
return NULL;
}
KeySym
XStringToKeysym(
TCL_UNUSED(const char *))
{
return NoSymbol;
}
/*
*----------------------------------------------------------------------
*
* XKeysymToKeycode --
*
* This is a stub function which converts a numerical keysym to the
* platform-specific keycode used in a KeyPress or KeyRelease XEvent.
* For macOS the keycode is an unsigned int with bitfields described
* in the definition of the MacKeycode type.
*
* Results:
*
* A macOS KeyCode. See the description of keycodes at the top of this
* file and the definition of the MacKeycode type in tkMacOSXPrivate.h.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
KeyCode
XKeysymToKeycode(
TCL_UNUSED(Display *),
KeySym keysym)
{
Tcl_HashEntry *hPtr;
MacKeycode macKC;
if (!initialized) {
InitHashTables();
}
/*
* First check for a special key.
*/
hPtr = Tcl_FindHashEntry(&keysym2keycode, INT2PTR(keysym));
if (hPtr != NULL) {
return (KeyCode) Tcl_GetHashValue(hPtr);
}
/*
* Initialize the keycode as if the keysym cannot be converted to anything
* else.
*/
macKC.v.virtual = NO_VIRTUAL;
macKC.v.o_s = 0;
macKC.v.keychar = 0;
/*
* If the keysym is recognized fill in the keychar. Also fill in the
* xvirtual field if the key exists on the current keyboard.
*/
hPtr = (Tcl_HashEntry *) Tcl_FindHashEntry(&keysym2unichar,
INT2PTR(keysym));
if (hPtr != NULL) {
unsigned long data = (unsigned long) Tcl_GetHashValue(hPtr);
macKC.x.keychar = (unsigned int) data;
hPtr = Tcl_FindHashEntry(&unichar2xvirtual, INT2PTR(macKC.x.keychar));
if (hPtr != NULL) {
data = (unsigned long) Tcl_GetHashValue(hPtr);
macKC.x.xvirtual = (unsigned int) data;
}
}
return (KeyCode) macKC.uint;
}
/*
*----------------------------------------------------------------------
*
* TkpSetKeycodeAndState --
*
* This function accepts a keysym and an XEvent and sets some fields of
* the XEvent. It is used by the event generate command.
*
* Results:
* None
*
* Side effects:
*
* Modifies the XEvent. Sets the xkey.keycode to a keycode value formatted
* by XKeysymToKeycode and updates the shift and option flags in
* xkey.state if either of those modifiers is required to generate the
* keysym.
*
*----------------------------------------------------------------------
*/
void
TkpSetKeycodeAndState(
TCL_UNUSED(Tk_Window),
KeySym keysym,
XEvent *eventPtr)
{
if (keysym == NoSymbol) {
eventPtr->xkey.keycode = 0;
} else {
int eventIndex = STATE2INDEX(eventPtr->xkey.state);
MacKeycode macKC;
macKC.uint = XKeysymToKeycode(NULL, keysym);
/*
* We have a virtual keycode and a minimal choice for Shift and Option
* modifiers which generates the keychar that corresponds to the
* specified keysym. But we might not have the correct keychar yet,
* because the xEvent may have specified modifiers beyond our minimal
* set. For example, the events described by <Oslash>, <Shift-oslash>,
* <Shift-Option-O> and <Shift-Option-o> should all produce the same
* uppercase Danish O. So we may need to add the extra modifiers and
* do another lookup for the keychar. We don't want to do this for
* special keys, however.
*/
if (macKC.v.o_s != eventIndex) {
macKC.v.o_s |= eventIndex;
}
if (macKC.v.keychar < 0xF700) {
UniChar keychar = macKC.v.keychar;
NSString *str, *lower, *upper;
if (macKC.v.virtual != NO_VIRTUAL) {
macKC.x.keychar = xvirtual2unichar[macKC.x.xvirtual];
} else {
str = [[NSString alloc] initWithCharacters:&keychar length:1];
lower = [str lowercaseString];
upper = [str uppercaseString];
if (![str isEqual: lower]) {
macKC.v.o_s |= INDEX_SHIFT;
}
if (macKC.v.o_s & INDEX_SHIFT) {
macKC.v.keychar = [upper characterAtIndex:0];
}
}
}
eventPtr->xkey.keycode = macKC.uint;
eventPtr->xkey.state |= INDEX2STATE(macKC.v.o_s);
}
}
/*
*----------------------------------------------------------------------
*
* TkpGetKeySym --
*
* This is a stub function called in tkBind.c. Given a KeyPress or
* KeyRelease XEvent, it maps the keycode in the event to a numerical
* keysym.
*
* Results:
* The return value is the keysym corresponding to eventPtr, or NoSymbol
* if no matching keysym could be found.
*
* Side effects:
* In the first call for a given display, calls TkpInitKeymapInfo.
*
*
*----------------------------------------------------------------------
*/
KeySym
TkpGetKeySym(
TkDisplay *dispPtr, /* Display in which to map keycode. */
XEvent *eventPtr) /* Description of X event. */
{
KeySym sym;
int index;
MacKeycode macKC;
macKC.uint = eventPtr->xkey.keycode;
/*
* Refresh the mapping information if it's stale.
*/
if (dispPtr->bindInfoStale) {
TkpInitKeymapInfo(dispPtr);
}
/*
* Modifier key events have a special mac keycode (see tkProcessKeyEvent).
*/
if (macKC.v.keychar == MOD_KEYCHAR) {
switch (macKC.v.virtual) {
case 54:
return XK_Meta_R;
case 55:
return XK_Meta_L;
case 56:
return XK_Shift_L;
case 57:
return XK_Caps_Lock;
case 58:
return XK_Alt_L;
case 59:
return XK_Control_L;
case 60:
return XK_Shift_R;
case 61:
return XK_Alt_R;
case 62:
return XK_Control_R;
case 63:
return XK_Super_L;
default:
return NoSymbol;
}
}
/*
* Figure out which of the four slots in the keymap vector to use for this
* key. Refer to Xlib documentation for more info on how this computation
* works.
*/
index = STATE2INDEX(eventPtr->xkey.state);
if (eventPtr->xkey.state & LockMask) {
index |= INDEX_SHIFT;
}
/*
* First do the straightforward lookup.
*/
sym = XkbKeycodeToKeysym(dispPtr->display, macKC.uint, 0, index);
/*
* Special handling: If the key was shifted because of Lock, which is only
* caps lock on macOS, not shift lock, and if the shifted keysym isn't
* upper-case alphabetic, then switch back to the unshifted keysym.
*/
if ((index & INDEX_SHIFT) && !(eventPtr->xkey.state & ShiftMask)) {
if ((sym == NoSymbol) || !Tcl_UniCharIsUpper(sym)) {
sym = XkbKeycodeToKeysym(dispPtr->display, macKC.uint, 0,
index & ~INDEX_SHIFT);
}
}
/*
* Another bit of special handling: If this is a shifted key and there is
* no keysym defined, then use the keysym for the unshifted key.
*/
if ((index & INDEX_SHIFT) && (sym == NoSymbol)) {
sym = XkbKeycodeToKeysym(dispPtr->display, macKC.uint, 0,
index & ~INDEX_SHIFT);
}
return sym;
}
/*
*--------------------------------------------------------------
*
* TkpInitKeymapInfo --
*
* This procedure initializes fields in the display that pertain
* to modifier keys.
*
* Results:
* None.
*
* Side effects:
* Modifier key information in dispPtr is initialized.
*
*--------------------------------------------------------------
*/
void
TkpInitKeymapInfo(
TkDisplay *dispPtr) /* Display for which to recompute keymap
* information. */
{
dispPtr->bindInfoStale = 0;
/*
* On macOS the caps lock key is always interpreted to mean that alphabetic
* keys become uppercase but other keys do not get shifted. (X11 allows
* a configuration option which makes the caps lock equivalent to holding
* down the shift key.)
* There is no offical "Mode_switch" key.
*/
dispPtr->lockUsage = LU_CAPS;
/* This field is no longer used by tkBind.c */
dispPtr->modeModMask = 0;
/* The Alt and Meta keys are interchanged on Macintosh keyboards compared
* to PC keyboards. These fields could be set to make the Alt key on a PC
* keyboard behave likd an Alt key. That would also require interchanging
* Mod1Mask and Mod2Mask in tkMacOSXKeyEvent.c.
*/
dispPtr->altModMask = 0;
dispPtr->metaModMask = 0;
/*
* The modKeyCodes table lists the keycodes that appear in KeyPress or
* KeyRelease XEvents for modifier keys. In tkBind.c this table is
* searched to determine whether an XEvent corresponds to a modifier key.
*/
if (dispPtr->modKeyCodes != NULL) {
ckfree(dispPtr->modKeyCodes);
}
dispPtr->numModKeyCodes = NUM_MOD_KEYCODES;
dispPtr->modKeyCodes = (KeyCode *)ckalloc(NUM_MOD_KEYCODES * sizeof(KeyCode));
for (int i = 0; i < NUM_MOD_KEYCODES; i++) {
dispPtr->modKeyCodes[i] = XKeysymToKeycode(NULL, modKeyArray[i]);
}
}
/*
*--------------------------------------------------------------
*
* TkMacOSXAddVirtual --
*
* This procedure is an internal utility which accepts an unsigned int
* that has been partially filled as a MacKeycode, having the Option and
* Shift state set in the o_s field and the keychar field set but with the
* virtual keycode blank. It looks up the virtual keycode for the keychar
* (possibly NO_VIRTUAL) and returns an unsigned int which is a complete
* MacKeycode with the looked up virtual keycode added. This is used when
* creating XEvents for the unicode characters which are generated by the
* NSTextInputClient.
*
* Results:
* An unsigned int which is a complete MacKeycode, including a virtual
* keycode which matches the Option-Shift state and keychar.
*
* Side effects:
* None
*
*--------------------------------------------------------------
*/
unsigned
TkMacOSXAddVirtual(
unsigned int keycode)
{
MacKeycode macKC;
Tcl_HashEntry *hPtr;
macKC.uint = keycode;
if (!initialized) {
InitHashTables();
}
hPtr = (Tcl_HashEntry *) Tcl_FindHashEntry(&unichar2xvirtual,
INT2PTR(macKC.v.keychar));
if (hPtr != NULL) {
unsigned long data = (unsigned long) Tcl_GetHashValue(hPtr);
macKC.x.xvirtual = (unsigned int) data;
} else {
macKC.v.virtual = NO_VIRTUAL;
}
return macKC.uint;
}
/*
* Local Variables:
* mode: objc
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/