summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarc_culler <marc.culler@gmail.com>2020-05-04 22:16:09 (GMT)
committermarc_culler <marc.culler@gmail.com>2020-05-04 22:16:09 (GMT)
commitdd4adf36936e5abb0eecfb4a37e7b9a6cf82e16e (patch)
treebe52d9a6619d376d7106eb0b1414d395e17d73d1
parentaa7fd4173bbd1149b15dfe1d97a38fa23d4f4cee (diff)
downloadtk-dd4adf36936e5abb0eecfb4a37e7b9a6cf82e16e.zip
tk-dd4adf36936e5abb0eecfb4a37e7b9a6cf82e16e.tar.gz
tk-dd4adf36936e5abb0eecfb4a37e7b9a6cf82e16e.tar.bz2
Add non-regression tests.
-rw-r--r--macosx/tkMacOSXKeyEvent.c31
-rw-r--r--macosx/tkMacOSXKeyboard.c62
-rw-r--r--macosx/tkMacOSXKeysyms.h20
-rw-r--r--macosx/tkMacOSXTest.c38
-rw-r--r--tests/bind.test137
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