Files
fenrir/internal/input/modifiers_linux.go

156 lines
3.8 KiB
Go

// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
//go:build linux && cgo
package input
import (
"fmt"
"strings"
)
// Modifier_codes expands generic modifiers to their physical left/right keys.
func Modifier_codes(names []string) (map[uint16]bool, error) {
keys := make(map[uint16]bool)
for _, name := range names {
code, ok := Key_code(name)
if !ok {
return nil, fmt.Errorf("invalid modifier key %q", name)
}
keys[code] = true
switch strings.ToUpper(name) {
case "KEY_META":
keys[KeyRightMeta] = true
case "KEY_CTRL":
keys[KeyRightCtrl] = true
case "KEY_SHIFT":
keys[KeyRightShift] = true
case "KEY_ALT":
keys[KeyRightAlt] = true
}
}
return keys, nil
}
// Fenrir_codes validates the supported configurable reader modifiers.
func Fenrir_codes(names []string) (map[uint16]bool, error) {
if len(names) == 0 {
return nil, fmt.Errorf("select at least one Fenrir key")
}
keys, err := Modifier_codes(names)
if err != nil {
return nil, err
}
for code := range keys {
switch code {
case KeyInsert, KeyKP0, KeyCapsLock, KeyMeta, KeyRightMeta:
default:
return nil, fmt.Errorf("unsupported Fenrir key %q", Key_name(code))
}
}
return keys, nil
}
func Validate_modifier_keys(fenrirKeys, scriptKeys []string) error {
reader, err := Fenrir_codes(fenrirKeys)
if err != nil {
return err
}
scripts, err := Modifier_codes(scriptKeys)
if err != nil {
return err
}
for code := range scripts {
if reader[code] {
return fmt.Errorf("%s cannot be both a Fenrir key and a script key", Key_name(code))
}
}
return nil
}
func (r *Router) Set_fenrir_keys(names []string) error {
keys, err := Fenrir_codes(names)
if err != nil {
return err
}
for key := range keys {
if r.scriptKeys[key] {
return fmt.Errorf("%s cannot be both a Fenrir key and a script key", Key_name(key))
}
}
r.Reset()
r.readerKeys = keys
return nil
}
// Fenrir_keys returns the effective selection for the settings form.
func (r *Router) Fenrir_keys() []string {
var keys []string
for _, code := range []uint16{KeyKP0, KeyInsert, KeyCapsLock, KeyMeta, KeyRightMeta} {
if !r.reader_modifier(code, false) {
continue
}
if code == KeyMeta && r.reader_modifier(KeyRightMeta, false) {
keys = append(keys, "KEY_META")
continue
}
if code == KeyRightMeta && r.reader_modifier(KeyMeta, false) {
continue
}
keys = append(keys, Key_name(code))
}
return keys
}
func (r *Router) script_modifier(key uint16, numLock bool) bool {
return r.scriptKeys[key] && (key != KeyKP0 || !numLock)
}
// Available_fenrir_keys keeps explicitly configured script keys out of reader
// defaults. Explicit reader selections are validated instead of being changed.
func Available_fenrir_keys(readerNames, scriptNames []string) ([]string, error) {
reader, err := Fenrir_codes(readerNames)
if err != nil {
return nil, err
}
scripts, err := Modifier_codes(scriptNames)
if err != nil {
return nil, err
}
var names []string
for _, key := range []uint16{KeyKP0, KeyInsert, KeyCapsLock, KeyMeta, KeyRightMeta} {
if reader[key] && !scripts[key] {
names = append(names, Key_name(key))
}
}
if len(names) == 0 {
return nil, fmt.Errorf("select at least one Fenrir key that is not a script key")
}
return names, nil
}
func (r *Router) Configure_modifiers(fenrirKeys, scriptKeys []string) error {
if fenrirKeys == nil {
var err error
fenrirKeys, err = Available_fenrir_keys(r.Fenrir_keys(), scriptKeys)
if err != nil {
return err
}
}
if err := Validate_modifier_keys(fenrirKeys, scriptKeys); err != nil {
return err
}
candidate := *r
candidate.scriptKeys = nil
if err := candidate.Set_fenrir_keys(fenrirKeys); err != nil {
return err
}
if err := candidate.Configure_scripts(scriptKeys, nil); err != nil {
return err
}
candidate.scriptBindings = r.scriptBindings
*r = candidate
return nil
}