156 lines
3.8 KiB
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
|
|
}
|