Default laptop key set to capslock. Keys that can be set to fenrir key or script key selectable via checkbox.

This commit is contained in:
Storm Dragon committed 2026-10-29 18:01:42 -04:00
1 parent 47f18fdd28
commit 15e04aa8f8
47 files changed
+1560 -351

No files matched your search

+93 -35
View File
@@ -37,6 +37,7 @@ const (
KeyRightShift = 54
KeyAlt = 56
KeySpace = 57
KeyCapsLock = 58
KeyF4 = 62
KeyKP7 = 71
KeyKP8 = 72
@@ -66,34 +67,37 @@ const (
)
type Decision struct {
Code uint16 // physical key code, for forwarded application press/repeat hooks
Forward bool
Interrupt bool
Keypress bool // a fresh physical press, excluding repeats and state repair
Deletion bool // forwarded Backspace/Delete, including repeats
Typing bool // forwarded text key or repeat; the screen supplies its actual text
WordBoundary bool // a forwarded Space, rather than cursor navigation
Command command.ID
UI *interaction.Key
Learn *LearnKey // captured physical press and its inactive command
Code uint16 // physical key code, for forwarded application press/repeat hooks
ToggleCapsLock bool // completed Shift+Caps Lock gesture
Forward bool
Interrupt bool
Keypress bool // a fresh physical press, excluding repeats and state repair
Deletion bool // forwarded Backspace/Delete, including repeats
Typing bool // forwarded text key or repeat; the screen supplies its actual text
WordBoundary bool // a forwarded Space, rather than cursor navigation
Command command.ID
UI *interaction.Key
Learn *LearnKey // captured physical press and its inactive command
}
type Router struct {
keys map[int]map[uint16]heldKey
passArmed bool
passing bool
captured bool
bindings map[chord]command.ID
doubleBindings map[chord]command.ID
tripleBindings map[chord]command.ID
multiPressTimeout time.Duration
pressCount int
lastChord chord
lastDevice int
lastPress time.Time
now func() time.Time
scriptKeys map[uint16]bool
scriptBindings map[string]command.ID
readerKeys map[uint16]bool
capsShift, capsUsed bool
keys map[int]map[uint16]heldKey
passArmed bool
passing bool
captured bool
bindings map[chord]command.ID
doubleBindings map[chord]command.ID
tripleBindings map[chord]command.ID
multiPressTimeout time.Duration
pressCount int
lastChord chord
lastDevice int
lastPress time.Time
now func() time.Time
scriptKeys map[uint16]bool
scriptBindings map[string]command.ID
}
type heldKey struct {
@@ -104,6 +108,7 @@ type heldKey struct {
func (r *Router) Reset() {
r.lastPress = time.Time{}
r.capsShift, r.capsUsed = false, false
r.keys = nil
r.passArmed = false
r.passing = false
@@ -111,6 +116,7 @@ func (r *Router) Reset() {
}
func (r *Router) Drop(device int) {
r.capsUsed = true
r.lastPress = time.Time{}
delete(r.keys, device)
if r.empty() {
@@ -161,6 +167,7 @@ func (r *Router) key(device int, key uint16, value int32, numLock, syncEvent, re
_, held := r.keys[device][key]
if value == 0 && held || value == 1 && !held {
r.lastPress = time.Time{}
r.capsUsed = true
}
}
if r.keys == nil {
@@ -176,7 +183,11 @@ func (r *Router) key(device int, key uint16, value int32, numLock, syncEvent, re
if r.empty() {
r.passing = false
}
return Decision{Forward: exists && state.forwarded}
toggle := key == KeyCapsLock && exists && !state.forwarded && r.Caps_modifier() && r.capsShift && !r.capsUsed && !syncEvent && !r.captured && !r.passing
if key == KeyCapsLock {
r.capsShift, r.capsUsed = false, false
}
return Decision{Forward: exists && state.forwarded, ToggleCapsLock: toggle}
}
if value != 1 && value != 2 {
return Decision{}
@@ -204,13 +215,34 @@ func (r *Router) key(device int, key uint16, value int32, numLock, syncEvent, re
if value == 2 {
return Decision{}
}
if !syncEvent && r.Caps_modifier() {
switch key {
case KeyCapsLock:
r.capsShift, r.capsUsed = r.down(KeyShift) || r.down(KeyRightShift), false
for _, held := range r.keys {
for code := range held {
if code != KeyShift && code != KeyRightShift {
r.capsUsed = true
}
}
}
case KeyShift, KeyRightShift:
if r.down(KeyCapsLock) {
r.capsShift = true
}
default:
if r.down(KeyCapsLock) {
r.capsUsed = true
}
}
}
if r.captured {
var learn *LearnKey
if !syncEvent {
learn = r.learn_key(device, key, numLock)
}
held[key] = heldKey{ui: true}
if syncEvent || pure_modifier(key) {
if syncEvent || pure_modifier(key) || r.reader_modifier(key, numLock) {
return Decision{Learn: learn, Keypress: !syncEvent, Interrupt: !syncEvent && (key == KeyCtrl || key == KeyRightCtrl)}
}
decision := r.ui_key(key)
@@ -229,10 +261,10 @@ func (r *Router) key(device int, key uint16, value int32, numLock, syncEvent, re
commandID = r.binding(key, numLock)
}
}
if !syncEvent && !pure_modifier(key) && !reader_modifier(key, numLock) {
if !syncEvent && !pure_modifier(key) && !r.reader_modifier(key, numLock) {
commandID = r.multi_press(device, r.binding_chord(key, numLock), commandID, scriptChord)
}
forwarded := commandID == "" && !scriptChord && !(reader_modifier(key, numLock) && !r.passing)
forwarded := commandID == "" && !scriptChord && !(r.reader_modifier(key, numLock) && !r.passing)
held[key] = heldKey{forwarded: forwarded, commandID: commandID}
if syncEvent {
return Decision{Forward: forwarded}
@@ -243,11 +275,11 @@ func (r *Router) key(device int, key uint16, value int32, numLock, syncEvent, re
func (r *Router) typing_key(key uint16, numLock bool) bool {
for scriptKey := range r.scriptKeys {
if r.down(scriptKey) {
if r.script_modifier(scriptKey, numLock) && r.down(scriptKey) {
return false
}
}
if r.down(KeyCtrl) || r.down(KeyRightCtrl) || r.down(KeyAlt) || r.down(KeyInsert) || r.down(KeyMeta) || r.down(KeyRightMeta) {
if r.down(KeyCtrl) || r.down(KeyRightCtrl) || r.down(KeyAlt) || r.reader_down(numLock) || r.down(KeyMeta) || r.down(KeyRightMeta) {
return false
}
// Physical text-key positions, independent of keyboard layout. AltGr is
@@ -284,8 +316,34 @@ func (r *Router) empty() bool {
return true
}
func reader_modifier(key uint16, numLock bool) bool {
return key == KeyInsert || key == KeyMeta || key == KeyRightMeta || key == KeyKP0 && !numLock
func (r *Router) reader_modifier(key uint16, numLock bool) bool {
if r.readerKeys == nil {
return key == KeyInsert || key == KeyMeta || key == KeyRightMeta || key == KeyKP0 && !numLock
}
return r.readerKeys[key] && (key != KeyKP0 || !numLock)
}
// Caps_modifier reports whether Caps Lock is reserved for reader or script chords.
func (r *Router) Caps_modifier() bool { return r.readerKeys[KeyCapsLock] || r.scriptKeys[KeyCapsLock] }
// Reader_keys supplies the X11 adapter with the physical keys to intercept.
func (r *Router) Reader_keys() []uint16 {
var keys []uint16
for _, key := range []uint16{KeyInsert, KeyMeta, KeyRightMeta, KeyCapsLock, KeyKP0} {
if r.reader_modifier(key, false) {
keys = append(keys, key)
}
}
return keys
}
func (r *Router) reader_down(numLock bool) bool {
for _, key := range r.Reader_keys() {
if r.reader_modifier(key, numLock) && r.down(key) {
return true
}
}
return false
}
func pure_modifier(key uint16) bool {
@@ -293,7 +351,7 @@ func pure_modifier(key uint16) bool {
}
func (r *Router) binding(key uint16, numLock bool) command.ID {
if reader_modifier(key, numLock) || pure_modifier(key) {
if r.reader_modifier(key, numLock) || pure_modifier(key) {
return ""
}
combo := r.binding_chord(key, numLock)
@@ -311,7 +369,7 @@ func (r *Router) binding(key uint16, numLock bool) command.ID {
func (r *Router) binding_chord(key uint16, numLock bool) chord {
var mods modifiers
if r.down(KeyInsert) || r.down(KeyMeta) || r.down(KeyRightMeta) || !numLock && r.down(KeyKP0) {
if r.reader_down(numLock) {
mods |= fenrirModifier
}
if r.down(KeyCtrl) || r.down(KeyRightCtrl) {