From 3dfcc64d60f5d0a1018c5fe6ebd6f38db678e5bb Mon Sep 17 00:00:00 2001 From: vincentdarley Date: Wed, 16 Oct 2002 11:29:49 +0000 Subject: dead keys first fix for MacOSX --- ChangeLog | 5 + macosx/tkMacOSXKeyEvent.c | 271 +++++++++++++++++++++++++++++++++++++++++----- macosx/tkMacOSXKeyboard.c | 43 +------- 3 files changed, 252 insertions(+), 67 deletions(-) diff --git a/ChangeLog b/ChangeLog index dcaf94f..e6ebdfe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,11 @@ * macosx/tkMacOSXMenu.c: fix to accelerators shown in menus with non-alphanumeric keys. + * macosx/tkMacOSXKeyEvent.c: + * macosx/tkMacOSXKeyboard.c: applied first patch from [Patch + #622582] to fix some of [Bug #616988]. Further work is needed + in this area, but this will let foreign keyboards at least work + reasonably with Tk. 2002-10-15 Jeff Hobbs diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index a8d2711..78a37eb 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -60,7 +60,7 @@ typedef struct { Point global; Point local; int state; - char ch; + unsigned char ch; UInt32 keyCode; UInt32 keyModifiers; UInt32 message; @@ -69,6 +69,8 @@ typedef struct { 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; + /* * Declarations for functions used only in this file. */ @@ -78,6 +80,22 @@ static int GenerateKeyEvent _ANSI_ARGS_(( EventKind eKind, Window window, UInt32 savedKeyCode, UInt32 savedModifiers)); + + +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 ); + + /* *---------------------------------------------------------------------- * @@ -232,7 +250,7 @@ int TkMacOSXProcessKeyboardEvent( *---------------------------------------------------------------------- */ -int +static int GenerateKeyEvent( EventKind eKind, KeyEventData * e, Window window, @@ -241,8 +259,6 @@ GenerateKeyEvent( EventKind eKind, { Tk_Window tkwin; XEvent event; - unsigned char byte; - char buf[16]; TkDisplay *dispPtr; /* @@ -264,33 +280,18 @@ GenerateKeyEvent( EventKind eKind, fprintf(stderr,"tkwin == NULL, %d\n", __LINE__); return -1; } - byte = (e->message&charCodeMask); - if (byte == 0) { - /* - * Either we have a pure-modifier change, or perhaps - * a dead-key (e.g. opt-e) was pressed. In the former case we do - * want to generate an event, in the latter I'm not sure - * what to do. - */ - if (eKind == kEventRawKeyModifiersChanged) { - /* Drop through to the event code below */ + + 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 { - /* - * What shall we do here? We certainly aren't dealing - * with deadkeys at present. Is this where they come? - */ + if (0 == DecodeViaKCHRResource(resource,e,&event)) return 0; } - } else if ((savedKeyCode == 0) && - (Tcl_ExternalToUtf(NULL, TkMacOSXCarbonEncoding, - (char *) &byte, 1, 0, NULL, - buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK)) { - /* - * This event specifies a lead byte. Wait for the second byte - * to come in before sending the XEvent. - */ - fprintf(stderr,"Failed %02x\n", byte); - return 0; } event.xany.send_event = False; @@ -327,7 +328,7 @@ GenerateKeyEvent( EventKind eKind, * * Help needed! */ - event.xkey.keycode = byte | + event.xkey.keycode = e->ch | ((savedKeyCode & charCodeMask) << 8) | ((e->message&keyCodeMask) << 8); @@ -377,6 +378,218 @@ GenerateKeyEvent( EventKind eKind, /* *---------------------------------------------------------------------- * + * GetKeyboardLayout -- + * + * 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. + * + * Results: + * 1 if there is returned a Unicode 'uchr' resource in + * "*resource", 0 if it is a classic 'KCHR' resource. + * + * Side effects: + * Sets some internal static variables. + * + *---------------------------------------------------------------------- + */ +static int +GetKeyboardLayout ( Ptr * resource ) +{ + static SInt16 lastKeyLayoutID = -1; /* should be safe */ + static Handle uchrHnd = NULL; + static Handle KCHRHnd = NULL; + + SInt16 keyScript; + SInt16 keyLayoutID; + + 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 (NULL != uchrHnd) { + *resource = *uchrHnd; + return 1; + } else { + *resource = *KCHRHnd; + return 0; + } +} + +/* + *---------------------------------------------------------------------- + * + * DecodeViaUnicodeResource -- + * + * Given MacOS key event data this function generates the UTF-8 + * 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. + * + * Results: + * 1 if the data was generated, 0 if we are waiting for another + * byte of a dead-key sequence. + * + * Side effects: + * Sets the trans_chars array in the XEvent->xkey structure. + * + *---------------------------------------------------------------------- + */ + +static int +DecodeViaUnicodeResource( + Ptr uchr, + EventKind eKind, + const KeyEventData * e, + XEvent * event ) +{ + /* input of UCKeyTranslate */ + unsigned vkey; + int action; + unsigned modifiers; + unsigned long keyboardType; + + /* output of UCKeyTranslate */ + enum { BUFFER_SIZE = 16 }; + UniChar unistring[BUFFER_SIZE]; + 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; + keyboardType = LMGetKbdType(); + + switch(eKind) { + default: /* keep compilers happy */ + case kEventRawKeyDown: action = kUCKeyActionDown; break; + case kEventRawKeyUp: action = kUCKeyActionUp; break; + case kEventRawKeyRepeat: action = kUCKeyActionAutoKey; break; + } + + status = UCKeyTranslate( + (const UCKeyboardLayout *)uchr, + vkey, action, modifiers, keyboardType, + 0, &deadKeyState, BUFFER_SIZE, &actuallength, unistring); + + if (0 != deadKeyState) + return 0; /* more data later */ + + if (noErr != status) { + fprintf(stderr,"UCKeyTranslate failed: %d", (int) status); + actuallength = 0; + } + s = 0; + d = 0; + while (s (sizeof(event->xkey.trans_chars)-1)) { + break; + } + d = newd; + ++s; + } + utf8buffer[d] = 0; + strcpy(event->xkey.trans_chars, utf8buffer); + + return 1; +} + + +/* + *---------------------------------------------------------------------- + * + * DecodeViaKCHRResource -- + * + * Given MacOS key event data this function generates the UTF-8 + * characters. It does this using a 'KCHR' and the + * KeyTranslate API. + * + * NB (benny): The function is not actually tested with double + * byte encodings yet. + * + * Results: + * 1 if the data was generated, 0 if we are waiting for another + * byte of a dead-key sequence. + * + * Side effects: + * Sets the trans_chars array in the XEvent->xkey structure. + * + *---------------------------------------------------------------------- + */ +static int +DecodeViaKCHRResource( + Ptr kchr, + const KeyEventData * e, + XEvent * event ) +{ + /* input and output of KeyTranslate */ + UInt16 keycode; + UInt32 result; + + /* for converting the result */ + char macbuff[2]; + char * macstr; + int maclen; + + keycode = e->keyCode | e->keyModifiers; + result = KeyTranslate(kchr, keycode, &deadKeyState); + + if (0 != deadKeyState) + return 0; /* more data later */ + + macbuff[0] = (char) (result >> 16); + macbuff[1] = (char) result; + + 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; + } else { + /* no valid bytes at all */ + macstr = NULL; + maclen = 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); + } + + return 1; +} + +/* + *---------------------------------------------------------------------- + * * XGrabKeyboard -- * * Simulates a keyboard grab by setting the focus. diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c index aff807e..447da04 100644 --- a/macosx/tkMacOSXKeyboard.c +++ b/macosx/tkMacOSXKeyboard.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacOSXKeyboard.c,v 1.3 2002/09/09 23:52:02 hobbs Exp $ + * RCS: @(#) $Id: tkMacOSXKeyboard.c,v 1.4 2002/10/16 11:29:50 vincentdarley Exp $ */ #include "tkInt.h" @@ -156,7 +156,7 @@ XKeycodeToKeysym( return NoSymbol; } - virtualKey = (char) (keycode >> 16); + virtualKey = keycode >> 16; c = (keycode) & 0xffff; if (c > 255) { return NoSymbol; @@ -166,7 +166,7 @@ XKeycodeToKeysym( * When determining what keysym to produce we first check to see if * the key is a function key. We then check to see if the character * is another non-printing key. Finally, we return the key syms - * for all ASCI chars. + * for all ASCII chars. */ if (c == 0x10) { hPtr = Tcl_FindHashEntry(&vkeyTable, (char *) virtualKey); @@ -222,42 +222,9 @@ TkpGetString( Tcl_DString *dsPtr) /* Uninitialized or empty string to hold * result. */ { - register Tcl_HashEntry *hPtr; - char string[3]; - int virtualKey; - int c, len; - - if (!initialized) { - InitKeyMaps(); - } - + (void) winPtr; /*unused*/ Tcl_DStringInit(dsPtr); - - virtualKey = (char) (eventPtr->xkey.keycode >> 16); - c = (eventPtr->xkey.keycode) & 0xffff; - - if (c < 256) { - string[0] = (char) c; - len = 1; - } else { - string[0] = (char) (c >> 8); - string[1] = (char) c; - len = 2; - } - /* - * Just return NULL if the character is a function key or another - * non-printing key. - */ - if (c == 0x10 || (eventPtr->xany.send_event == -1)) { - len = 0; - } else { - hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey); - if (hPtr != NULL) { - len = 0; - } - } - return Tcl_ExternalToUtfDString(TkMacOSXCarbonEncoding, string, - len, dsPtr); + return Tcl_DStringAppend(dsPtr, eventPtr->xkey.trans_chars, -1); } /* -- cgit v0.12