diff options
author | marc_culler <marc.culler@gmail.com> | 2020-05-04 22:16:09 (GMT) |
---|---|---|
committer | marc_culler <marc.culler@gmail.com> | 2020-05-04 22:16:09 (GMT) |
commit | dd4adf36936e5abb0eecfb4a37e7b9a6cf82e16e (patch) | |
tree | be52d9a6619d376d7106eb0b1414d395e17d73d1 | |
parent | aa7fd4173bbd1149b15dfe1d97a38fa23d4f4cee (diff) | |
download | tk-dd4adf36936e5abb0eecfb4a37e7b9a6cf82e16e.zip tk-dd4adf36936e5abb0eecfb4a37e7b9a6cf82e16e.tar.gz tk-dd4adf36936e5abb0eecfb4a37e7b9a6cf82e16e.tar.bz2 |
Add non-regression tests.
-rw-r--r-- | macosx/tkMacOSXKeyEvent.c | 31 | ||||
-rw-r--r-- | macosx/tkMacOSXKeyboard.c | 62 | ||||
-rw-r--r-- | macosx/tkMacOSXKeysyms.h | 20 | ||||
-rw-r--r-- | macosx/tkMacOSXTest.c | 38 | ||||
-rw-r--r-- | tests/bind.test | 137 |
5 files changed, 240 insertions, 48 deletions
diff --git a/macosx/tkMacOSXKeyEvent.c b/macosx/tkMacOSXKeyEvent.c index 5913957..8d8ccc3 100644 --- a/macosx/tkMacOSXKeyEvent.c +++ b/macosx/tkMacOSXKeyEvent.c @@ -38,6 +38,7 @@ static Tk_Window composeWin = NULL; static int caret_x = 0, caret_y = 0, caret_height = 0; static void setupXEvent(XEvent *xEvent, Tk_Window tkwin, NSUInteger modifiers); static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); +static NSUInteger textInputModifiers; #pragma mark TKApplication(TKKeyEvent) @@ -62,7 +63,6 @@ static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); static NSUInteger savedModifiers = 0; static NSMutableArray *nsEvArray = nil; - if (nsEvArray == nil) { nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1]; processingCompose = NO; @@ -94,13 +94,16 @@ static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); if (type == NSKeyUp || type == NSKeyDown) { if ([[theEvent characters] length] > 0) { keychar = [[theEvent characters] characterAtIndex:0]; -#if 0 /* Currently, real keys always send BMP characters. */ + + /* + * Currently, real keys always send BMP characters, but who knows? + */ + if (CFStringIsSurrogateHighCharacter(keychar)) { - UniChar lowChar = [str characterAtIndex:1]; + UniChar lowChar = [[theEvent characters] characterAtIndex:1]; keychar = CFStringGetLongCharacterForSurrogatePair( - (UniChar)keychar, lowChar); + keychar, lowChar); } -#endif } else { /* @@ -171,6 +174,7 @@ static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); */ if (use_text_input) { + textInputModifiers = modifiers; /* * In IME the Enter key is used to terminate a composition sequence. @@ -286,9 +290,9 @@ static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); - (void)insertText: (id)aString replacementRange: (NSRange)repRange { - int i, len; + int i, len, state; XEvent xEvent; - NSString *str; + NSString *str, *keystr, *lower; TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); Tk_Window tkwin = (Tk_Window) winPtr; Bool sendingIMEText = NO; @@ -314,7 +318,7 @@ static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); * Insert the string as a sequence of keystrokes. */ - setupXEvent(&xEvent, tkwin, 0); + setupXEvent(&xEvent, tkwin, textInputModifiers); setXEventPoint(&xEvent, tkwin, [self window]); xEvent.xany.type = KeyPress; @@ -349,6 +353,7 @@ static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); * character which we write into the trans_chars field of the XEvent. */ + state = xEvent.xkey.state; for (i = 0; i < len; i++) { unsigned int code; UniChar keychar; @@ -367,6 +372,15 @@ static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); macKC.uint = TkMacOSXAddVirtual(macKC.uint); xEvent.xkey.state |= INDEX2STATE(macKC.x.xvirtual); } + keystr = [[NSString alloc] initWithCharacters:&keychar length:1]; + lower = [keystr lowercaseString]; + if (![keystr isEqual: lower]) { + macKC.v.o_s |= INDEX_SHIFT; + xEvent.xkey.state |= ShiftMask; + } + if (xEvent.xkey.state & Mod2Mask) { + macKC.v.o_s |= INDEX_OPTION; + } TkUtfAtIndex(str, i, xEvent.xkey.trans_chars, &code); if (code > 0xFFFF){ i++; @@ -374,6 +388,7 @@ static void setXEventPoint(XEvent *xEvent, Tk_Window tkwin, NSWindow *w); xEvent.xkey.keycode = macKC.uint; xEvent.xany.type = KeyPress; Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL); + xEvent.xkey.state = state; } } diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c index 004a1eb..920abfe 100644 --- a/macosx/tkMacOSXKeyboard.c +++ b/macosx/tkMacOSXKeyboard.c @@ -184,21 +184,32 @@ InitHashTables(void) Tcl_HashEntry *hPtr; const KeyInfo *kPtr; const KeysymInfo *ksPtr; - int dummy; + int dummy, index; Tcl_InitHashTable(&special2keysym, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&keysym2keycode, TCL_ONE_WORD_KEYS); for (kPtr = keyArray; kPtr->virtual != 0; kPtr++) { - MacKeycode keycode; - keycode.v.o_s = 0; + MacKeycode macKC; + macKC.v.o_s = 0; hPtr = Tcl_CreateHashEntry(&special2keysym, INT2PTR(kPtr->virtual), &dummy); Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym)); hPtr = Tcl_CreateHashEntry(&keysym2keycode, INT2PTR(kPtr->keysym), &dummy); - keycode.v.virtual = kPtr->virtual; - keycode.v.keychar = kPtr->keychar; - Tcl_SetHashValue(hPtr, INT2PTR(keycode.uint)); + macKC.v.virtual = kPtr->virtual; + macKC.v.keychar = kPtr->keychar; + Tcl_SetHashValue(hPtr, INT2PTR(macKC.uint)); + + /* + * The Carbon framework does not work for finding the unicode character + * of a special key. But that does not depend on the keyboard layout, + * so we can record the information here. + */ + + for (index = 3; index >= 0; index--) { + macKC.v.o_s = index; + xvirtual2unichar[macKC.x.xvirtual] = macKC.x.keychar; + } } Tcl_InitHashTable(&keysym2unichar, TCL_ONE_WORD_KEYS); Tcl_InitHashTable(&unichar2keysym, TCL_ONE_WORD_KEYS); @@ -264,13 +275,21 @@ UpdateKeymaps() UniChar keychar = 0; result = KeyDataToUnicode(&keychar, 1, kUCKeyActionDown, virtual, modifiers, NULL); + if (keychar == 0x10) { + + /* + * This is a special key, handled in InitHashTables. + */ + + continue; + } macKC.v.keychar = keychar; if (! ON_KEYPAD(virtual)) { hPtr = Tcl_CreateHashEntry(&unichar2xvirtual, INT2PTR(macKC.x.keychar), &dummy); Tcl_SetHashValue(hPtr, INT2PTR(macKC.x.xvirtual)); } - xvirtual2unichar[macKC.x.xvirtual] = macKC.x.keychar; + xvirtual2unichar[macKC.x.xvirtual] = macKC.x.keychar; } } } @@ -666,25 +685,28 @@ TkpSetKeycodeAndState( * set. For example, the events described by <Oslash>, <Shift-oslash>, * <Shift-Option-O> and <Shift-Option-o> should all produce the same * uppercase Danish O. So we may need to add the extra modifiers and - * do another lookup for the keychar. + * do another lookup for the keychar. We don't want to do this for + * special keys, however. */ if (macKC.v.o_s != eventIndex) { macKC.v.o_s |= eventIndex; + } + if (macKC.v.keychar < 0xF700) { + UniChar keychar = macKC.v.keychar; + NSString *str, *lower, *upper; if (macKC.v.virtual != NO_VIRTUAL) { macKC.x.keychar = xvirtual2unichar[macKC.x.xvirtual]; - } else if (macKC.v.o_s & INDEX_SHIFT) { - - /* - * Even though this keychar is not on the keyboard, we can - * still apply the Shift modifier. However, we can't guess the - * effect of the Option modifier and so we ignore it. - */ - - UniChar keychar = macKC.v.keychar; - NSString *upper = [[[NSString alloc] initWithCharacters:&keychar - length:1] uppercaseString]; - macKC.v.keychar = [upper characterAtIndex:0]; + } else { + str = [[NSString alloc] initWithCharacters:&keychar length:1]; + lower = [str lowercaseString]; + upper = [str uppercaseString]; + if (![str isEqual: lower]) { + macKC.v.o_s |= INDEX_SHIFT; + } + if (macKC.v.o_s & INDEX_SHIFT) { + macKC.v.keychar = [upper characterAtIndex:0]; + } } } eventPtr->xkey.keycode = macKC.uint; diff --git a/macosx/tkMacOSXKeysyms.h b/macosx/tkMacOSXKeysyms.h index 8e8dba6..281b5e7 100644 --- a/macosx/tkMacOSXKeysyms.h +++ b/macosx/tkMacOSXKeysyms.h @@ -42,16 +42,16 @@ static const KeyInfo keyArray[] = { {51, XK_BackSpace, NSDeleteCharacter}, {52, XK_Return, NSNewlineCharacter}, /* Used on some Powerbooks */ {53, XK_Escape, 0x1B}, - {54, XK_Meta_R, XK_Meta_R}, - {55, XK_Meta_L, XK_Meta_L}, - {56, XK_Shift_L, XK_Shift_L}, - {57, XK_Caps_Lock, XK_Caps_Lock}, - {58, XK_Alt_L, XK_Alt_L}, - {59, XK_Control_L, XK_Control_L}, - {60, XK_Shift_R, XK_Shift_R}, - {61, XK_Alt_R, XK_Alt_R}, - {62, XK_Control_R, XK_Control_R}, - {63, XK_Super_L, XK_Super_L}, + {54, XK_Meta_R, MOD_KEYCHAR}, + {55, XK_Meta_L, MOD_KEYCHAR}, + {56, XK_Shift_L, MOD_KEYCHAR}, + {57, XK_Caps_Lock, MOD_KEYCHAR}, + {58, XK_Alt_L, MOD_KEYCHAR}, + {59, XK_Control_L, MOD_KEYCHAR}, + {60, XK_Shift_R, MOD_KEYCHAR}, + {61, XK_Alt_R, MOD_KEYCHAR}, + {62, XK_Control_R, MOD_KEYCHAR}, + {63, XK_Super_L, MOD_KEYCHAR}, {64, XK_F17, NSF17FunctionKey}, {65, XK_KP_Decimal, '.'}, {67, XK_KP_Multiply, '*'}, diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c index d465492..902bf9e 100644 --- a/macosx/tkMacOSXTest.c +++ b/macosx/tkMacOSXTest.c @@ -233,15 +233,15 @@ InjectKeyEventObjCmd( "press", "release", "flagschanged", NULL}; NSUInteger types[3] = {NSKeyDown, NSKeyUp, NSFlagsChanged}; static const char *const argStrings[] = { - "-shift", "-control", "-option", "-command", "-x", "-y", NULL}; - enum args {KEYEVENT_SHIFT, KEYEVENT_CONTROL, KEYEVENT_OPTION, - KEYEVENT_COMMAND, KEYEVENT_X, KEYEVENT_Y}; + "-shift", "-control", "-option", "-command", "-function", "-x", "-y", NULL}; + enum args {KEYEVENT_SHIFT, KEYEVENT_CONTROL, KEYEVENT_OPTION, KEYEVENT_COMMAND, + KEYEVENT_FUNCTION, KEYEVENT_X, KEYEVENT_Y}; int i, index, keysym, mods = 0, x = 0, y = 0; - NSString *chars = nil; + NSString *chars = nil, *unmod = nil, *upper, *lower; NSEvent *keyEvent; NSUInteger type; MacKeycode macKC; - + if (objc < 3) { wrongArgs: Tcl_WrongNumArgs(interp, 1, objv, "option keysym ?arg?"); @@ -269,13 +269,16 @@ InjectKeyEventObjCmd( mods |= NSShiftKeyMask; break; case KEYEVENT_CONTROL: - mods |= NSShiftKeyMask; + mods |= NSControlKeyMask; break; case KEYEVENT_OPTION: - mods |= NSShiftKeyMask; + mods |= NSAlternateKeyMask; break; case KEYEVENT_COMMAND: - mods |= NSShiftKeyMask; + mods |= NSCommandKeyMask; + break; + case KEYEVENT_FUNCTION: + mods |= NSFunctionKeyMask; break; case KEYEVENT_X: if (++i >= objc) { @@ -297,7 +300,22 @@ InjectKeyEventObjCmd( } if (type != NSFlagsChanged) { UniChar keychar = macKC.v.keychar; - chars = [[NSString alloc] initWithCharacters: &keychar length:1]; + chars = [[NSString alloc] initWithCharacters: &keychar length:1]; + upper = [chars uppercaseString]; + lower = [chars lowercaseString]; + if (![upper isEqual: lower] && [chars isEqual: upper]) { + mods |= NSShiftKeyMask; + } + if (mods & NSShiftKeyMask) { + chars = upper; + unmod = lower; + macKC.v.o_s |= INDEX_SHIFT; + } else { + unmod = chars; + } + if (macKC.v.o_s & INDEX_OPTION) { + mods |= NSAlternateKeyMask; + } } keyEvent = [NSEvent keyEventWithType:type location:NSMakePoint(x, y) @@ -306,7 +324,7 @@ InjectKeyEventObjCmd( windowNumber:0 context:nil characters:chars - charactersIgnoringModifiers:chars ? [chars lowercaseString] : nil + charactersIgnoringModifiers:unmod isARepeat:NO keyCode:macKC.v.virtual]; [NSApp postEvent:keyEvent atStart:NO]; diff --git a/tests/bind.test b/tests/bind.test index 7cb515d..05bca6f 100644 --- a/tests/bind.test +++ b/tests/bind.test @@ -6707,6 +6707,143 @@ test bind-34.3 {-warp works with null or negative coordinates} -setup { } -cleanup { } -result {ok ok ok ok} +set keyInfo {} +set numericKeysym {} +proc testKey {window event type mods} { + global keyInfo numericKeysym + set keyInfo {} + set numericKeysym {} + bind $window <KeyPress> { + set keyInfo [format "%K,0x%%X,0x%%X,%A" %N %k] + set numericKeysym %N + } + focus -force $window + update + event generate $window $event + if {$keyInfo == {}} { + vwait keyInfo + } + set save $keyInfo + set keyInfo {} + set injectcmd [list injectkeyevent $type $numericKeysym] + foreach {option} $mods { + lappend injectcmd $option + } + eval $injectcmd + if {$keyInfo == {}} { + vwait keyInfo + } + if {$save != $keyInfo} { + return "[format "0x%x" $numericKeysym] ($mods): $save != $keyInfo" + } + return pass +} +proc testKeyWithMods {window keysym type} { + set result [testKey $window "<$keysym>" $type {}] + if {$result != {pass}} { + return $result + } + set result [testKey $window "<Shift-$keysym>" $type {-shift}] + if {$result != {pass}} { + return $result + } + set result [testKey $window "<Option-$keysym>" $type {-option}] + if {$result != {pass}} { + return $result + } + set result [testKey $window "<Shift-Option-$keysym>" $type {-shift -option}] + if {$result != {pass}} { + return $result + } + return pass +} +proc testModifierKey {window event option} { + global KeyInfo numericKeysym + bind . <KeyPress> { + set keyInfo [format "%K,0x%%X,0x%%X,%A" %N %k] + set numericKeysym %N + } + wm iconify $window + wm deiconify $window + update + focus -force $window + set keyInfo {} + event generate $window $event + if {$keyInfo == {}} { + vwait keyInfo + } + set save $keyInfo + set keyInfo {} + injectkeyevent flagschanged $numericKeysym -shift + if {$keyInfo == {}} { + vwait keyInfo + } + if {$save != $keyInfo} { + return "[format "0x%x" $numericKeysym]: $save != $keyInfo" + } else { + return pass + } +} + +test bind-35.0 {Generated and real key events agree} -constraints {aqua} -body { + foreach k {o O F2 Home Right Greek_sigma Greek_ALPHA} { + set result [testKeyWithMods . $k press] + if {$result != "pass"} { + return $result + } + } + return pass +} -cleanup { +} -result pass + +test bind-35.1 {Key events agree for entry widgets} -constraints {aqua} -setup { + toplevel .new + entry .new.e + pack .new.e +} -body { + foreach k {o O F2 Home Right Greek_sigma Greek_ALPHA} { + set result [testKeyWithMods .new.e $k press] + if {$result != "pass"} { + return $result + } + } + return pass +} -cleanup { + destroy .new.e + destroy .new +} -result pass + +test bind-35.2 {Can bind to function keys} -constraints {aqua} -body { + global keyInfo numericKeysym + bind . <KeyPress> {} + bind . <KeyPress> { + lappend keyInfo %K + set numericKeysym %N + } + set keyInfo {} + set numericKeysym {} + focus -force . + event generate . <F2> + injectkeyevent press $numericKeysym -function + vwait keyInfo + return $keyInfo +} -cleanup { +} -result {F2 F2} + +## For some reason this hangs after the call to event generate: +# test bind-35.3 {Events agree for modifier keys} -constraints {aqua} -body { +# return [testModifierKey . <Control_L> -control] +# } -cleanup { +# } -result pass +## but this works fine: +# $ tktest +# % bind . <KeyPress> {puts [format "%K 0x%%X 0x%%X %A" %N %k]} +# % event generate . <Control_L> +# % focus -force . ; event generate . <Control_L> +# Control_L 0xFFE3 0x3B00F8FE {} +# focus -force . ; injectkeyevent flagschanged 0xFFE3 -control +# % Control_L 0xFFE3 0x3B00F8FE {} + # cleanup cleanupTests return |