Files

115 lines
3.5 KiB
Go

// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
package preferences
import (
"fmt"
"path/filepath"
"slices"
"git.stormux.org/storm/fenrir/internal/config"
"git.stormux.org/storm/fenrir/internal/input"
"git.stormux.org/storm/fenrir/internal/interaction"
)
type modifierOption struct{ name, Label string }
var modifierOptions = []modifierOption{
{name: "KEY_KP0", Label: "Keypad Insert"},
{name: "KEY_INSERT", Label: "Insert"},
{name: "KEY_CAPSLOCK", Label: "Caps Lock"},
{name: "KEY_META", Label: "Super"},
}
func reader_names(settings config.Settings) []string {
if settings.Keyboard.FenrirKeys != nil {
return settings.Keyboard.FenrirKeys
}
// Running applications supply the resolved layout's keys at startup.
// Standalone forms use the built-in layout defaults.
var names []string
switch filepath.Base(settings.Keyboard.Layout) {
case "laptop", "laptop.toml":
names = []string{"KEY_KP0", "KEY_INSERT", "KEY_CAPSLOCK"}
default:
names = []string{"KEY_KP0", "KEY_INSERT", "KEY_META"}
}
available, err := input.Available_fenrir_keys(names, settings.General.ScriptKeys)
if err != nil {
return []string{}
}
return available
}
func modifier_checked(names []string, name string) bool {
keys, _ := input.Modifier_codes(names)
option, _ := input.Modifier_codes([]string{name})
for key := range option {
if keys[key] {
return true
}
}
return false
}
func modifier_controls(settings config.Settings) []interaction.Control {
var controls []interaction.Control
for _, role := range []struct {
id, Label string
names []string
}{
{id: "fenrir_key.", Label: "Fenrir keys", names: reader_names(settings)},
{id: "script_key.", Label: "Script keys", names: settings.General.ScriptKeys},
} {
options := slices.Clone(modifierOptions)
if role.id == "script_key." {
options = append(options, modifierOption{name: "KEY_COMPOSE", Label: "Compose"})
}
for _, option := range options {
controls = append(controls, interaction.Control{ID: role.id + option.name, Label: option.Label, Group: role.Label, Kind: interaction.CheckBox, Checked: modifier_checked(role.names, option.name)})
}
}
return controls
}
func selected_modifiers(values map[string]interaction.Control, prefix string, names []string, options []modifierOption) ([]string, bool, error) {
selected := slices.Clone(names)
changed := false
for _, option := range options {
control, ok := values["keyboard."+prefix+option.name]
if !ok {
return nil, false, fmt.Errorf("missing modifier checkbox %s", option.name)
}
if control.Checked == modifier_checked(names, option.name) {
continue
}
changed = true
if control.Checked {
selected = append(selected, option.name)
continue
}
selected = slices.DeleteFunc(selected, func(name string) bool { return modifier_checked([]string{name}, option.name) })
}
return selected, changed, nil
}
func modifier_settings(values map[string]interaction.Control, base *config.Settings) error {
reader, changed, err := selected_modifiers(values, "fenrir_key.", reader_names(*base), modifierOptions)
if err != nil {
return err
}
scripts, _, err := selected_modifiers(values, "script_key.", base.General.ScriptKeys, append(slices.Clone(modifierOptions), modifierOption{name: "KEY_COMPOSE", Label: "Compose"}))
if err != nil {
return err
}
if err := input.Validate_modifier_keys(reader, scripts); err != nil {
return err
}
if changed {
base.Keyboard.FenrirKeys = reader
}
base.General.ScriptKeys = scripts
return nil
}