736 lines
20 KiB
C
736 lines
20 KiB
C
/*
|
||
* tkMacOSXKeyEvent.c --
|
||
*
|
||
* This file implements functions that decode & handle keyboard events on
|
||
* MacOS X.
|
||
*
|
||
* Copyright 2001-2009, Apple Inc.
|
||
* Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
|
||
* Copyright (c) 2012 Adrian Robert.
|
||
* Copyright 2015 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"
|
||
|
||
/*
|
||
#ifdef TK_MAC_DEBUG
|
||
#define TK_MAC_DEBUG_KEYBOARD
|
||
#endif
|
||
*/
|
||
#define NS_KEYLOG 0
|
||
|
||
|
||
static Tk_Window grabWinPtr = NULL;
|
||
/* Current grab window, NULL if no grab. */
|
||
static Tk_Window keyboardGrabWinPtr = NULL;
|
||
/* Current keyboard grab window. */
|
||
static NSWindow *keyboardGrabNSWindow = nil;
|
||
/* NSWindow for the current keyboard grab window. */
|
||
static NSModalSession modalSession = nil;
|
||
|
||
static BOOL processingCompose = NO;
|
||
static BOOL finishedCompose = NO;
|
||
|
||
static int caret_x = 0, caret_y = 0, caret_height = 0;
|
||
|
||
static void setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state);
|
||
static unsigned isFunctionKey(unsigned int code);
|
||
|
||
|
||
#pragma mark TKApplication(TKKeyEvent)
|
||
|
||
@implementation TKApplication(TKKeyEvent)
|
||
|
||
- (NSEvent *) tkProcessKeyEvent: (NSEvent *) theEvent
|
||
{
|
||
#ifdef TK_MAC_DEBUG_EVENTS
|
||
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
|
||
#endif
|
||
NSWindow* w;
|
||
NSEventType type = [theEvent type];
|
||
NSUInteger modifiers, len = 0;
|
||
BOOL repeat = NO;
|
||
unsigned short keyCode;
|
||
NSString *characters = nil, *charactersIgnoringModifiers = nil;
|
||
static NSUInteger savedModifiers = 0;
|
||
static NSMutableArray *nsEvArray;
|
||
|
||
if (nsEvArray == nil)
|
||
{
|
||
nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
|
||
processingCompose = NO;
|
||
}
|
||
|
||
switch (type) {
|
||
case NSKeyUp:
|
||
if (finishedCompose)
|
||
{
|
||
// if we were composing, swallow the last release since we already sent
|
||
finishedCompose = NO;
|
||
return theEvent;
|
||
}
|
||
case NSKeyDown:
|
||
repeat = [theEvent isARepeat];
|
||
characters = [theEvent characters];
|
||
charactersIgnoringModifiers = [theEvent charactersIgnoringModifiers];
|
||
len = [charactersIgnoringModifiers length];
|
||
case NSFlagsChanged:
|
||
modifiers = [theEvent modifierFlags];
|
||
keyCode = [theEvent keyCode];
|
||
// w = [self windowWithWindowNumber:[theEvent windowNumber]];
|
||
w = [theEvent window];
|
||
#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1
|
||
NSLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' code=%u c=%d %@ %d", [self class], self, _cmd, repeat, modifiers, characters, charactersIgnoringModifiers, keyCode,([charactersIgnoringModifiers length] == 0) ? 0 : [charactersIgnoringModifiers characterAtIndex: 0], w, type);
|
||
#endif
|
||
break;
|
||
|
||
default:
|
||
return theEvent; /* Unrecognized key event. */
|
||
}
|
||
|
||
/* Create an Xevent to add to the Tk queue. */
|
||
if (!processingCompose) {
|
||
unsigned int state = 0;
|
||
|
||
if (modifiers & NSAlphaShiftKeyMask) {
|
||
state |= LockMask;
|
||
}
|
||
if (modifiers & NSShiftKeyMask) {
|
||
state |= ShiftMask;
|
||
}
|
||
if (modifiers & NSControlKeyMask) {
|
||
state |= ControlMask;
|
||
}
|
||
if (modifiers & NSCommandKeyMask) {
|
||
state |= Mod1Mask; /* command key */
|
||
}
|
||
if (modifiers & NSAlternateKeyMask) {
|
||
state |= Mod2Mask; /* option key */
|
||
}
|
||
if (modifiers & NSNumericPadKeyMask) {
|
||
state |= Mod3Mask;
|
||
}
|
||
if (modifiers & NSFunctionKeyMask) {
|
||
state |= Mod4Mask;
|
||
}
|
||
|
||
/*
|
||
* The focus must be in the FrontWindow on the Macintosh. We then query Tk
|
||
* to determine the exact Tk window that owns the focus.
|
||
*/
|
||
|
||
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
|
||
Tk_Window tkwin = (Tk_Window) winPtr;
|
||
|
||
if (!tkwin) {
|
||
TkMacOSXDbgMsg("tkwin == NULL");
|
||
return theEvent;
|
||
}
|
||
tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
|
||
if (!tkwin) {
|
||
TkMacOSXDbgMsg("tkwin == NULL");
|
||
return theEvent; /* Give up. No window for this event. */
|
||
}
|
||
|
||
/*
|
||
* If it's a function key, or we have modifiers other than Shift or Alt,
|
||
* pass it straight to Tk. Otherwise we'll send for input processing.
|
||
*/
|
||
int code = (len == 0) ?
|
||
0 : [charactersIgnoringModifiers characterAtIndex: 0];
|
||
if (type != NSKeyDown || isFunctionKey(code)
|
||
|| (len > 0 && state & (ControlMask | Mod1Mask | Mod3Mask | Mod4Mask))) {
|
||
|
||
XEvent xEvent;
|
||
setupXEvent(&xEvent, w, state);
|
||
|
||
if (type == NSFlagsChanged) {
|
||
if (savedModifiers > modifiers) {
|
||
xEvent.xany.type = KeyRelease;
|
||
} else {
|
||
xEvent.xany.type = KeyPress;
|
||
}
|
||
|
||
/*
|
||
* Use special '-1' to signify a special keycode to our platform
|
||
* specific code in tkMacOSXKeyboard.c. This is rather like what
|
||
* happens on Windows.
|
||
*/
|
||
|
||
xEvent.xany.send_event = -1;
|
||
|
||
/*
|
||
* Set keycode (which was zero) to the changed modifier
|
||
*/
|
||
|
||
xEvent.xkey.keycode = (modifiers ^ savedModifiers);
|
||
} else {
|
||
if (type == NSKeyUp || repeat) {
|
||
xEvent.xany.type = KeyRelease;
|
||
} else {
|
||
xEvent.xany.type = KeyPress;
|
||
}
|
||
|
||
/* For command key, take input manager's word so things
|
||
like dvorak / qwerty layout work. */
|
||
if ((modifiers & NSCommandKeyMask) == NSCommandKeyMask
|
||
&& (modifiers & NSAlternateKeyMask) != NSAlternateKeyMask
|
||
&& len > 0 && !isFunctionKey(code)) {
|
||
// head off keycode-based translation in tkMacOSXKeyboard.c
|
||
xEvent.xkey.nbytes = [characters length]; //len
|
||
}
|
||
|
||
if ([characters length] > 0) {
|
||
xEvent.xkey.keycode =
|
||
(keyCode << 16) | (UInt16) [characters characterAtIndex:0];
|
||
if (![characters getCString:xEvent.xkey.trans_chars
|
||
maxLength:XMaxTransChars encoding:NSUTF8StringEncoding]) {
|
||
/* prevent SF bug 2907388 (crash on some composite chars) */
|
||
//PENDING: we might not need this anymore
|
||
TkMacOSXDbgMsg("characters too long");
|
||
return theEvent;
|
||
}
|
||
}
|
||
|
||
if (repeat) {
|
||
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
|
||
xEvent.xany.type = KeyPress;
|
||
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
|
||
}
|
||
}
|
||
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
|
||
savedModifiers = modifiers;
|
||
return theEvent;
|
||
} /* if send straight to TK */
|
||
|
||
} /* if not processing compose */
|
||
|
||
if (type == NSKeyDown) {
|
||
if (NS_KEYLOG)
|
||
fprintf (stderr, "keyDown: %s compose sequence.\n",
|
||
processingCompose == YES ? "Continue" : "Begin");
|
||
processingCompose = YES;
|
||
[nsEvArray addObject: theEvent];
|
||
[[w contentView] interpretKeyEvents: nsEvArray];
|
||
[nsEvArray removeObject: theEvent];
|
||
}
|
||
|
||
savedModifiers = modifiers;
|
||
|
||
return theEvent;
|
||
}
|
||
@end
|
||
|
||
|
||
|
||
@implementation TKContentView
|
||
/* <NSTextInput> implementation (called through interpretKeyEvents:]). */
|
||
|
||
/* <NSTextInput>: called when done composing;
|
||
NOTE: also called when we delete over working text, followed immed.
|
||
by doCommandBySelector: deleteBackward: */
|
||
- (void)insertText: (id)aString
|
||
{
|
||
int i, len = [(NSString *)aString length];
|
||
XEvent xEvent;
|
||
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
|
||
Tk_Window tkwin = (Tk_Window) winPtr;
|
||
|
||
if (NS_KEYLOG)
|
||
NSLog (@"insertText '%@'\tlen = %d", aString, len);
|
||
processingCompose = NO;
|
||
finishedCompose = YES;
|
||
|
||
/* first, clear any working text */
|
||
if (privateWorkingText != nil)
|
||
[self deleteWorkingText];
|
||
|
||
/* now insert the string as keystrokes */
|
||
setupXEvent(&xEvent, [self window], 0);
|
||
xEvent.xany.type = KeyPress;
|
||
|
||
for (i =0; i<len; i++)
|
||
{
|
||
xEvent.xkey.keycode = (UInt16) [aString characterAtIndex: i];
|
||
[[aString substringWithRange: NSMakeRange(i,1)]
|
||
getCString: xEvent.xkey.trans_chars
|
||
maxLength: XMaxTransChars encoding: NSUTF8StringEncoding];
|
||
xEvent.xkey.nbytes = strlen(xEvent.xkey.trans_chars);
|
||
xEvent.xany.type = KeyPress;
|
||
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
|
||
|
||
xEvent.xany.type = KeyRelease;
|
||
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
|
||
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
|
||
xEvent.xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
|
||
}
|
||
}
|
||
|
||
|
||
/* <NSTextInput>: inserts display of composing characters */
|
||
- (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
|
||
{
|
||
NSString *str = [aString respondsToSelector: @selector (string)] ?
|
||
[aString string] : aString;
|
||
if (NS_KEYLOG)
|
||
NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu", str,
|
||
(unsigned long) [str length], (unsigned long) selRange.length,
|
||
(unsigned long) selRange.location);
|
||
|
||
if (privateWorkingText != nil)
|
||
[self deleteWorkingText];
|
||
if ([str length] == 0)
|
||
return;
|
||
|
||
processingCompose = YES;
|
||
privateWorkingText = [str copy];
|
||
|
||
//PENDING: insert workingText underlined
|
||
}
|
||
|
||
|
||
- (BOOL)hasMarkedText
|
||
{
|
||
return privateWorkingText != nil;
|
||
}
|
||
|
||
|
||
- (NSRange)markedRange
|
||
{
|
||
NSRange rng = privateWorkingText != nil
|
||
? NSMakeRange (0, [privateWorkingText length]) : NSMakeRange (NSNotFound, 0);
|
||
if (NS_KEYLOG)
|
||
NSLog (@"markedRange request");
|
||
return rng;
|
||
}
|
||
|
||
|
||
- (void)unmarkText
|
||
{
|
||
if (NS_KEYLOG)
|
||
NSLog (@"unmark (accept) text");
|
||
[self deleteWorkingText];
|
||
processingCompose = NO;
|
||
}
|
||
|
||
|
||
/* used to position char selection windows, etc. */
|
||
- (NSRect)firstRectForCharacterRange: (NSRange)theRange
|
||
{
|
||
NSRect rect;
|
||
NSPoint pt;
|
||
|
||
pt.x = caret_x;
|
||
pt.y = caret_y;
|
||
|
||
pt = [self convertPoint: pt toView: nil];
|
||
pt = [[self window] convertPointToScreen: pt];
|
||
pt.y -= caret_height;
|
||
|
||
rect.origin = pt;
|
||
rect.size.width = caret_height;
|
||
rect.size.height = caret_height;
|
||
return rect;
|
||
}
|
||
|
||
|
||
- (NSInteger)conversationIdentifier
|
||
{
|
||
return (NSInteger)self;
|
||
}
|
||
|
||
|
||
- (void)doCommandBySelector: (SEL)aSelector
|
||
{
|
||
if (NS_KEYLOG)
|
||
NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
|
||
processingCompose = NO;
|
||
if (aSelector == @selector (deleteBackward:))
|
||
{
|
||
/* happens when user backspaces over an ongoing composition:
|
||
throw a 'delete' into the event queue */
|
||
XEvent xEvent;
|
||
setupXEvent(&xEvent, [self window], 0);
|
||
xEvent.xany.type = KeyPress;
|
||
xEvent.xkey.nbytes = 1;
|
||
xEvent.xkey.keycode = (0x33 << 16) | 0x7F;
|
||
xEvent.xkey.trans_chars[0] = 0x7F;
|
||
xEvent.xkey.trans_chars[1] = 0x0;
|
||
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
|
||
}
|
||
}
|
||
|
||
|
||
- (NSArray *)validAttributesForMarkedText
|
||
{
|
||
static NSArray *arr = nil;
|
||
if (arr == nil) arr = [NSArray new];
|
||
/* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
|
||
return arr;
|
||
}
|
||
|
||
|
||
- (NSRange)selectedRange
|
||
{
|
||
if (NS_KEYLOG)
|
||
NSLog (@"selectedRange request");
|
||
return NSMakeRange (NSNotFound, 0);
|
||
}
|
||
|
||
|
||
- (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
|
||
{
|
||
if (NS_KEYLOG)
|
||
NSLog (@"characterIndexForPoint request");
|
||
return 0;
|
||
}
|
||
|
||
|
||
- (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
|
||
{
|
||
static NSAttributedString *str = nil;
|
||
if (str == nil) str = [NSAttributedString new];
|
||
if (NS_KEYLOG)
|
||
NSLog (@"attributedSubstringFromRange request");
|
||
return str;
|
||
}
|
||
/* End <NSTextInput> impl. */
|
||
@end
|
||
|
||
|
||
@implementation TKContentView(TKKeyEvent)
|
||
/* delete display of composing characters [not in <NSTextInput>] */
|
||
- (void)deleteWorkingText
|
||
{
|
||
if (privateWorkingText == nil)
|
||
return;
|
||
if (NS_KEYLOG)
|
||
NSLog(@"deleteWorkingText len = %lu\n",
|
||
(unsigned long)[privateWorkingText length]);
|
||
[privateWorkingText release];
|
||
privateWorkingText = nil;
|
||
processingCompose = NO;
|
||
|
||
//PENDING: delete working text
|
||
}
|
||
@end
|
||
|
||
|
||
|
||
/*
|
||
* Set up basic fields in xevent for keyboard input.
|
||
*/
|
||
static void
|
||
setupXEvent(XEvent *xEvent, NSWindow *w, unsigned int state)
|
||
{
|
||
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
|
||
Tk_Window tkwin = (Tk_Window) winPtr;
|
||
|
||
memset(xEvent, 0, sizeof(XEvent));
|
||
xEvent->xany.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
|
||
xEvent->xany.send_event = false;
|
||
xEvent->xany.display = Tk_Display(tkwin);
|
||
xEvent->xany.window = Tk_WindowId(tkwin);
|
||
|
||
xEvent->xkey.root = XRootWindow(Tk_Display(tkwin), 0);
|
||
xEvent->xkey.subwindow = None;
|
||
xEvent->xkey.time = TkpGetMS();
|
||
xEvent->xkey.state = state;
|
||
xEvent->xkey.same_screen = true;
|
||
xEvent->xkey.trans_chars[0] = 0;
|
||
xEvent->xkey.nbytes = 0;
|
||
}
|
||
|
||
#pragma mark -
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* XGrabKeyboard --
|
||
*
|
||
* Simulates a keyboard grab by setting the focus.
|
||
*
|
||
* Results:
|
||
* Always returns GrabSuccess.
|
||
*
|
||
* Side effects:
|
||
* Sets the keyboard focus to the specified window.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
XGrabKeyboard(
|
||
Display* display,
|
||
Window grab_window,
|
||
Bool owner_events,
|
||
int pointer_mode,
|
||
int keyboard_mode,
|
||
Time time)
|
||
{
|
||
keyboardGrabWinPtr = Tk_IdToWindow(display, grab_window);
|
||
if (keyboardGrabWinPtr && grabWinPtr) {
|
||
NSWindow *w = TkMacOSXDrawableWindow(grab_window);
|
||
MacDrawable *macWin = (MacDrawable *) grab_window;
|
||
|
||
if (w && macWin->toplevel->winPtr == (TkWindow*) grabWinPtr) {
|
||
if (modalSession) {
|
||
Tcl_Panic("XGrabKeyboard: already grabbed");
|
||
}
|
||
keyboardGrabNSWindow = w;
|
||
[w retain];
|
||
modalSession = [NSApp beginModalSessionForWindow:w];
|
||
}
|
||
}
|
||
return GrabSuccess;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* XUngrabKeyboard --
|
||
*
|
||
* Releases the simulated keyboard grab.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Sets the keyboard focus back to the value before the grab.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
XUngrabKeyboard(
|
||
Display* display,
|
||
Time time)
|
||
{
|
||
if (modalSession) {
|
||
[NSApp endModalSession:modalSession];
|
||
modalSession = nil;
|
||
}
|
||
if (keyboardGrabNSWindow) {
|
||
[keyboardGrabNSWindow release];
|
||
keyboardGrabNSWindow = nil;
|
||
}
|
||
keyboardGrabWinPtr = NULL;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkMacOSXGetCapture --
|
||
*
|
||
* Results:
|
||
* Returns the current grab window
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
Tk_Window
|
||
TkMacOSXGetCapture(void)
|
||
{
|
||
return grabWinPtr;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkMacOSXGetModalSession --
|
||
*
|
||
* Results:
|
||
* Returns the current modal session
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
MODULE_SCOPE NSModalSession
|
||
TkMacOSXGetModalSession(void)
|
||
{
|
||
return modalSession;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* TkpSetCapture --
|
||
*
|
||
* This function captures the mouse so that all future events will be
|
||
* reported to this window, even if the mouse is outside the window. If
|
||
* the specified window is NULL, then the mouse is released.
|
||
*
|
||
* Results:
|
||
* None.
|
||
*
|
||
* Side effects:
|
||
* Sets the capture flag and captures the mouse.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
TkpSetCapture(
|
||
TkWindow *winPtr) /* Capture window, or NULL. */
|
||
{
|
||
while (winPtr && !Tk_IsTopLevel(winPtr)) {
|
||
winPtr = winPtr->parentPtr;
|
||
}
|
||
grabWinPtr = (Tk_Window) winPtr;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* Tk_SetCaretPos --
|
||
*
|
||
* This enables correct placement of the XIM caret. This is called by
|
||
* widgets to indicate their cursor placement, and the caret location is
|
||
* used by TkpGetString to place the XIM caret.
|
||
*
|
||
* Results:
|
||
* None
|
||
*
|
||
* Side effects:
|
||
* None
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
void
|
||
Tk_SetCaretPos(
|
||
Tk_Window tkwin,
|
||
int x,
|
||
int y,
|
||
int height)
|
||
{
|
||
TkCaret *caretPtr = &(((TkWindow *) tkwin)->dispPtr->caret);
|
||
|
||
/*
|
||
* Prevent processing anything if the values haven't changed. Windows only
|
||
* has one display, so we can do this with statics.
|
||
*/
|
||
|
||
if ((caretPtr->winPtr == ((TkWindow *) tkwin))
|
||
&& (caretPtr->x == x) && (caretPtr->y == y)) {
|
||
return;
|
||
}
|
||
|
||
caretPtr->winPtr = ((TkWindow *) tkwin);
|
||
caretPtr->x = x;
|
||
caretPtr->y = y;
|
||
caretPtr->height = height;
|
||
|
||
/*
|
||
* As in Windows, adjust to the toplevel to get the coords right.
|
||
*/
|
||
|
||
while (!Tk_IsTopLevel(tkwin)) {
|
||
x += Tk_X(tkwin);
|
||
y += Tk_Y(tkwin);
|
||
tkwin = Tk_Parent(tkwin);
|
||
if (tkwin == NULL) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
/* But adjust for fact that NS uses flipped view. */
|
||
y = Tk_Height(tkwin) - y;
|
||
|
||
caret_x = x;
|
||
caret_y = y;
|
||
caret_height = height;
|
||
}
|
||
|
||
|
||
static unsigned convert_ns_to_X_keysym[] =
|
||
{
|
||
NSHomeFunctionKey, 0x50,
|
||
NSLeftArrowFunctionKey, 0x51,
|
||
NSUpArrowFunctionKey, 0x52,
|
||
NSRightArrowFunctionKey, 0x53,
|
||
NSDownArrowFunctionKey, 0x54,
|
||
NSPageUpFunctionKey, 0x55,
|
||
NSPageDownFunctionKey, 0x56,
|
||
NSEndFunctionKey, 0x57,
|
||
NSBeginFunctionKey, 0x58,
|
||
NSSelectFunctionKey, 0x60,
|
||
NSPrintFunctionKey, 0x61,
|
||
NSExecuteFunctionKey, 0x62,
|
||
NSInsertFunctionKey, 0x63,
|
||
NSUndoFunctionKey, 0x65,
|
||
NSRedoFunctionKey, 0x66,
|
||
NSMenuFunctionKey, 0x67,
|
||
NSFindFunctionKey, 0x68,
|
||
NSHelpFunctionKey, 0x6A,
|
||
NSBreakFunctionKey, 0x6B,
|
||
|
||
NSF1FunctionKey, 0xBE,
|
||
NSF2FunctionKey, 0xBF,
|
||
NSF3FunctionKey, 0xC0,
|
||
NSF4FunctionKey, 0xC1,
|
||
NSF5FunctionKey, 0xC2,
|
||
NSF6FunctionKey, 0xC3,
|
||
NSF7FunctionKey, 0xC4,
|
||
NSF8FunctionKey, 0xC5,
|
||
NSF9FunctionKey, 0xC6,
|
||
NSF10FunctionKey, 0xC7,
|
||
NSF11FunctionKey, 0xC8,
|
||
NSF12FunctionKey, 0xC9,
|
||
NSF13FunctionKey, 0xCA,
|
||
NSF14FunctionKey, 0xCB,
|
||
NSF15FunctionKey, 0xCC,
|
||
NSF16FunctionKey, 0xCD,
|
||
NSF17FunctionKey, 0xCE,
|
||
NSF18FunctionKey, 0xCF,
|
||
NSF19FunctionKey, 0xD0,
|
||
NSF20FunctionKey, 0xD1,
|
||
NSF21FunctionKey, 0xD2,
|
||
NSF22FunctionKey, 0xD3,
|
||
NSF23FunctionKey, 0xD4,
|
||
NSF24FunctionKey, 0xD5,
|
||
|
||
NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
|
||
NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
|
||
NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
|
||
|
||
NSTabCharacter, 0x09,
|
||
0x19, 0x09, /* left tab->regular since pass shift */
|
||
NSCarriageReturnCharacter, 0x0D,
|
||
NSNewlineCharacter, 0x0D,
|
||
NSEnterCharacter, 0x8D,
|
||
|
||
0x1B, 0x1B /* escape */
|
||
};
|
||
|
||
|
||
static unsigned isFunctionKey(unsigned code)
|
||
{
|
||
const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
|
||
/ sizeof (convert_ns_to_X_keysym[0]));
|
||
unsigned keysym;
|
||
for (keysym = 0; keysym < last_keysym; keysym += 2)
|
||
if (code == convert_ns_to_X_keysym[keysym])
|
||
return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* Local Variables:
|
||
* mode: objc
|
||
* c-basic-offset: 4
|
||
* fill-column: 79
|
||
* coding: utf-8
|
||
* End:
|
||
*/
|