summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXKeyEvent.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXKeyEvent.c')
-rw-r--r--macosx/tkMacOSXKeyEvent.c853
1 files changed, 572 insertions, 281 deletions
diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c
index 78a37eb..eee1844 100644
--- a/macosx/tkMacOSXKeyEvent.c
+++ b/macosx/tkMacOSXKeyEvent.c
@@ -1,7 +1,7 @@
/*
* tkMacOSXKeyEvent.c --
*
- * This file implements functions that decode & handle keyboard events
+ * This file implements functions that decode & handle keyboard events
* on MacOS X.
*
* Copyright 2001, Apple Computer, Inc.
@@ -66,35 +66,51 @@ typedef struct {
UInt32 message;
} KeyEventData;
-static Tk_Window gGrabWinPtr = NULL; /* Current grab window, NULL if no grab. */
+static Tk_Window gGrabWinPtr = NULL; /* Current grab window,
+ * NULL if no grab. */
static Tk_Window gKeyboardWinPtr = NULL; /* Current keyboard grab window. */
-static UInt32 deadKeyState = 0;
+static UInt32 deadKeyStateUp = 0; /* The deadkey state for the current
+ * sequence of keyup events or 0 if
+ * not in a deadkey sequence */
+static UInt32 deadKeyStateDown = 0; /* Ditto for keydown */
/*
* Declarations for functions used only in this file.
*/
-static int GenerateKeyEvent _ANSI_ARGS_(( EventKind eKind,
+static int InitKeyData(
+ KeyEventData * keyEventDataPtr);
+
+static int InitKeyEvent(
+ XEvent * eventPtr,
KeyEventData * e,
- Window window,
UInt32 savedKeyCode,
- UInt32 savedModifiers));
+ UInt32 savedModifiers);
+static int GenerateKeyEvent (
+ UInt32 eKind,
+ KeyEventData * e,
+ UInt32 savedKeyCode,
+ UInt32 savedModifiers,
+ const UniChar * chars, int numChars);
static int GetKeyboardLayout (
- Ptr * resource );
-
-static int DecodeViaUnicodeResource(
- Ptr uchr,
- EventKind eKind,
- const KeyEventData * e,
- XEvent * event );
-static int DecodeViaKCHRResource(
- Ptr kchr,
- const KeyEventData * e,
- XEvent * event );
-
+ Ptr * resource);
+
+static int KeycodeToUnicodeViaUnicodeResource(
+ UniChar * uniChars, int maxChars,
+ Ptr uchr,
+ EventKind eKind,
+ UInt32 keycode, UInt32 modifiers,
+ UInt32 * deadKeyStatePtr);
+
+static int KeycodeToUnicodeViaKCHRResource(
+ UniChar * uniChars, int maxChars,
+ Ptr kchr,
+ EventKind eKind,
+ UInt32 keycode, UInt32 modifiers,
+ UInt32 * deadKeyStatePtr);
/*
*----------------------------------------------------------------------
@@ -119,22 +135,22 @@ int TkMacOSXProcessKeyboardEvent(
{
static UInt32 savedKeyCode = 0;
static UInt32 savedModifiers = 0;
+ static UniChar savedChar = 0;
OSStatus status;
KeyEventData keyEventData;
- Window window;
+#if 0
MenuRef menuRef;
MenuItemIndex menuItemIndex;
+#endif
int eventGenerated;
-
- statusPtr->handledByTk = 1;
- keyEventData.whichWindow = FrontNonFloatingWindow();
- if (keyEventData.whichWindow == NULL) {
- return 0;
+ UniChar uniChars[5]; /* make this larger, if needed */
+ UInt32 uniCharsLen;
+
+ if (!InitKeyData(&keyEventData)) {
+ statusPtr->err = 1;
+ return false;
}
- GetMouse(&keyEventData.local);
- keyEventData.global = keyEventData.local;
- LocalToGlobal(&keyEventData.global);
- keyEventData.state = TkMacOSXButtonKeyState();
+
#if 0
/*
* This block of code seems like a good idea, to trap
@@ -163,7 +179,7 @@ int TkMacOSXProcessKeyboardEvent(
int selection;
menuID = GetMenuID(menuRef);
- selection = (menuID << 16 ) | menuItemIndex;
+ selection = (menuID << 16) | menuItemIndex;
GetKeys(theKeys);
oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
@@ -173,10 +189,10 @@ int TkMacOSXProcessKeyboardEvent(
* Handle -postcommand
*/
- TkMacOSXPreprocessMenu();
- TkMacOSXHandleMenuSelect(selection, theKeys[1] & 4);
- Tcl_SetServiceMode(oldMode);
- return 0; /* TODO: may not be on event on queue. */
+ TkMacOSXPreprocessMenu();
+ TkMacOSXHandleMenuSelect(selection, theKeys[1] & 4);
+ Tcl_SetServiceMode(oldMode);
+ return 0; /* TODO: may not be on event on queue. */
}
#endif
@@ -186,9 +202,9 @@ int TkMacOSXProcessKeyboardEvent(
sizeof(keyEventData.ch), NULL,
&keyEventData.ch);
if (status != noErr) {
- fprintf(stderr, "Failed to retrieve KeyMacCharCodes\n" );
+ fprintf (stderr, "Failed to retrieve KeyMacCharCodes\n");
statusPtr->err = 1;
- return 1;
+ return false;
}
status = GetEventParameter(eventPtr->eventRef,
kEventParamKeyCode,
@@ -196,9 +212,9 @@ int TkMacOSXProcessKeyboardEvent(
sizeof(keyEventData.keyCode), NULL,
&keyEventData.keyCode);
if (status != noErr) {
- fprintf(stderr, "Failed to retrieve KeyCode\n" );
+ fprintf (stderr, "Failed to retrieve KeyCode\n");
statusPtr->err = 1;
- return 1;
+ return false;
}
status = GetEventParameter(eventPtr->eventRef,
kEventParamKeyModifiers,
@@ -206,43 +222,102 @@ int TkMacOSXProcessKeyboardEvent(
sizeof(keyEventData.keyModifiers), NULL,
&keyEventData.keyModifiers);
if (status != noErr) {
- fprintf(stderr, "Failed to retrieve KeyModifiers\n" );
+ fprintf (stderr, "Failed to retrieve KeyModifiers\n");
statusPtr->err = 1;
- return 1;
+ return false;
+ }
+
+ switch (eventPtr->eKind) {
+ case kEventRawKeyUp:
+ case kEventRawKeyDown:
+ case kEventRawKeyRepeat:
+ {
+ UInt32 *deadKeyStatePtr;
+
+ if (kEventRawKeyDown == eventPtr->eKind) {
+ deadKeyStatePtr = &deadKeyStateDown;
+ } else {
+ deadKeyStatePtr = &deadKeyStateUp;
+ }
+
+ uniCharsLen = TkMacOSXKeycodeToUnicode(
+ uniChars, sizeof(uniChars)/sizeof(*uniChars),
+ eventPtr->eKind,
+ keyEventData.keyCode, keyEventData.keyModifiers,
+ deadKeyStatePtr);
+ }
+ }
+
+ if (kEventRawKeyUp == eventPtr->eKind) {
+ /*
+ * For some reason the deadkey processing for KeyUp doesn't work
+ * sometimes, so we fudge and use the last detected KeyDown.
+ */
+
+ if((0 == uniCharsLen) && (0 != savedChar)) {
+ uniChars[0] = savedChar;
+ uniCharsLen = 1;
+ }
+
+ /*
+ * Suppress keyup events while we have a deadkey sequence on keydown.
+ * We still *do* want to collect deadkey state in this situation if
+ * the system provides it, that's why we do this only after
+ * TkMacOSXKeycodeToUnicode().
+ */
+
+ if (0 != deadKeyStateDown) {
+ uniCharsLen = 0;
+ }
}
+
keyEventData.message = keyEventData.ch|(keyEventData.keyCode << 8);
- window = TkMacOSXGetXWindow(keyEventData.whichWindow);
-
- eventGenerated = GenerateKeyEvent(eventPtr->eKind, &keyEventData,
- window, savedKeyCode, savedModifiers);
+ eventGenerated = GenerateKeyEvent(
+ eventPtr->eKind, &keyEventData,
+ savedKeyCode, savedModifiers,
+ uniChars, uniCharsLen);
+
savedModifiers = keyEventData.keyModifiers;
+
+ if ((kEventRawKeyDown == eventPtr->eKind) && (uniCharsLen > 0)) {
+ savedChar = uniChars[0];
+ } else {
+ savedChar = 0;
+ }
+ statusPtr->stopProcessing = 1;
+
if (eventGenerated == 0) {
- savedKeyCode = keyEventData.message;
- return false;
+ savedKeyCode = keyEventData.message;
+ return false;
} else if (eventGenerated == -1) {
- savedKeyCode = 0;
- return false;
+ savedKeyCode = 0;
+ statusPtr->stopProcessing = 0;
+ return false;
} else {
- savedKeyCode = 0;
- return true;
+ savedKeyCode = 0;
+ return true;
}
}
-
+
/*
*----------------------------------------------------------------------
*
* GenerateKeyEvent --
*
- * Given Macintosh keyUp, keyDown & autoKey events this function
- * generates the appropiate X key events. The window that is passed
- * should represent the frontmost window - which will recieve the
- * event.
+ * Given Macintosh keyUp, keyDown & autoKey events (in their "raw"
+ * form) and a list of unicode characters this function generates the
+ * appropriate X key events.
+ *
+ * Parameter eKind is a raw keyboard event. e contains the data sent
+ * with the event. savedKeyCode and savedModifiers contain the values
+ * from the last event that came before (see
+ * TkMacOSXProcessKeyboardEvent()). chars/numChars has the Unicode
+ * characters for which we want to create events.
*
* Results:
- * 1 if an event was generated, 0 if we are waiting for another
- * byte of a multi-byte sequence, and -1 for any other error.
+ * 1 if an event was generated, -1 for any error.
*
* Side effects:
* Additional events may be place on the Tk event queue.
@@ -251,14 +326,173 @@ int TkMacOSXProcessKeyboardEvent(
*/
static int
-GenerateKeyEvent( EventKind eKind,
+GenerateKeyEvent(
+ UInt32 eKind,
KeyEventData * e,
- Window window,
UInt32 savedKeyCode,
- UInt32 savedModifiers )
+ UInt32 savedModifiers,
+ const UniChar * chars, int numChars)
{
- Tk_Window tkwin;
XEvent event;
+ int i;
+
+ if (-1 == InitKeyEvent(&event, e, savedKeyCode, savedModifiers)) {
+ return -1;
+ }
+
+ if (kEventRawKeyModifiersChanged == eKind) {
+
+ if (savedModifiers > e->keyModifiers) {
+ event.xany.type = KeyRelease;
+ } else {
+ event.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.
+ */
+
+ event.xany.send_event = -1;
+
+ /*
+ * Set keycode (which was zero) to the changed modifier
+ */
+
+ event.xkey.keycode = (e->keyModifiers ^ savedModifiers);
+ Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+
+ } else {
+
+ for (i=0; i<numChars; ++i) {
+
+ /*
+ * Encode one char in the trans_chars array that was already
+ * introduced for MS Windows. Don't encode the string, if it is
+ * a control character but was not generated with a real control
+ * modifier. Such control characters get generated by KeyTrans()
+ * for special keys, but we rather want to identify those by
+ * their KeySyms.
+ */
+
+ event.xkey.trans_chars[0] = 0;
+ if ((controlKey & e->keyModifiers) || (chars[i] >= ' ')) {
+ int done;
+ done = Tcl_UniCharToUtf(chars[i],event.xkey.trans_chars);
+ event.xkey.trans_chars[done] = 0;
+ }
+
+ switch(eKind) {
+ case kEventRawKeyDown:
+ event.xany.type = KeyPress;
+ Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+ break;
+ case kEventRawKeyUp:
+ event.xany.type = KeyRelease;
+ Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+ break;
+ case kEventRawKeyRepeat:
+ event.xany.type = KeyRelease;
+ Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+ event.xany.type = KeyPress;
+ Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
+ break;
+ default:
+ fprintf (stderr,
+ "GenerateKeyEvent(): Invalid parameter eKind %d\n",
+ (int) eKind);
+ return -1;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * InitKeyData --
+ *
+ * This routine initializes a KeyEventData structure by asking the OS
+ * and Tk for all the global information needed here.
+ *
+ * Results:
+ * True if the current front window can be found in Tk data structures
+ * - false otherwise.
+ *
+ * Side Effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+InitKeyData(KeyEventData * keyEventDataPtr)
+{
+ memset (keyEventDataPtr, 0, sizeof(*keyEventDataPtr));
+
+ keyEventDataPtr->whichWindow = FrontNonFloatingWindow();
+ if (keyEventDataPtr->whichWindow == NULL) {
+ return false;
+ }
+ GetMouse(&keyEventDataPtr->local);
+ keyEventDataPtr->global = keyEventDataPtr->local;
+ LocalToGlobal(&keyEventDataPtr->global);
+ keyEventDataPtr->state = TkMacOSXButtonKeyState();
+
+ return true;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * InitKeyEvent --
+ *
+ * Initialize an XEvent structure by asking Tk for global information.
+ * Also uses a KeyEventData structure and other current state.
+ *
+ * Results:
+ * 1 on success, -1 for any error.
+ *
+ * Side effects:
+ * Additional events may be place on the Tk event queue.
+ *
+ *----------------------------------------------------------------------
+ */
+
+/*
+ * We have a general problem here. How do we handle 'Option-char'
+ * keypresses? The problem is that we might want to bind to some of these
+ * (e.g. Cmd-Opt-d is 'uncomment' in Alpha). OTOH Option-d actually produces
+ * a real character on MacOS, namely a mathematical delta.
+ *
+ * The current behaviour is that a binding goes by the combinations of
+ * modifiers and base keysym, that is Option-d. The string value of the
+ * event is the mathematical delta character, so if no binding calls
+ * [break], the text widget will insert that character.
+ *
+ * Note that this is similar to control combinations on all platforms. They
+ * also generate events that have the base character as keysym and a real
+ * control character as character value. So Ctrl+C gets us the keysym XK_C,
+ * the modifier Control (so you can bind <Control-C>) and a string value as
+ * "\u0003".
+ *
+ * For a different solutions we may want for the event to contain keysyms for
+ * *both* the 'Opt-d' side of things and the mathematical delta. Then a
+ * binding on Opt-d will trigger, but a binding on mathematical delta would
+ * also trigger. This would require changes in the core, though.
+ */
+
+static int
+InitKeyEvent(
+ XEvent * eventPtr,
+ KeyEventData * e,
+ UInt32 savedKeyCode,
+ UInt32 savedModifiers)
+{
+ Window window;
+ Tk_Window tkwin;
TkDisplay *dispPtr;
/*
@@ -267,6 +501,7 @@ GenerateKeyEvent( EventKind eKind,
* that owns the focus.
*/
+ window = TkMacOSXGetXWindow(e->whichWindow);
dispPtr = TkGetDisplayList();
tkwin = Tk_IdToWindow(dispPtr->display, window);
@@ -281,127 +516,58 @@ GenerateKeyEvent( EventKind eKind,
return -1;
}
- event.xkey.trans_chars[0] = 0;
-
- if (0 != e->ch) {
- Ptr resource = NULL;
- if (GetKeyboardLayout(&resource)) {
- if (0 == DecodeViaUnicodeResource(resource,eKind,e,&event))
- return 0;
- } else {
- if (0 == DecodeViaKCHRResource(resource,e,&event))
- return 0;
- }
- }
-
- event.xany.send_event = False;
- event.xkey.same_screen = true;
- event.xkey.subwindow = None;
- event.xkey.time = TkpGetMS();
-
- event.xkey.x_root = e->global.h;
- event.xkey.y_root = e->global.v;
- Tk_TopCoordsToWindow(tkwin, e->local.h, e->local.v,
- &event.xkey.x, &event.xkey.y);
-
- /*
- * Now, we may have a problem here. How do we handle 'Option-char'
- * keypresses? The problem is that we might want to bind to some of
- * these (e.g. Cmd-Opt-d is 'uncomment' in Alpha), but Option-d
- * generates a 'delta' symbol with some keycode unrelated to 'd', and so
- * the binding never triggers. In any case, the delta that is produced
- * is never mapped to an 'XK_Greek_DELTA' keysym so bindings on that
- * won't work either (a general KeyPress binding will of course trigger,
- * but a specific binding on XK_Greek_DELTA will not).
- *
- * I think what we want is for the event to contain information on
- * both the 'Opt-d' side of things and the 'delta'. Then a binding
- * on Opt-d will trigger, but the ascii/string representation of the
- * event will be a delta.
- *
- * A different way to look at this is that 'Opt-d' is delta, but that
- * Command-Opt-d is nothing to do with delta, but I'm not sure that is
- * helpful.
- *
- * Also some keypresses (Opt-e) are dead-keys to add accents to
- * letters. We don't handle them yet.
- *
- * Help needed!
- */
- event.xkey.keycode = e->ch |
+ eventPtr->xany.send_event = false;
+ eventPtr->xany.serial = Tk_Display(tkwin)->request;
+
+ eventPtr->xkey.same_screen = true;
+ eventPtr->xkey.subwindow = None;
+ eventPtr->xkey.time = TkpGetMS();
+ eventPtr->xkey.x_root = e->global.h;
+ eventPtr->xkey.y_root = e->global.v;
+ eventPtr->xkey.window = Tk_WindowId(tkwin);
+ eventPtr->xkey.display = Tk_Display(tkwin);
+ eventPtr->xkey.root = XRootWindow(Tk_Display(tkwin), 0);
+ eventPtr->xkey.state = e->state;
+ eventPtr->xkey.trans_chars[0] = 0;
+
+ Tk_TopCoordsToWindow(
+ tkwin, e->local.h, e->local.v,
+ &eventPtr->xkey.x, &eventPtr->xkey.y);
+
+ eventPtr->xkey.keycode = e->ch |
((savedKeyCode & charCodeMask) << 8) |
((e->message&keyCodeMask) << 8);
-
- event.xany.serial = Tk_Display(tkwin)->request;
- event.xkey.window = Tk_WindowId(tkwin);
- event.xkey.display = Tk_Display(tkwin);
- event.xkey.root = XRootWindow(Tk_Display(tkwin), 0);
- event.xkey.state = e->state;
-
- switch(eKind) {
- case kEventRawKeyDown:
- event.xany.type = KeyPress;
- Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
- break;
- case kEventRawKeyUp:
- event.xany.type = KeyRelease;
- Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
- break;
- case kEventRawKeyRepeat:
- event.xany.type = KeyRelease;
- Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
- event.xany.type = KeyPress;
- Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
- break;
- case kEventRawKeyModifiersChanged:
- if (savedModifiers > e->keyModifiers) {
- event.xany.type = KeyRelease;
- } else {
- event.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.
- */
- event.xany.send_event = -1;
- /* Set keycode (which was zero) to the changed modifier */
- event.xkey.keycode = (e->keyModifiers ^ savedModifiers);
- Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
- break;
- default:
- break;
- }
+
return 1;
}
+
/*
*----------------------------------------------------------------------
*
* GetKeyboardLayout --
*
- * Queries the OS for a pointer to a keyboard resource.
+ * Queries the OS for a pointer to a keyboard resource.
*
- * NB (benny): This function is supposed to work with the
- * keyboard layout switch menu that we have in 10.2. Currently
- * the menu is not enabled at all for wish, so I can not really
- * test it. We will probably have to use real TSM-style event
- * handling to get all those goodies, but I haven't figured out
- * those bits yet.
+ * This function works with the keyboard layout switch menu that
+ * we have in 10.2.
*
* Results:
- * 1 if there is returned a Unicode 'uchr' resource in
- * "*resource", 0 if it is a classic 'KCHR' resource.
+ * 1 if there is returned a Unicode 'uchr' resource in
+ * "*resource", 0 if it is a classic 'KCHR' resource. A pointer
+ * to the actual resource data goes into *resource.
*
* Side effects:
- * Sets some internal static variables.
+ * Sets some internal static variables.
*
*----------------------------------------------------------------------
*/
+
static int
-GetKeyboardLayout ( Ptr * resource )
+GetKeyboardLayout (Ptr * resource)
{
- static SInt16 lastKeyLayoutID = -1; /* should be safe */
+ static Boolean initialized = false;
+ static SInt16 lastKeyLayoutID = -1;
static Handle uchrHnd = NULL;
static Handle KCHRHnd = NULL;
@@ -411,182 +577,307 @@ GetKeyboardLayout ( Ptr * resource )
keyScript = GetScriptManagerVariable(smKeyScript);
keyLayoutID = GetScriptVariable(keyScript,smScriptKeys);
- if (lastKeyLayoutID != keyLayoutID) {
- deadKeyState = 0;
- lastKeyLayoutID = keyLayoutID;
- uchrHnd = GetResource('uchr',keyLayoutID);
- if (NULL == uchrHnd) {
- KCHRHnd = GetResource('KCHR',keyLayoutID);
- }
+ if (!initialized || (lastKeyLayoutID != keyLayoutID)) {
+ initialized = true;
+ deadKeyStateUp = deadKeyStateDown = 0;
+ lastKeyLayoutID = keyLayoutID;
+ uchrHnd = GetResource('uchr',keyLayoutID);
+ if (NULL == uchrHnd) {
+ KCHRHnd = GetResource('KCHR',keyLayoutID);
+ }
+ if ((NULL == uchrHnd) && (NULL == KCHRHnd)) {
+ initialized = false;
+ fprintf (stderr,
+ "GetKeyboardLayout(): "
+ "Can't get a keyboard layout for layout %d "
+ "(error code %d)?\n",
+ (int) keyLayoutID, (int) ResError());
+ *resource = (Ptr) GetScriptManagerVariable(smKCHRCache);
+ fprintf (stderr,
+ "GetKeyboardLayout(): Trying the cache: %p\n",
+ *resource);
+ return 0;
+ }
}
if (NULL != uchrHnd) {
- *resource = *uchrHnd;
- return 1;
+ *resource = *uchrHnd;
+ return 1;
} else {
- *resource = *KCHRHnd;
- return 0;
+ *resource = *KCHRHnd;
+ return 0;
}
}
+
/*
*----------------------------------------------------------------------
*
- * DecodeViaUnicodeResource --
+ * KeycodeToUnicodeViaUnicodeResource --
*
- * Given MacOS key event data this function generates the UTF-8
- * characters. It does this using a 'uchr' and the
- * UCKeyTranslate API.
+ * Given MacOS key event data this function generates the Unicode
+ * characters. It does this using a 'uchr' and the UCKeyTranslate
+ * API.
*
- * NB (benny): This function is not tested at all, because my
- * system does not actually return a 'uchr' resource in
- * GetKeyboardLayout currently. We probably need to do
- * TSM-style event handling to get keyboard layout switching
- * first.
+ * The parameter deadKeyStatePtr can be NULL, if no deadkey handling
+ * is needed.
+ *
+ * Tested and known to work with US, Hebrew, Greek and Russian layouts
+ * as well as "Unicode Hex Input".
*
* Results:
- * 1 if the data was generated, 0 if we are waiting for another
- * byte of a dead-key sequence.
+ * The number of characters generated if any, 0 if we are waiting for
+ * another byte of a dead-key sequence. Fills in the uniChars array
+ * with a Unicode string.
*
- * Side effects:
- * Sets the trans_chars array in the XEvent->xkey structure.
+ * Side Effects:
+ * None
*
*----------------------------------------------------------------------
*/
static int
-DecodeViaUnicodeResource(
- Ptr uchr,
- EventKind eKind,
- const KeyEventData * e,
- XEvent * event )
+KeycodeToUnicodeViaUnicodeResource(
+ UniChar * uniChars, int maxChars,
+ Ptr uchr,
+ EventKind eKind,
+ UInt32 keycode, UInt32 modifiers,
+ UInt32 * deadKeyStatePtr)
{
- /* input of UCKeyTranslate */
- unsigned vkey;
int action;
- unsigned modifiers;
unsigned long keyboardType;
-
- /* output of UCKeyTranslate */
- enum { BUFFER_SIZE = 16 };
- UniChar unistring[BUFFER_SIZE];
+ OptionBits options = 0;
+ UInt32 dummy_state;
UniCharCount actuallength;
OSStatus status;
- /* for converting the result */
- char utf8buffer[sizeof(event->xkey.trans_chars)+4];
- int s, d;
-
- vkey = ((e->message) >> 8) & 0xFF;
- modifiers = ((e->keyModifiers) >> 8) & 0xFF;
+ keycode &= 0xFF;
+ modifiers = (modifiers >> 8) & 0xFF;
keyboardType = LMGetKbdType();
- switch(eKind) {
- default: /* keep compilers happy */
- case kEventRawKeyDown: action = kUCKeyActionDown; break;
- case kEventRawKeyUp: action = kUCKeyActionUp; break;
- case kEventRawKeyRepeat: action = kUCKeyActionAutoKey; break;
+ if (NULL==deadKeyStatePtr) {
+ options = kUCKeyTranslateNoDeadKeysMask;
+ dummy_state = 0;
+ deadKeyStatePtr = &dummy_state;
+ }
+
+ switch(eKind) {
+ case kEventRawKeyDown:
+ action = kUCKeyActionDown;
+ break;
+ case kEventRawKeyUp:
+ action = kUCKeyActionUp;
+ break;
+ case kEventRawKeyRepeat:
+ action = kUCKeyActionAutoKey;
+ break;
+ default:
+ fprintf (stderr,
+ "KeycodeToUnicodeViaUnicodeResource(): "
+ "Invalid parameter eKind %d\n",
+ (int) eKind);
+ return 0;
}
status = UCKeyTranslate(
- (const UCKeyboardLayout *)uchr,
- vkey, action, modifiers, keyboardType,
- 0, &deadKeyState, BUFFER_SIZE, &actuallength, unistring);
+ (const UCKeyboardLayout *) uchr,
+ keycode, action, modifiers, keyboardType,
+ options, deadKeyStatePtr,
+ maxChars, &actuallength, uniChars);
- if (0 != deadKeyState)
- return 0; /* more data later */
+ if ((0 == actuallength) && (0 != *deadKeyStatePtr)) {
+ /*
+ * More data later
+ */
+
+ return 0;
+ }
+
+ /*
+ * some IMEs leave residue :-(
+ */
+
+ *deadKeyStatePtr = 0;
if (noErr != status) {
- fprintf(stderr,"UCKeyTranslate failed: %d", (int) status);
- actuallength = 0;
- }
- s = 0;
- d = 0;
- while (s<actuallength) {
- int newd = d + Tcl_UniCharToUtf(unistring[s],utf8buffer+d);
- if (newd > (sizeof(event->xkey.trans_chars)-1)) {
- break;
- }
- d = newd;
- ++s;
+ fprintf(stderr,"UCKeyTranslate failed: %d", (int) status);
+ actuallength = 0;
}
- utf8buffer[d] = 0;
- strcpy(event->xkey.trans_chars, utf8buffer);
- return 1;
+ return actuallength;
}
-
+
/*
*----------------------------------------------------------------------
*
- * DecodeViaKCHRResource --
+ * KeycodeToUnicodeViaKCHRResource --
*
- * Given MacOS key event data this function generates the UTF-8
- * characters. It does this using a 'KCHR' and the
- * KeyTranslate API.
+ * Given MacOS key event data this function generates the Unicode
+ * characters. It does this using a 'KCHR' and the KeyTranslate API.
*
- * NB (benny): The function is not actually tested with double
- * byte encodings yet.
+ * The parameter deadKeyStatePtr can be NULL, if no deadkey handling
+ * is needed.
*
* Results:
- * 1 if the data was generated, 0 if we are waiting for another
- * byte of a dead-key sequence.
+ * The number of characters generated if any, 0 if we are waiting for
+ * another byte of a dead-key sequence. Fills in the uniChars array
+ * with a Unicode string.
*
- * Side effects:
- * Sets the trans_chars array in the XEvent->xkey structure.
+ * Side Effects:
+ * None
*
*----------------------------------------------------------------------
*/
+
static int
-DecodeViaKCHRResource(
- Ptr kchr,
- const KeyEventData * e,
- XEvent * event )
+KeycodeToUnicodeViaKCHRResource(
+ UniChar * uniChars, int maxChars,
+ Ptr kchr,
+ EventKind eKind,
+ UInt32 keycode, UInt32 modifiers,
+ UInt32 * deadKeyStatePtr)
{
- /* input and output of KeyTranslate */
- UInt16 keycode;
UInt32 result;
+ char macBuff[3];
+ char * macStr;
+ int macStrLen;
+ UInt32 dummy_state = 0;
- /* for converting the result */
- char macbuff[2];
- char * macstr;
- int maclen;
- keycode = e->keyCode | e->keyModifiers;
- result = KeyTranslate(kchr, keycode, &deadKeyState);
+ if (NULL == deadKeyStatePtr) {
+ deadKeyStatePtr = &dummy_state;
+ }
+
+ keycode |= modifiers;
+ result = KeyTranslate(kchr, keycode, deadKeyStatePtr);
+
+ if ((0 == result) && (0 != dummy_state)) {
+ /*
+ * 'dummy_state' gets only filled if the caller did not want deadkey
+ * processing (deadKeyStatePtr was NULL originally), but we still
+ * have a deadkey. We just push the keycode for the space bar to get
+ * the real key value.
+ */
+
+ result = KeyTranslate(kchr, 0x31, deadKeyStatePtr);
+ *deadKeyStatePtr = 0;
+ }
- if (0 != deadKeyState)
- return 0; /* more data later */
+ if ((0 == result) && (0 != *deadKeyStatePtr)) {
+ /*
+ * More data later
+ */
+
+ return 0;
+ }
- macbuff[0] = (char) (result >> 16);
- macbuff[1] = (char) result;
+ macBuff[0] = (char) (result >> 16);
+ macBuff[1] = (char) result;
+ macBuff[2] = 0;
- if (0 != macbuff[0]) {
- /* if the first byte is valid, the second is too */
- macstr = macbuff;
- maclen = 2;
- } else if (0 != macbuff[1]) {
- /* only the second is valid */
- macstr = macbuff+1;
- maclen = 1;
+ if (0 != macBuff[0]) {
+ /*
+ * If the first byte is valid, the second is too
+ */
+
+ macStr = macBuff;
+ macStrLen = 2;
+ } else if (0 != macBuff[1]) {
+ /*
+ * Only the second is valid
+ */
+
+ macStr = macBuff+1;
+ macStrLen = 1;
} else {
- /* no valid bytes at all */
- macstr = NULL;
- maclen = 0;
+ /*
+ * No valid bytes at all -- shouldn't happen
+ */
+
+ macStr = NULL;
+ macStrLen = 0;
}
- if (maclen > 0) {
- int result = Tcl_ExternalToUtf(
- NULL, TkMacOSXCarbonEncoding,
- macstr, maclen, 0, NULL,
- event->xkey.trans_chars, sizeof(event->xkey.trans_chars),
- NULL, NULL, NULL);
+ if (macStrLen <= 0) {
+ return 0;
+ } else {
+ /*
+ * Use the CFString conversion routines. This is the easiest and
+ * most compatible way to get from an 8-bit string and a MacOS script
+ * code to a Unicode string.
+ */
+
+ CFStringRef cfString;
+ int uniStrLen;
+
+ cfString = CFStringCreateWithCStringNoCopy(
+ NULL, macStr,
+ GetScriptManagerVariable(smKeyScript),
+ kCFAllocatorNull);
+ uniStrLen = CFStringGetLength(cfString);
+ if (uniStrLen > maxChars) {
+ uniStrLen = maxChars;
+ }
+ CFStringGetCharacters(cfString, CFRangeMake(0,uniStrLen), uniChars);
+ CFRelease(cfString);
+
+ return uniStrLen;
}
+}
- return 1;
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXKeycodeToUnicode --
+ *
+ * Given MacOS key event data this function generates the Unicode
+ * characters. It does this using OS resources and APIs.
+ *
+ * The parameter deadKeyStatePtr can be NULL, if no deadkey handling
+ * is needed.
+ *
+ * This function is called from XKeycodeToKeysym() in
+ * tkMacOSKeyboard.c.
+ *
+ * Results:
+ * The number of characters generated if any, 0 if we are waiting for
+ * another byte of a dead-key sequence. Fills in the uniChars array
+ * with a Unicode string.
+ *
+ * Side Effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkMacOSXKeycodeToUnicode(
+ UniChar * uniChars, int maxChars,
+ EventKind eKind,
+ UInt32 keycode, UInt32 modifiers,
+ UInt32 * deadKeyStatePtr)
+{
+ Ptr resource = NULL;
+ int len;
+
+
+ if (GetKeyboardLayout(&resource)) {
+ len = KeycodeToUnicodeViaUnicodeResource(
+ uniChars, maxChars, resource, eKind,
+ keycode, modifiers, deadKeyStatePtr);
+ } else {
+ len = KeycodeToUnicodeViaKCHRResource(
+ uniChars, maxChars, resource, eKind,
+ keycode, modifiers, deadKeyStatePtr);
+ }
+
+ return len;
}
+
+
/*
*----------------------------------------------------------------------
*
@@ -691,15 +982,15 @@ TkpSetCapture(
*
* 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.
+ * 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
+ * None
*
* Side effects:
- * None
+ * None
*
*----------------------------------------------------------------------
*/
@@ -707,8 +998,8 @@ TkpSetCapture(
void
Tk_SetCaretPos(tkwin, x, y, height)
Tk_Window tkwin;
- int x;
- int y;
- int height;
+ int x;
+ int y;
+ int height;
{
}