summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXKeyEvent.c
diff options
context:
space:
mode:
authorwolfsuit <wolfsuit>2003-02-19 19:27:43 (GMT)
committerwolfsuit <wolfsuit>2003-02-19 19:27:43 (GMT)
commite891595e16225fe441b40805b6bc3f1e9ff7cc75 (patch)
treee88ef97ca29843dc17db985018abfbbb170e7a5d /macosx/tkMacOSXKeyEvent.c
parent6e2cd243ccc9bd454ae118549066ad2669c00160 (diff)
downloadtk-e891595e16225fe441b40805b6bc3f1e9ff7cc75.zip
tk-e891595e16225fe441b40805b6bc3f1e9ff7cc75.tar.gz
tk-e891595e16225fe441b40805b6bc3f1e9ff7cc75.tar.bz2
This submission contains a slightly reworked & cleaned up version of
two parts of the patches in Patch Tracker #622582 - new-evthdlng.2003-02-12.diff and basic-keyboard.2003-02-10.diff. The second part puts translation of MacOS X keycodes to characters on a better footing. The first part relaxs Tk's policy of consuming all events unless it can see they go to windows it didn't create. This change gets the little traffic lights working, and should make things like QuickTimeTcl easier to implement.
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;
{
}