mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-01 19:18:28 -04:00
@@ -55,6 +55,7 @@ func (n *NiriProvider) GetCheatSheet() (*keybinds.CheatSheet, error) {
|
||||
sheet := &keybinds.CheatSheet{
|
||||
Title: "Niri Keybinds",
|
||||
Provider: n.Name(),
|
||||
ModKey: result.ModKey,
|
||||
Binds: categorizedBinds,
|
||||
DMSBindsIncluded: result.DMSBindsIncluded,
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ type NiriSection struct {
|
||||
|
||||
type NiriParser struct {
|
||||
configDir string
|
||||
modKey string
|
||||
processedFiles map[string]bool
|
||||
bindMap map[string]*NiriKeyBinding
|
||||
bindOrder []string
|
||||
@@ -237,6 +238,7 @@ func isBraceAdjacentSpace(b byte) bool {
|
||||
func NewNiriParser(configDir string) *NiriParser {
|
||||
return &NiriParser{
|
||||
configDir: configDir,
|
||||
modKey: "Super",
|
||||
processedFiles: make(map[string]bool),
|
||||
bindMap: make(map[string]*NiriKeyBinding),
|
||||
bindOrder: []string{},
|
||||
@@ -377,6 +379,8 @@ func (p *NiriParser) processNodes(nodes []*document.Node, section *NiriSection,
|
||||
switch name {
|
||||
case "include":
|
||||
p.handleInclude(node, section, baseDir)
|
||||
case "input":
|
||||
p.handleInput(node)
|
||||
case "binds":
|
||||
p.extractBinds(node, section, "")
|
||||
case "recent-windows":
|
||||
@@ -385,6 +389,19 @@ func (p *NiriParser) processNodes(nodes []*document.Node, section *NiriSection,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *NiriParser) handleInput(node *document.Node) {
|
||||
for _, child := range node.Children {
|
||||
if child.Name.String() != "mod-key" || len(child.Arguments) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
modKey := strings.Trim(strings.TrimSpace(child.Arguments[0].String()), "\"")
|
||||
if modKey != "" {
|
||||
p.modKey = modKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *NiriParser) handleInclude(node *document.Node, section *NiriSection, baseDir string) {
|
||||
if len(node.Arguments) == 0 {
|
||||
return
|
||||
@@ -534,6 +551,7 @@ func (p *NiriParser) parseKeyCombo(combo string) ([]string, string) {
|
||||
|
||||
type NiriParseResult struct {
|
||||
Section *NiriSection
|
||||
ModKey string
|
||||
DMSBindsIncluded bool
|
||||
DMSStatus *DMSBindsStatusInfo
|
||||
ConflictingConfigs map[string]*NiriKeyBinding
|
||||
@@ -586,6 +604,7 @@ func ParseNiriKeys(configDir string) (*NiriParseResult, error) {
|
||||
}
|
||||
return &NiriParseResult{
|
||||
Section: section,
|
||||
ModKey: parser.modKey,
|
||||
DMSBindsIncluded: parser.HasDMSBindsIncluded(),
|
||||
DMSStatus: parser.buildDMSStatus(),
|
||||
ConflictingConfigs: parser.conflictingConfigs,
|
||||
|
||||
@@ -7,6 +7,28 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNiriParseModKey(t *testing.T) {
|
||||
config := `input {
|
||||
mod-key "Alt"
|
||||
}
|
||||
binds {
|
||||
Mod+T { spawn "kitty"; }
|
||||
}
|
||||
`
|
||||
tmpDir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(tmpDir, "config.kdl"), []byte(config), 0o644); err != nil {
|
||||
t.Fatalf("Failed to write test config: %v", err)
|
||||
}
|
||||
|
||||
result, err := ParseNiriKeys(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseNiriKeys failed: %v", err)
|
||||
}
|
||||
if result.ModKey != "Alt" {
|
||||
t.Errorf("ModKey = %q, want %q", result.ModKey, "Alt")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNiriParse_NoSpaceBeforeBrace(t *testing.T) {
|
||||
config := `recent-windows {
|
||||
binds {
|
||||
|
||||
@@ -17,7 +17,10 @@ func TestNiriProviderGetCheatSheet(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
configFile := filepath.Join(tmpDir, "config.kdl")
|
||||
|
||||
content := `binds {
|
||||
content := `input {
|
||||
mod-key "Alt"
|
||||
}
|
||||
binds {
|
||||
Mod+Q { close-window; }
|
||||
Mod+F { fullscreen-window; }
|
||||
Mod+T hotkey-overlay-title="Open Terminal" { spawn "kitty"; }
|
||||
@@ -45,6 +48,10 @@ func TestNiriProviderGetCheatSheet(t *testing.T) {
|
||||
t.Errorf("Provider = %q, want %q", cheatSheet.Provider, "niri")
|
||||
}
|
||||
|
||||
if cheatSheet.ModKey != "Alt" {
|
||||
t.Errorf("ModKey = %q, want %q", cheatSheet.ModKey, "Alt")
|
||||
}
|
||||
|
||||
windowBinds := cheatSheet.Binds["Window"]
|
||||
if len(windowBinds) < 2 {
|
||||
t.Errorf("Expected at least 2 Window binds, got %d", len(windowBinds))
|
||||
|
||||
@@ -32,6 +32,7 @@ type DMSBindsStatus struct {
|
||||
type CheatSheet struct {
|
||||
Title string `json:"title"`
|
||||
Provider string `json:"provider"`
|
||||
ModKey string `json:"modKey,omitempty"`
|
||||
Binds map[string][]Keybind `json:"binds"`
|
||||
DMSBindsIncluded bool `json:"dmsBindsIncluded"`
|
||||
DMSStatus *DMSBindsStatus `json:"dmsStatus,omitempty"`
|
||||
|
||||
@@ -192,23 +192,42 @@ function formatToken(mods, key) {
|
||||
return (mods.length ? mods.join("+") + "+" : "") + key;
|
||||
}
|
||||
|
||||
function normalizeKeyCombo(keyCombo) {
|
||||
if (!keyCombo)
|
||||
return "";
|
||||
return keyCombo.toLowerCase().replace(/\bmod\b/g, "super").replace(/\bsuper\b/g, "super");
|
||||
function canonicalModifier(modifier) {
|
||||
var normalized = (modifier || "").toLowerCase();
|
||||
if (normalized === "control")
|
||||
return "ctrl";
|
||||
if (normalized === "win")
|
||||
return "super";
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function getConflictingBinds(keyCombo, currentAction, allBinds) {
|
||||
function withSymbolicMod(mods, modKey) {
|
||||
var configuredMod = canonicalModifier(modKey);
|
||||
if (!configuredMod)
|
||||
return mods;
|
||||
return mods.map(function (modifier) {
|
||||
return canonicalModifier(modifier) === configuredMod ? "Mod" : modifier;
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeKeyCombo(keyCombo, modKey) {
|
||||
if (!keyCombo)
|
||||
return "";
|
||||
var configuredMod = canonicalModifier(modKey) || "super";
|
||||
return keyCombo.toLowerCase().replace(/\bmod\b/g, configuredMod).replace(/\bcontrol\b/g, "ctrl").replace(/\bwin\b/g, "super");
|
||||
}
|
||||
|
||||
function getConflictingBinds(keyCombo, currentAction, allBinds, modKey) {
|
||||
if (!keyCombo)
|
||||
return [];
|
||||
var conflicts = [];
|
||||
var normalizedKey = normalizeKeyCombo(keyCombo);
|
||||
var normalizedKey = normalizeKeyCombo(keyCombo, modKey);
|
||||
for (var i = 0; i < allBinds.length; i++) {
|
||||
var bind = allBinds[i];
|
||||
if (bind.action === currentAction)
|
||||
continue;
|
||||
for (var k = 0; k < bind.keys.length; k++) {
|
||||
if (normalizeKeyCombo(bind.keys[k].key) === normalizedKey) {
|
||||
if (normalizeKeyCombo(bind.keys[k].key, modKey) === normalizedKey) {
|
||||
conflicts.push({
|
||||
action: bind.action,
|
||||
desc: bind.desc || bind.action
|
||||
|
||||
@@ -42,6 +42,7 @@ Singleton {
|
||||
property bool saving: false
|
||||
property bool fixing: false
|
||||
property string lastError: ""
|
||||
property string modKey: "Super"
|
||||
property bool dmsBindsIncluded: true
|
||||
|
||||
property var dmsStatus: ({
|
||||
@@ -348,6 +349,7 @@ Singleton {
|
||||
|
||||
function _processData() {
|
||||
keybinds = _rawData || {};
|
||||
modKey = currentProvider === "niri" ? (_rawData?.modKey || "Super") : "Super";
|
||||
dmsBindsIncluded = _rawData?.dmsBindsIncluded ?? true;
|
||||
const status = _rawData?.dmsStatus;
|
||||
if (status) {
|
||||
|
||||
@@ -56,7 +56,7 @@ Item {
|
||||
readonly property bool hasConfigConflict: configConflict !== null
|
||||
readonly property string _originalKey: editingKeyIndex >= 0 && editingKeyIndex < keys.length ? keys[editingKeyIndex].key : ""
|
||||
readonly property string _selectedDesc: editingKeyIndex >= 0 && editingKeyIndex < keys.length ? (keys[editingKeyIndex].desc || bindData.desc || "") : (bindData.desc || "")
|
||||
readonly property var _conflicts: editKey ? KeyUtils.getConflictingBinds(editKey, bindData.action, KeybindsService.getFlatBinds()) : []
|
||||
readonly property var _conflicts: editKey ? KeyUtils.getConflictingBinds(editKey, bindData.action, KeybindsService.getFlatBinds(), KeybindsService.currentProvider === "niri" ? KeybindsService.modKey : "Super") : []
|
||||
readonly property bool hasConflict: _conflicts.length > 0
|
||||
|
||||
readonly property real _inputHeight: Math.round(Theme.fontSizeMedium * 3)
|
||||
@@ -725,6 +725,8 @@ Item {
|
||||
if (!mods.includes("Shift"))
|
||||
mods.push("Shift");
|
||||
}
|
||||
if (KeybindsService.currentProvider === "niri")
|
||||
mods = KeyUtils.withSymbolicMod(mods, KeybindsService.modKey);
|
||||
|
||||
const key = KeyUtils.xkbKeyFromQtKey(qtKey, !!(event.modifiers & Qt.KeypadModifier));
|
||||
if (!key) {
|
||||
@@ -756,7 +758,7 @@ Item {
|
||||
}
|
||||
wheel.accepted = true;
|
||||
|
||||
const mods = [];
|
||||
let mods = [];
|
||||
if (wheel.modifiers & Qt.ControlModifier)
|
||||
mods.push("Ctrl");
|
||||
if (wheel.modifiers & Qt.ShiftModifier)
|
||||
@@ -765,6 +767,8 @@ Item {
|
||||
mods.push("Alt");
|
||||
if (wheel.modifiers & Qt.MetaModifier)
|
||||
mods.push("Super");
|
||||
if (KeybindsService.currentProvider === "niri")
|
||||
mods = KeyUtils.withSymbolicMod(mods, KeybindsService.modKey);
|
||||
|
||||
let wheelKey = "";
|
||||
if (wheel.angleDelta.y > 0)
|
||||
|
||||
Reference in New Issue
Block a user