From 941a78eaf1cd5e471c07bc072485ec695027aff8 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Thu, 24 Nov 2022 22:02:32 -0500 Subject: [PATCH] THE DRAGON HAS BEEN SLAIN Numlock is fully supported, as well as shift lock. Of course, I cannot properly test shift lock or caps lock because I have neither of those things, but I assume they work as well as num lock does. --- backends/x/factory.go | 38 ++++++++++++++++++++ backends/x/unicode.go | 81 +++++++++++++++++++++++++++++++++++-------- backends/x/x.go | 7 ++++ 3 files changed, 112 insertions(+), 14 deletions(-) diff --git a/backends/x/factory.go b/backends/x/factory.go index 8a4a942..21ff165 100644 --- a/backends/x/factory.go +++ b/backends/x/factory.go @@ -74,7 +74,13 @@ func factory ( if err != nil { return } backend.window, err = xwindow.Generate(backend.connection) if err != nil { return } + + // get keyboard mapping information keybind.Initialize(backend.connection) + backend.modifierMasks.capsLock = backend.keysymToMask(0xFFE5) + backend.modifierMasks.shiftLock = backend.keysymToMask(0xFFE6) + backend.modifierMasks.numLock = backend.keysymToMask(0xFF7F) + backend.modifierMasks.modeSwitch = backend.keysymToMask(0xFF7E) // create the window backend.window.Create ( @@ -158,6 +164,38 @@ func findAndLoadFont (name string, size float64) (face font.Face) { return } +func (backend *Backend) keysymToKeycode ( + symbol xproto.Keysym, +) ( + code xproto.Keycode, +) { + mapping := keybind.KeyMapGet(backend.connection) + + for index, testSymbol := range mapping.Keysyms { + if testSymbol == symbol { + code = xproto.Keycode ( + index / + int(mapping.KeysymsPerKeycode) + + int(backend.connection.Setup().MinKeycode)) + break + } + } + + return +} + +func (backend *Backend) keysymToMask ( + symbol xproto.Keysym, +) ( + mask uint16, +) { + mask = keybind.ModGet ( + backend.connection, + backend.keysymToKeycode(symbol)) + + return +} + // init registers this backend when the program starts. func init () { stone.RegisterBackend(factory) diff --git a/backends/x/unicode.go b/backends/x/unicode.go index ec917d3..a48cc46 100644 --- a/backends/x/unicode.go +++ b/backends/x/unicode.go @@ -1,5 +1,7 @@ package x +// TODO: rename this file? lol + // import "fmt" import "unicode" import "github.com/jezek/xgb/xproto" @@ -117,13 +119,11 @@ func (backend *Backend) keycodeToButton ( button stone.Button, numberPad bool, ) { - // 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 + shift := + state & xproto.ModMaskShift > 0 || + state & backend.modifierMasks.shiftLock > 0 + capsLock := state & backend.modifierMasks.capsLock > 0 + numLock := state & backend.modifierMasks.numLock > 0 symbol1 := keybind.KeysymGet(backend.connection, keycode, 0) symbol2 := keybind.KeysymGet(backend.connection, keycode, 1) @@ -132,7 +132,19 @@ func (backend *Backend) keycodeToButton ( cased := false - // third paragraph + // PARAGRAPH 3 + // + // A list of KeySyms is associated with each KeyCode. The list is + // intended to convey the set of symbols on the corresponding key. If + // the list (ignoring trailing NoSymbol entries) is a single KeySym + // ``K'', then the list is treated as if it were the list ``K NoSymbol + // K NoSymbol''. If the list (ignoring trailing NoSymbol entries) is a + // pair of KeySyms ``K1 K2'', then the list is treated as if it were the + // list ``K1 K2 K1 K2''. If the list (ignoring trailing NoSymbol + // entries) is a triple of KeySyms ``K1 K2 K3'', then the list is + // treated as if it were the list ``K1 K2 K3 NoSymbol''. When an + // explicit ``void'' element is desired in the list, the value + // VoidSymbol can be used. switch { case symbol2 == 0 && symbol3 == 0 && symbol4 == 0: symbol3 = symbol1 @@ -151,7 +163,18 @@ func (backend *Backend) keycodeToButton ( // FIXME: we ignore mode switch stuff _ = symbol4Rune - // fourth paragraph + // PARAGRAPH 4 + // + // The first four elements of the list are split into two groups of + // KeySyms. Group 1 contains the first and second KeySyms; Group 2 + // contains the third and fourth KeySyms. Within each group, if the + // second element of the group is NoSymbol , then the group should be + // treated as if the second element were the same as the first element, + // except when the first element is an alphabetic KeySym ``K'' for which + // both lowercase and uppercase forms are defined. In that case, the + // group should be treated as if the first element were the lowercase + // form of ``K'' and the second element were the uppercase form of + // ``K.'' if symbol2 == 0 { upper := unicode.IsUpper(symbol1Rune) lower := unicode.IsLower(symbol1Rune) @@ -180,30 +203,60 @@ func (backend *Backend) keycodeToButton ( var selectedKeysym xproto.Keysym var selectedRune rune - // big ol list in the middle + _, symbol2IsNumPad := keypadCodeTable[symbol2] + + // "PARAGRAPH" 5 + // + // Within a group, the choice of KeySym is determined by applying the + // first rule that is satisfied from the following list: switch { - // FIXME: take into account numlock + case numLock && symbol2IsNumPad: + // The numlock modifier is on and the second KeySym is a keypad + // KeySym. In this case, if the Shift modifier is on, or if the + // Lock modifier is on and is interpreted as ShiftLock, then the + // first KeySym is used, otherwise the second KeySym is used. + if shift { + selectedKeysym = symbol1 + selectedRune = symbol1Rune + } else { + selectedKeysym = symbol2 + selectedRune = symbol2Rune + } + case !shift && !capsLock: + // The Shift and Lock modifiers are both off. In this case, the + // first KeySym is used. selectedKeysym = symbol1 selectedRune = symbol1Rune - + case !shift && capsLock: + // The Shift modifier is off, and the Lock modifier is on and is + // interpreted as CapsLock. In this case, the first KeySym is + // used, but if that KeySym is lowercase alphabetic, then the + // corresponding uppercase KeySym is used instead. if cased && unicode.IsLower(symbol1Rune) { selectedRune = symbol2Rune } else { selectedKeysym = symbol1 selectedRune = symbol1Rune } - + case shift && capsLock: + // The Shift modifier is on, and the Lock modifier is on and is + // interpreted as CapsLock. In this case, the second KeySym is + // used, but if that KeySym is lowercase alphabetic, then the + // corresponding uppercase KeySym is used instead. if cased && unicode.IsLower(symbol2Rune) { selectedRune = unicode.ToUpper(symbol2Rune) } else { selectedKeysym = symbol2 selectedRune = symbol2Rune } - + case shift: + // The Shift modifier is on, or the Lock modifier is on and is + // interpreted as ShiftLock, or both. In this case, the second + // KeySym is used. selectedKeysym = symbol2 selectedRune = symbol2Rune } diff --git a/backends/x/x.go b/backends/x/x.go index 74a7818..67e764b 100644 --- a/backends/x/x.go +++ b/backends/x/x.go @@ -43,6 +43,13 @@ type Backend struct { descent int } + modifierMasks struct { + capsLock uint16 + shiftLock uint16 + numLock uint16 + modeSwitch uint16 + } + windowBoundsClean bool }