47 lines
1.5 KiB
Go
47 lines
1.5 KiB
Go
package input
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Tentacle bindings are runtime registrations, never persisted core overrides.
|
|
// The native input owner arbitrates them again whenever core settings change.
|
|
func ValidateTentacleBindings(bindings []BindingOverride) error {
|
|
if len(bindings) > 16*32*4 {
|
|
return fmt.Errorf("too many tentacle bindings")
|
|
}
|
|
for _, binding := range bindings {
|
|
if !strings.HasPrefix(string(binding.Command), "tentacle/") || len(binding.Command) > 400 ||
|
|
(binding.Layout != DesktopKeyboardLayout && binding.Layout != LaptopKeyboardLayout) ||
|
|
(binding.Scope != "global" && binding.Scope != "browse") || len(binding.Keys) != 1 {
|
|
return fmt.Errorf("invalid tentacle binding")
|
|
}
|
|
if _, err := ParseCommandChord(binding.Keys[0]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// MergeTentacleBindings preserves core bindings and registration order. A
|
|
// conflicting suggestion stays unbound. Callers validate both inputs first.
|
|
func MergeTentacleBindings(core, suggestions []BindingOverride) []BindingOverride {
|
|
result := CloneBindingOverrides(core)
|
|
for _, layout := range []KeyboardLayout{DesktopKeyboardLayout, LaptopKeyboardLayout} {
|
|
occupied, _ := ResolveCommandBindings(layout, true, core)
|
|
for _, suggestion := range suggestions {
|
|
if suggestion.Layout != layout {
|
|
continue
|
|
}
|
|
chord, _ := ParseCommandChord(suggestion.Keys[0])
|
|
if occupied[chord] != "" {
|
|
continue
|
|
}
|
|
occupied[chord] = suggestion.Command
|
|
result = append(result, CloneBindingOverrides([]BindingOverride{suggestion})[0])
|
|
}
|
|
}
|
|
return result
|
|
}
|