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