From 9d2872f256889172f8cfbfd25490ffe10ff8c622 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Fri, 25 Nov 2022 13:33:28 -0500 Subject: [PATCH] Support mode shift modifier The code has also been reorganized and cleaned up a bit, with more comments added. --- backends/x/unicode.go | 85 ++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/backends/x/unicode.go b/backends/x/unicode.go index a48cc46..debe6a6 100644 --- a/backends/x/unicode.go +++ b/backends/x/unicode.go @@ -112,6 +112,10 @@ var keypadCodeTable = map[xproto.Keysym] stone.Button { 0xffb9: stone.Button('9'), } +// keycodeToButton converts an X keycode to a stone button code. It implements +// a more fleshed out version of some of the logic found in +// xgbutil/keybind/encoding.go to get a full keycode to keysym conversion, but +// eliminates redundant work by going straight to a button code. func (backend *Backend) keycodeToButton ( keycode xproto.Keycode, state uint16, @@ -119,19 +123,6 @@ func (backend *Backend) keycodeToButton ( button stone.Button, numberPad bool, ) { - 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) - symbol3 := keybind.KeysymGet(backend.connection, keycode, 2) - symbol4 := keybind.KeysymGet(backend.connection, keycode, 3) - - cased := false - // PARAGRAPH 3 // // A list of KeySyms is associated with each KeyCode. The list is @@ -145,6 +136,10 @@ func (backend *Backend) keycodeToButton ( // 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. + 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) switch { case symbol2 == 0 && symbol3 == 0 && symbol4 == 0: symbol3 = symbol1 @@ -154,15 +149,11 @@ func (backend *Backend) keycodeToButton ( case symbol4 == 0: symbol4 = 0 } - symbol1Rune := keysymToRune(symbol1) symbol2Rune := keysymToRune(symbol2) symbol3Rune := keysymToRune(symbol3) symbol4Rune := keysymToRune(symbol4) - // FIXME: we ignore mode switch stuff - _ = symbol4Rune - // PARAGRAPH 4 // // The first four elements of the list are split into two groups of @@ -175,6 +166,7 @@ func (backend *Backend) keycodeToButton ( // 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.'' + cased := false if symbol2 == 0 { upper := unicode.IsUpper(symbol1Rune) lower := unicode.IsLower(symbol1Rune) @@ -200,15 +192,59 @@ func (backend *Backend) keycodeToButton ( } } - var selectedKeysym xproto.Keysym - var selectedRune rune + // PARAGRAPH 5 + // + // The standard rules for obtaining a KeySym from a KeyPress event make + // use of only the Group 1 and Group 2 KeySyms; no interpretation of/ + // other KeySyms in the list is given. Which group to use is determined + // by the modifier state. Switching between groups is controlled by the + // KeySym named MODE SWITCH, by attaching that KeySym to some KeyCode + // and attaching that KeyCode to any one of the modifiers Mod1 through + // Mod5. This modifier is called the group modifier. For any KeyCode, + // Group 1 is used when the group modifier is off, and Group 2 is used + // when the group modifier is on. + modeSwitch := state & backend.modifierMasks.modeSwitch > 0 + if modeSwitch { + symbol1 = symbol3 + symbol1Rune = symbol3Rune + symbol2 = symbol4 + symbol2Rune = symbol4Rune + + } - _, symbol2IsNumPad := keypadCodeTable[symbol2] + // PARAGRAPH 6 + // + // The Lock modifier is interpreted as CapsLock when the KeySym named + // XK_Caps_Lock is attached to some KeyCode and that KeyCode is attached + // to the Lock modifier. The Lock modifier is interpreted as ShiftLock + // when the KeySym named XK_Shift_Lock is attached to some KeyCode and + // that KeyCode is attached to the Lock modifier. If the Lock modifier + // could be interpreted as both CapsLock and ShiftLock, the CapsLock + // interpretation is used. + shift := + state & xproto.ModMaskShift > 0 || + state & backend.modifierMasks.shiftLock > 0 + capsLock := state & backend.modifierMasks.capsLock > 0 - // "PARAGRAPH" 5 + // PARAGRAPH 7 + // + // The operation of keypad keys is controlled by the KeySym named + // XK_Num_Lock, by attaching that KeySym to some KeyCode and attaching + // that KeyCode to any one of the modifiers Mod1 through Mod5 . This + // modifier is called the numlock modifier. The standard KeySyms with + // the prefix ``XK_KP_'' in their name are called keypad KeySyms; these + // are KeySyms with numeric value in the hexadecimal range 0xFF80 to + // 0xFFBD inclusive. In addition, vendor-specific KeySyms in the + // hexadecimal range 0x11000000 to 0x1100FFFF are also keypad KeySyms. + numLock := state & backend.modifierMasks.numLock > 0 + + // PARAGRAPH 8 // // Within a group, the choice of KeySym is determined by applying the // first rule that is satisfied from the following list: + var selectedKeysym xproto.Keysym + var selectedRune rune + _, symbol2IsNumPad := keypadCodeTable[symbol2] switch { case numLock && symbol2IsNumPad: // The numlock modifier is on and the second KeySym is a keypad @@ -261,6 +297,10 @@ func (backend *Backend) keycodeToButton ( selectedRune = symbol2Rune } + ///////////////////////////////////////////////////////////////// + // all of the below stuff is specific to stone's button codes. // + ///////////////////////////////////////////////////////////////// + // look up in control code table var isControl bool button, isControl = buttonCodeTable[selectedKeysym] @@ -276,6 +316,9 @@ func (backend *Backend) keycodeToButton ( return } +// keysymToRune takes in an X keysym and outputs a utf32 code point. This +// function does not and should not handle keypad keys, as those are handled +// by Backend.keycodeToButton. 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.