Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Another rewrite of tkProcessKeyEvent to repair and clarify the logic of when to use the TextInputClient and when to send an XEvent. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | bug-585584ad66 |
Files: | files | file ages | folders |
SHA3-256: |
769f555de32d10d4e7448576e71ece0d |
User & Date: | marc_culler 2020-04-20 17:14:40 |
References
2020-04-20
| ||
19:02 | • Ticket [585584ad] Aqua: `event generate` not working for function keys status still Open with 3 other changes artifact: 3d3b1190 user: chrstphrchvz | |
Context
2020-04-20
| ||
19:18 | Fix two typos and a bug -- thanks to Christopher Chavez. check-in: f4ee810c user: culler tags: bug-585584ad66 | |
17:14 | Another rewrite of tkProcessKeyEvent to repair and clarify the logic of when to use the TextInputClient and when to send an XEvent. check-in: 769f555d user: marc_culler tags: bug-585584ad66 | |
2020-04-19
| ||
23:43 | Another major overhaul: more code cleanup; make event generate work for Home, End, ...; distinguish left and right mod keys. check-in: 7e861e1e user: marc_culler tags: bug-585584ad66 | |
Changes
Changes to macosx/tkMacOSXKeyEvent.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_KEYBOARD #endif */ #define NS_KEYLOG 0 | | < > > > > < > | > > | > > > < < < < | < < < < > | > | < < | < < < < < < < | | < < < < < | < > | < < < < < < < | < < < < < < | < < < < | < < < | > | | < < < < > | < | | | | | < < < < < < < < < < < | < < | < < > | > | > | < < < < | | < < < | < < < < | < < < < < | | < | | | > | < | | | | | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | > > > > > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | /* #ifdef TK_MAC_DEBUG #define TK_MAC_DEBUG_KEYBOARD #endif */ #define NS_KEYLOG 0 #define XEVENT_MOD_MASK (ControlMask | Mod1Mask | Mod3Mask | Mod4Mask) static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */ static NSWindow *keyboardGrabNSWindow = nil; /* Its underlying NSWindow.*/ static NSModalSession modalSession = nil; static BOOL processingCompose = NO; static Tk_Window composeWin = NULL; static int caret_x = 0, caret_y = 0, caret_height = 0; static TkWindow *caret_win = NULL; static void setupXEvent(XEvent *xEvent, Tk_Window tkwin, NSUInteger modifiers); #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 = [theEvent window]; TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr; NSEventType type = [theEvent type]; NSUInteger keyCode = [theEvent keyCode]; NSUInteger modifiers = ([theEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask); XEvent xEvent; Bool has_modifiers = NO; Bool has_caret = NO; Bool use_text_input = NO; UniChar keychar = 0; static NSUInteger savedModifiers = 0; static NSMutableArray *nsEvArray = nil; if (nsEvArray == nil) { nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1]; processingCompose = NO; } if (!winPtr) { return theEvent; } /* * Control-Tab and Control-Shift-Tab are used to switch tabs in a tabbed * window. We do not want to generate an Xevent for these since that might * cause the deselected tab to be reactivated. */ if (keyCode == 48 && (modifiers & NSControlKeyMask) == NSControlKeyMask) { return theEvent; } /* * If a local grab is in effect, key events for windows in the * grabber's application are redirected to the grabber. Key events * for <other applications are delivered normally. If a global * grab is in effect all key events are redirected to the grabber. */ if (grabWinPtr) { if (winPtr->dispPtr->grabFlags || /* global grab */ grabWinPtr->mainPtr == winPtr->mainPtr){ /* same application */ tkwin = (Tk_Window) winPtr->dispPtr->focusPtr; } } /* * Extract the unicode character from KeyUp and KeyDown events. */ if (type == NSKeyUp || type == NSKeyDown) { if ([[theEvent characters] length] > 0) { keychar = [[theEvent characters] characterAtIndex:0]; } else { /* * This is a dead key, so it should go to the TextInputClient. */ use_text_input = YES; } #if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1 TKLog(@"-[%@(%p) %s] repeat=%d mods=%x char=%x code=%lu c=%d type=%d", [self class], self, _cmd, (type == NSKeyDown) && [theEvent isARepeat], modifiers, keychar, keyCode, w, type); #endif } /* * Build a skeleton XEvent. We need to build it here, even if we will not * send it, so we can pass it to TkFocusKeyEvent to determine whether the * target windows has the caret. */ setupXEvent(&xEvent, tkwin, modifiers); has_modifiers = xEvent.xkey.state & XEVENT_MOD_MASK; has_caret = (TkFocusKeyEvent(winPtr, &xEvent) == caret_win); /* * A KeyDown event targetting the caret window and having alphanumeric * keychar should be processed by our TextInputClient. The XEvent will not * be sent in this case. */ if (type == NSKeyDown && has_caret && !has_modifiers && (keychar >= 0x0020) && (keychar <= 0x00FF)) { use_text_input = YES; } if (use_text_input) { #if (NS_KEYLOG) TKLog(@"keyDown: %s compose sequence.\n", processingCompose == YES ? "Continue" : "Begin"); #endif /* * Call our interpretKeyEvents method to handle the event as a * TextInputClient. When the composition sequence is complete, our * implementation of insertText: replacementRange will be called. That * method generates a keyPress XEvent with the selected character. In * IME when multiple characters have the same composition sequence and * the selected character is not the default it may be necessary to hit * the Enter key multiple times before the character is accepted and * rendered. So we repeatedly send Enter key events until the inputText * method has cleared the processingCompose flag. */ processingCompose = YES; while(processingCompose) { [nsEvArray addObject: theEvent]; [[w contentView] interpretKeyEvents: nsEvArray]; [nsEvArray removeObject: theEvent]; if ([theEvent keyCode] != 36) { break; } } return theEvent; } /* * We need to send an XEvent. Finish constructing it. */ xEvent.xkey.keycode = (keyCode << 16) | keychar; switch (type) { case NSFlagsChanged: /* * We simulate KeyPress and KeyRelease events whenever a modifier flag * change is reported. To determine the type, note that the highest * bit where the flags differ is 1 if and only if it is a KeyPress. * Remember the modifiers for the next flag change. */ xEvent.xany.type = modifiers > savedModifiers ? KeyPress : KeyRelease; savedModifiers = modifiers; /* * The value -1 signals a modifier keycode to the function TkpGetKeySym * (see tkMacOSXKeyboard.c). */ xEvent.xany.send_event = -1; break; case NSKeyUp: xEvent.xany.type = KeyRelease; break; case NSKeyDown: xEvent.xany.type = KeyPress; break; default: return theEvent; /* Unrecognized key event. */ } /* * Finally we can queue an XEvent, inserting a KeyRelease before a * repeated KeyPress. */ if (type == NSKeyDown && [theEvent isARepeat]) { xEvent.xany.type = KeyRelease; Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); xEvent.xany.type = KeyPress; } Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); return theEvent; } @end @implementation TKContentView |
︙ | ︙ |
Changes to macosx/tkMacOSXKeyboard.c.
︙ | ︙ | |||
71 72 73 74 75 76 77 78 79 | {97, XK_F6, NSF6FunctionKey}, {98, XK_F7, NSF7FunctionKey}, {99, XK_F3, NSF3FunctionKey}, {100, XK_F8, NSF8FunctionKey}, {101, XK_F9, NSF9FunctionKey}, {103, XK_F11, NSF11FunctionKey}, {105, XK_F13, NSF13FunctionKey}, {107, XK_F14, NSF14FunctionKey}, {109, XK_F10, NSF10FunctionKey}, | > < < | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | {97, XK_F6, NSF6FunctionKey}, {98, XK_F7, NSF7FunctionKey}, {99, XK_F3, NSF3FunctionKey}, {100, XK_F8, NSF8FunctionKey}, {101, XK_F9, NSF9FunctionKey}, {103, XK_F11, NSF11FunctionKey}, {105, XK_F13, NSF13FunctionKey}, {106, XK_F16, NSF16FunctionKey}, {107, XK_F14, NSF14FunctionKey}, {109, XK_F10, NSF10FunctionKey}, {111, XK_F12, NSF12FunctionKey}, {113, XK_F15, NSF15FunctionKey}, {114, XK_Help, NSHelpFunctionKey}, {115, XK_Home, NSHomeFunctionKey}, /* Fn Left */ {116, XK_Page_Up, NSPageUpFunctionKey}, /* Fn Up */ {117, XK_Delete, NSDeleteFunctionKey}, /* Fn Deleete */ {118, XK_F4, NSF4FunctionKey}, |
︙ | ︙ | |||
98 99 100 101 102 103 104 | }; /* * X11 keysyms for modifier keys, in order. */ #define NUM_MOD_KEYCODES 14 | | | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | }; /* * X11 keysyms for modifier keys, in order. */ #define NUM_MOD_KEYCODES 14 static const KeyCode modKeyArray[NUM_MOD_KEYCODES] = { XK_Shift_L, XK_Shift_R, XK_Control_L, XK_Control_R, XK_Caps_Lock, XK_Shift_Lock, XK_Meta_L, XK_Meta_R, XK_Alt_L, XK_Alt_R, XK_Super_L, XK_Super_R, XK_Hyper_L, XK_Hyper_R, }; static BOOL initialized = NO; static BOOL keyboardChanged = YES; static Tcl_HashTable virtual2keysym; /* Maps Mac keyCode to X11 keysym. */ static Tcl_HashTable keysym2keycode; /* Maps X11 keysym to Mac keycode. */ static int latin1Table[LATIN1_MAX+1]; /* Reverse mapping table for Latin-1. */ /* * Prototypes for static functions used in this file. */ |
︙ | ︙ | |||
139 140 141 142 143 144 145 | @implementation TKApplication(TKKeyboard) - (void) keyboardChanged: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif | | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | @implementation TKApplication(TKKeyboard) - (void) keyboardChanged: (NSNotification *) notification { #ifdef TK_MAC_DEBUG_NOTIFICATIONS TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif keyboardChanged = YES; } @end #pragma mark - /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
178 179 180 181 182 183 184 | hPtr = Tcl_CreateHashEntry(&virtual2keysym, INT2PTR(kPtr->virtual), &dummy); Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym)); hPtr = Tcl_CreateHashEntry(&keysym2keycode, INT2PTR(kPtr->keysym), &dummy); Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keychar | (kPtr->virtual << 16))); } | | | 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | hPtr = Tcl_CreateHashEntry(&virtual2keysym, INT2PTR(kPtr->virtual), &dummy); Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym)); hPtr = Tcl_CreateHashEntry(&keysym2keycode, INT2PTR(kPtr->keysym), &dummy); Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keychar | (kPtr->virtual << 16))); } initialized = YES; } /* *---------------------------------------------------------------------- * * InitLatin1Table -- * |
︙ | ︙ |