From 84cd21b16d38589fd6d4a978e19d62890fbaa11d Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Mon, 14 Nov 2022 22:33:46 -0500 Subject: [PATCH] Added untested advanced keycode translation --- backends/x/event.go | 8 +-- backends/x/unicode.go | 133 +++++++++++++++++++++++++++++++++++------- 2 files changed, 116 insertions(+), 25 deletions(-) diff --git a/backends/x/event.go b/backends/x/event.go index 45d7ebb..04154e5 100644 --- a/backends/x/event.go +++ b/backends/x/event.go @@ -58,8 +58,8 @@ func (backend *Backend) handleKeyPress ( event xevent.KeyPressEvent, ) { keyEvent := *event.KeyPressEvent - keysym := backend.keycodeToKeysym(keyEvent.Detail) - backend.channel <- stone.EventPress(keysymToButtonCode(keysym)) + button := backend.keycodeToButton(keyEvent.Detail, keyEvent.State) + backend.channel <- stone.EventPress(button) } func (backend *Backend) handleKeyRelease ( @@ -67,8 +67,8 @@ func (backend *Backend) handleKeyRelease ( event xevent.KeyReleaseEvent, ) { keyEvent := *event.KeyReleaseEvent - keysym := backend.keycodeToKeysym(keyEvent.Detail) - backend.channel <- stone.EventRelease(keysymToButtonCode(keysym)) + button := backend.keycodeToButton(keyEvent.Detail, keyEvent.State) + backend.channel <- stone.EventRelease(button) } func (backend *Backend) handleMotionNotify ( diff --git a/backends/x/unicode.go b/backends/x/unicode.go index b1c2df3..0cb45a5 100644 --- a/backends/x/unicode.go +++ b/backends/x/unicode.go @@ -1,5 +1,6 @@ package x +import "unicode" import "github.com/jezek/xgb/xproto" import "github.com/jezek/xgbutil/keybind" import "git.tebibyte.media/sashakoshka/stone" @@ -55,48 +56,138 @@ var buttonCodeTable = map[xproto.Keysym] stone.Button { 0xFFC9: stone.KeyF12, } -func (backend *Backend) keycodeToKeysym ( +func (backend *Backend) keycodeToButton ( keycode xproto.Keycode, + state uint16, ) ( - keysym xproto.Keysym, + button stone.Button, ) { - keysym = keybind.KeysymGet(backend.connection, keycode, 0) + // FIXME: also set shift to true if the lock modifier is on and the lock + // modifier is interpreted as shiftLock + shift := state & xproto.ModMaskShift > 0 + + // FIXME: only set this to true if the lock modifier is on and the lock + // modifier is interpreted as capsLock + capsLock := state & xproto.ModMaskLock > 0 + + symbol1 := keybind.KeysymGet(backend.connection, keycode, 0) + symbol2 := keybind.KeysymGet(backend.connection, keycode, 1) + symbol3 := keybind.KeysymGet(backend.connection, keycode, 2) + symbol4 := keybind.KeysymGet(backend.connection, keycode, 3) + + cased := false + + // third paragraph + switch { + case symbol2 == 0 && symbol3 == 0 && symbol4 == 0: + symbol3 = symbol1 + case symbol3 == 0 && symbol4 == 0: + symbol3 = symbol1 + symbol2 = symbol2 + case symbol4 == 0: + symbol4 = 0 + } + + symbol1Rune := keysymToRune(symbol1) + symbol2Rune := keysymToRune(symbol2) + symbol3Rune := keysymToRune(symbol3) + symbol4Rune := keysymToRune(symbol4) + + // FIXME: we ignore mode switch stuff + _ = symbol4Rune + + // fourth paragraph + if symbol2 == 0 { + upper := unicode.IsUpper(symbol1Rune) + lower := unicode.IsLower(symbol1Rune) + if upper || lower { + symbol1Rune = unicode.ToLower(symbol1Rune) + symbol2Rune = unicode.ToUpper(symbol1Rune) + cased = true + } else { + symbol2 = symbol1 + } + } + if symbol4 == 0 { + upper := unicode.IsUpper(symbol3Rune) + lower := unicode.IsLower(symbol3Rune) + if upper || lower { + symbol3Rune = unicode.ToLower(symbol3Rune) + symbol4Rune = unicode.ToUpper(symbol3Rune) + cased = true + } else { + symbol4 = symbol3 + } + } + + var selectedKeysym xproto.Keysym + var selectedRune rune + + // big ol list in the middle + switch { + // FIXME: take into account numlock + case !shift && !capsLock: + selectedKeysym = symbol1 + selectedRune = symbol1Rune + + case !shift && capsLock: + if cased && unicode.IsLower(symbol1Rune) { + selectedRune = symbol2Rune + } else { + selectedKeysym = symbol1 + selectedRune = symbol1Rune + } + + case shift && capsLock: + if cased && unicode.IsLower(symbol2Rune) { + selectedRune = unicode.ToUpper(symbol2Rune) + } else { + selectedKeysym = symbol2 + selectedRune = symbol2Rune + } + + case shift: + selectedKeysym = symbol3 + selectedRune = symbol3Rune + } + + // look up in table + var isControl bool + button, isControl = buttonCodeTable[selectedKeysym] + if isControl { return } + + button = stone.Button(selectedRune) // TODO: shift isnt working. follow // https://tronche.com/gui/x/xlib/input/keyboard-encoding.html println("--") println(keycode) - println(keysym) - println(stone.EventPress(keysymToButtonCode(keysym))) + println(selectedKeysym) + println(selectedRune) + println(button) return } -func keysymToButtonCode (keysym xproto.Keysym) (button stone.Button) { - var isControl bool - button, isControl = buttonCodeTable[keysym] - if isControl { return } - +func keysymToRune (keysym xproto.Keysym) (character rune) { + // X keysyms like 0xFF.. or 0xFE.. are non-character keys. these cannot + // be converted so we return a zero. + if (keysym >> 8) == 0xFF || (keysym >> 8) == 0xFE { + character = 0 + return + } + // some X keysyms have a single bit set to 1 here. i believe this is to // prevent conflicts with existing codes. if we mask it off we will get // a correct utf-32 code point. if keysym & 0xF000000 == 0x1000000 { - button = stone.Button(keysym & 0x0111111) - return - } - - // X keysyms like 0xFF.. or 0xFE.. are non-character keys. we already - // resolve these by looking them up in the button code table, so if any - // that we don't support pop up we should just silence them as it is - // effectively garbage data as far as stone applications are concerned. - if (keysym >> 8) == 0xFF || (keysym >> 8) == 0xFE { - button = stone.ButtonUnknown + character = rune(keysym & 0x0111111) return } // if none of these things happened, we can safely (i think) assume that // the keysym is an exact utf-32 code point. - button = stone.Button(keysym) + character = rune(keysym) return }