1package input
2
3import (
4 "strings"
5
6 "github.com/bnema/dumber/internal/domain/vimkeys"
7 "github.com/bnema/puregotk/v4/gdk"
8)
9
10// namedKeyvalSym maps a GDK named keyval onto a canonical vimkeys symbol.
11// Immutable switch mirrors Phase 1 parser quality (no mutable package map).
12func namedKeyvalSym(keyval uint) (string, bool) {
13 switch keyval {
14 case uint(gdk.KEY_Escape):
15 return "Esc", true
16 case uint(gdk.KEY_Return), uint(gdk.KEY_KP_Enter):
17 return "CR", true
18 case uint(gdk.KEY_Tab), uint(gdk.KEY_ISO_Left_Tab):
19 return "Tab", true
20 case uint(gdk.KEY_BackSpace):
21 return "BackSpace", true
22 case uint(gdk.KEY_space):
23 return "Space", true
24 case uint(gdk.KEY_Left):
25 return "Left", true
26 case uint(gdk.KEY_Right):
27 return "Right", true
28 case uint(gdk.KEY_Up):
29 return "Up", true
30 case uint(gdk.KEY_Down):
31 return "Down", true
32 case uint(gdk.KEY_Home):
33 return "Home", true
34 case uint(gdk.KEY_End):
35 return "End", true
36 case uint(gdk.KEY_Page_Up):
37 return "PageUp", true
38 case uint(gdk.KEY_Page_Down):
39 return "PageDown", true
40 case uint(gdk.KEY_Delete):
41 return "Delete", true
42 default:
43 return "", false
44 }
45}
46
47// KeyvalToVimKey converts a GDK key event into a vimkeys.Key.
48// Named keys keep modifiers. Printable non-letter glyphs drop Shift because the
49// glyph already encodes it; Ctrl and Alt are preserved.
50func KeyvalToVimKey(keyval uint, state gdk.ModifierType) (vimkeys.Key, bool) {
51 mods := vimModsFromState(state)
52 if sym, ok := namedKeyvalSym(keyval); ok {
53 return vimkeys.Key{Sym: sym, Mods: mods}, true
54 }
55
56 r := rune(keyvalToUnicode(keyval))
57 if r == 0 || r < 0x20 {
58 return vimkeys.Key{}, false
59 }
60 if r >= 'A' && r <= 'Z' {
61 return vimkeys.Key{Sym: strings.ToLower(string(r)), Mods: mods}, true
62 }
63 if r >= 'a' && r <= 'z' {
64 return vimkeys.Key{Sym: string(r), Mods: mods}, true
65 }
66 return vimkeys.Key{Sym: string(r), Mods: mods &^ vimkeys.ModShift}, true
67}
68
69func vimModsFromState(state gdk.ModifierType) vimkeys.Mods {
70 var mods vimkeys.Mods
71 if state&gdk.ControlMaskValue != 0 {
72 mods |= vimkeys.ModCtrl
73 }
74 if state&gdk.ShiftMaskValue != 0 {
75 mods |= vimkeys.ModShift
76 }
77 if state&gdk.AltMaskValue != 0 {
78 mods |= vimkeys.ModAlt
79 }
80 return mods
81}
82
83// keyvalToUnicode mirrors gdk_keyval_to_unicode for Latin-1 graphic keysyms
84// (identity mapping) and falls back to GDK for the remaining keyvals.
85func keyvalToUnicode(keyval uint) uint32 {
86 // ASCII graphic and Latin-1 supplement keysyms share Unicode code points.
87 if keyval >= 0x20 && keyval <= 0x7e {
88 return uint32(keyval)
89 }
90 if keyval >= 0xa0 && keyval <= 0xff {
91 return uint32(keyval)
92 }
93 return gdk.KeyvalToUnicode(keyval)
94}