package rdp import "testing" func TestScancodeMapping(t *testing.T) { tests := []struct { jsCode string expected uint32 }{ {"Escape", 0x0001}, {"Digit1", 0x0002}, {"Digit0", 0x000B}, {"KeyA", 0x001E}, {"KeyZ", 0x002C}, {"Enter", 0x001C}, {"Space", 0x0039}, {"Tab", 0x000F}, {"Backspace", 0x000E}, {"ShiftLeft", 0x002A}, {"ShiftRight", 0x0036}, {"ControlLeft", 0x001D}, {"ControlRight", 0xE01D}, {"AltLeft", 0x0038}, {"AltRight", 0xE038}, {"CapsLock", 0x003A}, {"F1", 0x003B}, {"F12", 0x0058}, {"ArrowUp", 0xE048}, {"ArrowDown", 0xE050}, {"ArrowLeft", 0xE04B}, {"ArrowRight", 0xE04D}, {"Insert", 0xE052}, {"Delete", 0xE053}, {"Home", 0xE047}, {"End", 0xE04F}, {"PageUp", 0xE049}, {"PageDown", 0xE051}, {"NumLock", 0x0045}, {"Numpad0", 0x0052}, {"Numpad9", 0x0049}, {"NumpadEnter", 0xE01C}, {"NumpadAdd", 0x004E}, {"NumpadSubtract", 0x004A}, {"NumpadMultiply", 0x0037}, {"NumpadDivide", 0xE035}, {"NumpadDecimal", 0x0053}, {"MetaLeft", 0xE05B}, {"MetaRight", 0xE05C}, {"ContextMenu", 0xE05D}, {"PrintScreen", 0xE037}, {"ScrollLock", 0x0046}, {"Backquote", 0x0029}, {"Minus", 0x000C}, {"Equal", 0x000D}, {"BracketLeft", 0x001A}, {"BracketRight", 0x001B}, {"Backslash", 0x002B}, {"Semicolon", 0x0027}, {"Quote", 0x0028}, {"Comma", 0x0033}, {"Period", 0x0034}, {"Slash", 0x0035}, } for _, tt := range tests { t.Run(tt.jsCode, func(t *testing.T) { sc, ok := JSKeyToScancode(tt.jsCode) if !ok { t.Fatalf("JSKeyToScancode(%q) returned false", tt.jsCode) } if sc != tt.expected { t.Errorf("JSKeyToScancode(%q) = 0x%04X, want 0x%04X", tt.jsCode, sc, tt.expected) } }) } } func TestAllLetterKeys(t *testing.T) { // Verify all 26 letter keys are mapped letters := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" for _, ch := range letters { code := "Key" + string(ch) _, ok := JSKeyToScancode(code) if !ok { t.Errorf("missing mapping for %s", code) } } } func TestAllDigitKeys(t *testing.T) { for i := 0; i <= 9; i++ { code := "Digit" + string(rune('0'+i)) _, ok := JSKeyToScancode(code) if !ok { t.Errorf("missing mapping for %s", code) } } } func TestAllFunctionKeys(t *testing.T) { fKeys := []string{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12"} for _, key := range fKeys { _, ok := JSKeyToScancode(key) if !ok { t.Errorf("missing mapping for %s", key) } } } func TestAllNumpadKeys(t *testing.T) { numpadKeys := []string{ "Numpad0", "Numpad1", "Numpad2", "Numpad3", "Numpad4", "Numpad5", "Numpad6", "Numpad7", "Numpad8", "Numpad9", "NumpadAdd", "NumpadSubtract", "NumpadMultiply", "NumpadDivide", "NumpadDecimal", "NumpadEnter", "NumLock", } for _, key := range numpadKeys { _, ok := JSKeyToScancode(key) if !ok { t.Errorf("missing mapping for %s", key) } } } func TestUnknownKey(t *testing.T) { sc, ok := JSKeyToScancode("FakeKey123") if ok { t.Errorf("unknown key returned ok=true with scancode 0x%04X", sc) } if sc != 0 { t.Errorf("unknown key scancode = 0x%04X, want 0", sc) } } func TestIsExtendedKey(t *testing.T) { tests := []struct { name string scancode uint32 extended bool }{ {"Escape (not extended)", 0x0001, false}, {"Enter (not extended)", 0x001C, false}, {"Right Ctrl (extended)", 0xE01D, true}, {"Right Alt (extended)", 0xE038, true}, {"ArrowUp (extended)", 0xE048, true}, {"Insert (extended)", 0xE052, true}, {"NumpadEnter (extended)", 0xE01C, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := IsExtendedKey(tt.scancode) if got != tt.extended { t.Errorf("IsExtendedKey(0x%04X) = %v, want %v", tt.scancode, got, tt.extended) } }) } } func TestScancodeValue(t *testing.T) { tests := []struct { name string scancode uint32 value uint8 }{ {"Escape", 0x0001, 0x01}, {"Right Ctrl", 0xE01D, 0x1D}, {"ArrowUp", 0xE048, 0x48}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := ScancodeValue(tt.scancode) if got != tt.value { t.Errorf("ScancodeValue(0x%04X) = 0x%02X, want 0x%02X", tt.scancode, got, tt.value) } }) } } func TestMouseFlags(t *testing.T) { // Verify the flag constants have the right values if MouseFlagMove != 0x0800 { t.Errorf("MouseFlagMove = 0x%04X, want 0x0800", MouseFlagMove) } if MouseFlagButton1 != 0x1000 { t.Errorf("MouseFlagButton1 = 0x%04X, want 0x1000", MouseFlagButton1) } if MouseFlagButton2 != 0x2000 { t.Errorf("MouseFlagButton2 = 0x%04X, want 0x2000", MouseFlagButton2) } if MouseFlagButton3 != 0x4000 { t.Errorf("MouseFlagButton3 = 0x%04X, want 0x4000", MouseFlagButton3) } if MouseFlagDown != 0x8000 { t.Errorf("MouseFlagDown = 0x%04X, want 0x8000", MouseFlagDown) } // Test combining flags — left click down flags := MouseFlagButton1 | MouseFlagDown if flags != 0x9000 { t.Errorf("left click down = 0x%04X, want 0x9000", flags) } // Test combining flags — right click up (no Down flag) flags = MouseFlagButton2 if flags != 0x2000 { t.Errorf("right click up = 0x%04X, want 0x2000", flags) } } func TestScancodeMapCompleteness(t *testing.T) { // Minimum expected mappings for a standard 104-key US keyboard: // 26 letters + 10 digits + 12 F-keys + escape + tab + caps + 2 shifts + // 2 ctrls + 2 alts + 2 metas + space + enter + backspace + // numrow punctuation (backquote, minus, equal) + // bracket pair + backslash + semicolon + quote + comma + period + slash + // 4 arrows + insert + delete + home + end + pageup + pagedown + // printscreen + scrolllock + pause + // numlock + numpad 0-9 + numpad operators (5) + numpad enter + numpad decimal + // context menu // = 26+10+12+1+1+1+2+2+2+2+1+1+1+3+2+1+1+1+1+1+1+4+6+3+1+10+5+1+1+1 = ~104 minExpected := 90 // conservative lower bound for core keys if len(ScancodeMap) < minExpected { t.Errorf("ScancodeMap has %d entries, expected at least %d", len(ScancodeMap), minExpected) } }