Files

299 lines
13 KiB
Go

package input
import "testing"
func TestQuitConsumesBalancedChord(t *testing.T) {
for _, modifierFirst := range []bool{false, true} {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(DesktopKeyboardLayout))
check := func(symbol uint32, code uint16, pressed, consume bool, command Command) {
t.Helper()
gotConsume, gotCommand := router.Handle(symbol, code, 0, pressed)
if gotConsume != consume || gotCommand != command {
t.Fatalf("got %v %q, want %v %q", gotConsume, gotCommand, consume, command)
}
}
check('q', 24, true, false, "")
check('q', 24, false, false, "")
check(0xff63, 118, true, true, "")
check('q', 24, true, true, Quit)
check('q', 24, true, true, "") // auto-repeat
if modifierFirst {
check(0xff63, 118, false, true, "")
check('q', 24, false, true, "")
} else {
check('q', 24, false, true, "")
check(0xff63, 118, false, true, "")
}
check('q', 24, true, false, "")
}
}
func TestUnknownChordPassesThrough(t *testing.T) {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(DesktopKeyboardLayout))
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle('x', 53, 0, true); consumed || command != "" {
t.Fatal("unknown command consumed")
}
router.Reset()
if consumed, command := router.Handle('x', 53, 0, false); consumed || command != "" {
t.Fatal("unknown command release consumed after pass-through reset")
}
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle('q', 24, 4, true); consumed || command != "" {
t.Fatal("Control+Insert+q became quit")
}
router.Reset()
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle('q', 24, 2|16, true); !consumed || command != Quit {
t.Fatal("lock keys prevented quit chord")
}
}
func TestBindingTableRoutesPreferencesOnPress(t *testing.T) {
bindings := DefaultCommandBindings(DesktopKeyboardLayout)
router := NewCommandRouter([]uint32{0xff63, 0xff9e}, bindings)
bindings[CommandChord{Symbol: ' ', CthulhuModifier: true}] = Quit
if consumed, command := router.Handle(0xff9e, 90, 0, true); !consumed || command != "" {
t.Fatalf("modifier press = %v %q", consumed, command)
}
if consumed, command := router.Handle(' ', 65, 0, true); !consumed || command != Preferences {
t.Fatalf("space press = %v %q", consumed, command)
}
if consumed, command := router.Handle(0xff9e, 90, 0, false); !consumed || command != "" {
t.Fatalf("modifier release = %v %q", consumed, command)
}
if consumed, command := router.Handle(' ', 65, 0, false); !consumed || command != "" {
t.Fatalf("space release = %v %q, want no command", consumed, command)
}
}
func TestApplicationPreferencesShortcut(t *testing.T) {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(DesktopKeyboardLayout))
if consumed, command := router.Handle(0xff63, 90, 0, true); !consumed || command != "" {
t.Fatalf("modifier press = %v %q", consumed, command)
}
if consumed, command := router.Handle(' ', 65, controlModifier, true); !consumed || command != ApplicationPreferences {
t.Fatalf("Cthulhu+Ctrl+Space = %v %q", consumed, command)
}
if consumed, command := router.Handle(' ', 65, controlModifier, false); !consumed || command != "" {
t.Fatalf("shortcut release = %v %q", consumed, command)
}
}
func TestApplicationPreferenceShiftShortcutsInBothLayouts(t *testing.T) {
for _, layout := range []KeyboardLayout{DesktopKeyboardLayout, LaptopKeyboardLayout} {
for _, tc := range []struct {
modifiers uint16
want Command
}{
{1, ApplicationPreferences}, {controlModifier | 1, ChooseApplicationPreferences},
} {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(layout))
router.Handle(0xff63, 90, 0, true)
if consumed, command := router.Handle(' ', 65, tc.modifiers, true); !consumed || command != tc.want {
t.Fatalf("layout %v shortcut = %v %q, want %q", layout, consumed, command, tc.want)
}
if consumed, command := router.Handle(' ', 65, tc.modifiers, false); !consumed || command != "" {
t.Fatalf("shortcut release = %v %q", consumed, command)
}
}
}
}
func TestLaptopBindingRoutesWhereAmI(t *testing.T) {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(LaptopKeyboardLayout))
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle(returnKeySymbol, 36, 0, true); !consumed || command != WhereAmI {
t.Fatalf("Return press = %v %q", consumed, command)
}
if consumed, command := router.Handle(returnKeySymbol, 36, 0, false); !consumed || command != "" {
t.Fatalf("Return release = %v %q", consumed, command)
}
if consumed, command := router.Handle(0xff63, 118, 0, false); !consumed || command != "" {
t.Fatalf("modifier release = %v %q, want no command", consumed, command)
}
}
func TestCharacterAttributesShortcutInBothLayouts(t *testing.T) {
for _, layout := range []KeyboardLayout{DesktopKeyboardLayout, LaptopKeyboardLayout} {
bindings := DefaultCommandBindings(layout)
if got := bindings[CommandChord{Symbol: 'f', CthulhuModifier: true}]; got != PresentCharacterAttributes {
t.Fatalf("layout %v Cthulhu+F = %q", layout, got)
}
}
}
func TestBrowseReturnActivatesWithoutChangingDefaultReturn(t *testing.T) {
for name, bindings := range map[string]CommandBindings{
"default": DefaultCommandBindings(DesktopKeyboardLayout),
"browse": BrowseCommandBindings(DesktopKeyboardLayout),
} {
router := NewCommandRouter([]uint32{0xff63}, bindings)
consumed, command := router.Handle(returnKeySymbol, 36, 0, true)
if name == "browse" && (!consumed || command != DocumentActivate) {
t.Fatalf("browse Return = %v %q", consumed, command)
}
if name == "default" && (consumed || command != "") {
t.Fatalf("default Return = %v %q", consumed, command)
}
}
}
func TestDesktopBindingRoutesWhereAmIWithoutModifier(t *testing.T) {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(DesktopKeyboardLayout))
if consumed, command := router.Handle(keypadEnterKeySymbol, 104, 0, true); !consumed || command != WhereAmI {
t.Fatalf("KP Enter press = %v %q", consumed, command)
}
if consumed, command := router.Handle(keypadEnterKeySymbol, 104, 0, false); !consumed || command != "" {
t.Fatalf("KP Enter release = %v %q, want no command", consumed, command)
}
}
func TestWhereAmIBindingsAreLayoutSpecific(t *testing.T) {
desktop := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(DesktopKeyboardLayout))
desktop.Handle(0xff63, 118, 0, true)
if consumed, command := desktop.Handle(returnKeySymbol, 36, 0, true); consumed || command != "" {
t.Fatalf("desktop Cthulhu+Return = %v %q, want unbound", consumed, command)
}
laptop := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(LaptopKeyboardLayout))
if consumed, command := laptop.Handle(keypadEnterKeySymbol, 104, 0, true); consumed || command != "" {
t.Fatalf("laptop KP Enter = %v %q, want unbound", consumed, command)
}
}
func TestObjectNavigationBindingsMatchPython(t *testing.T) {
tests := []struct {
symbol uint32
command Command
}{
{upKeySymbol, ObjectParent},
{downKeySymbol, ObjectFirstChild},
{leftKeySymbol, ObjectPreviousSibling},
{rightKeySymbol, ObjectNextSibling},
}
for _, test := range tests {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(DesktopKeyboardLayout))
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle(test.symbol, 111, controlModifier, true); !consumed || command != test.command {
t.Fatalf("symbol %#x press = %v %q", test.symbol, consumed, command)
}
if consumed, command := router.Handle(test.symbol, 111, controlModifier, false); !consumed || command != "" {
t.Fatalf("symbol %#x release = %v %q", test.symbol, consumed, command)
}
if consumed, command := router.Handle(0xff63, 118, controlModifier, false); !consumed || command != "" {
t.Fatalf("symbol %#x modifier release = %v %q, want %q", test.symbol, consumed, command, Command(""))
}
}
}
func TestObjectNavigationRequiresControl(t *testing.T) {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(DesktopKeyboardLayout))
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle(upKeySymbol, 111, 0, true); !consumed || command != IncreaseSpeechSetting {
t.Fatalf("Cthulhu+Up = %v %q, want speech adjustment", consumed, command)
}
}
func TestControlPressDoesNotMakeObjectNavigationPassThrough(t *testing.T) {
router := NewCommandRouter([]uint32{0xff63}, DefaultCommandBindings(DesktopKeyboardLayout))
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle(leftControlKeySymbol, 37, 0, true); consumed || command != "" {
t.Fatalf("Control press = %v %q", consumed, command)
}
if !router.IsModifier(leftControlKeySymbol) || !router.IsModifier(rightControlKeySymbol) {
t.Fatal("Control key was not classified as a chord modifier")
}
if consumed, command := router.Handle(upKeySymbol, 111, controlModifier, true); !consumed || command != ObjectParent {
t.Fatalf("Up press = %v %q", consumed, command)
}
}
func TestBindingTableMatchesExactAdditionalModifiers(t *testing.T) {
bindings := CommandBindings{{Symbol: 'x', Modifiers: 4, CthulhuModifier: true}: Preferences}
router := NewCommandRouter([]uint32{0xff63}, bindings)
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle('x', 53, 0, true); consumed || command != "" {
t.Fatal("binding matched without its Control modifier")
}
router.Reset()
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle('x', 53, 4, true); !consumed || command != Preferences {
t.Fatal("binding did not match its Control modifier")
}
}
func TestBrowseCommandsPreserveShiftAndReleaseOrder(t *testing.T) {
for _, tc := range []struct {
symbol uint32
mods uint16
want Command
}{
{'h', 0, DocumentNextHeading}, {'h', 1, DocumentPreviousHeading},
{'k', 0, DocumentNextLink}, {'k', 1, DocumentPreviousLink},
{'b', 0, DocumentNextButton}, {'b', 1, DocumentPreviousButton},
{'x', 0, DocumentNextCheckBox}, {'x', 1, DocumentPreviousCheckBox},
{'l', 0, DocumentNextList}, {'l', 1, DocumentPreviousList},
{'s', 0, DocumentNextSeparator}, {'s', 1, DocumentPreviousSeparator},
{'q', 0, DocumentNextBlockQuote}, {'q', 1, DocumentPreviousBlockQuote},
{'c', 0, DocumentNextComboBox}, {'c', 1, DocumentPreviousComboBox},
{'e', 0, DocumentNextEntry}, {'e', 1, DocumentPreviousEntry},
{'f', 0, DocumentNextFormField}, {'f', 1, DocumentPreviousFormField},
{'g', 0, DocumentNextImage}, {'g', 1, DocumentPreviousImage},
{'m', 0, DocumentNextLandmark}, {'m', 1, DocumentPreviousLandmark},
{'i', 0, DocumentNextListItem}, {'i', 1, DocumentPreviousListItem},
{'d', 0, DocumentNextLiveRegion}, {'d', 1, DocumentPreviousLiveRegion},
{'p', 0, DocumentNextParagraph}, {'p', 1, DocumentPreviousParagraph},
{'r', 0, DocumentNextRadioButton}, {'r', 1, DocumentPreviousRadioButton},
{'t', 0, DocumentNextTable}, {'t', 1, DocumentPreviousTable},
{'u', 0, DocumentNextUnvisitedLink}, {'u', 1, DocumentPreviousUnvisitedLink},
{'v', 0, DocumentNextVisitedLink}, {'v', 1, DocumentPreviousVisitedLink},
{'a', 0, DocumentNextClickable}, {'a', 1, DocumentPreviousClickable},
{'o', 0, DocumentNextChunk}, {'o', 1, DocumentPreviousChunk},
{'1', 0, DocumentNextHeadingAtLevel1}, {'1', 1, DocumentPreviousHeadingAtLevel1},
{'2', 0, DocumentNextHeadingAtLevel2}, {'2', 1, DocumentPreviousHeadingAtLevel2},
{'3', 0, DocumentNextHeadingAtLevel3}, {'3', 1, DocumentPreviousHeadingAtLevel3},
{'4', 0, DocumentNextHeadingAtLevel4}, {'4', 1, DocumentPreviousHeadingAtLevel4},
{'5', 0, DocumentNextHeadingAtLevel5}, {'5', 1, DocumentPreviousHeadingAtLevel5},
{'6', 0, DocumentNextHeadingAtLevel6}, {'6', 1, DocumentPreviousHeadingAtLevel6},
{'h', 4, ""}, {'k', 8, ""},
} {
router := NewCommandRouter([]uint32{0xff63}, BrowseCommandBindings(DesktopKeyboardLayout))
consumed, command := router.Handle(tc.symbol, 43, tc.mods, true)
if consumed != (tc.want != "") || command != tc.want {
t.Fatalf("press: %v %s", consumed, command)
}
consumed, command = router.Handle(tc.symbol, 43, tc.mods, false)
if consumed != (tc.want != "") || command != "" {
t.Fatalf("release: %v %s want %s", consumed, command, Command(""))
}
}
}
func TestSpeechSettingBindings(t *testing.T) {
for _, layout := range []KeyboardLayout{DesktopKeyboardLayout, LaptopKeyboardLayout} {
for _, bindings := range []CommandBindings{DefaultCommandBindings(layout), BrowseCommandBindings(layout)} {
for _, test := range []struct {
symbol uint32
modifiers uint16
command Command
}{
{leftKeySymbol, 0, SelectPreviousSpeechSetting}, {rightKeySymbol, 0, SelectNextSpeechSetting},
{upKeySymbol, 0, IncreaseSpeechSetting}, {downKeySymbol, 0, DecreaseSpeechSetting},
{'s', controlModifier | 1, SaveSpeechSettings},
} {
router := NewCommandRouter([]uint32{0xff63}, bindings)
router.Handle(0xff63, 118, 0, true)
if consumed, command := router.Handle(test.symbol, 111, test.modifiers, true); !consumed || command != test.command {
t.Fatalf("press: %v %q", consumed, command)
}
router.Handle(0xff63, 118, 0, false)
if consumed, command := router.Handle(test.symbol, 111, test.modifiers, false); !consumed || command != "" {
t.Fatalf("release: %v %q", consumed, command)
}
}
}
}
}