diff --git a/Services/Compositor/HyprlandService.qml b/Services/Compositor/HyprlandService.qml index 46838bbf..f379c5a2 100644 --- a/Services/Compositor/HyprlandService.qml +++ b/Services/Compositor/HyprlandService.qml @@ -3,6 +3,7 @@ import Quickshell import Quickshell.Hyprland import Quickshell.Io import qs.Commons +import qs.Services.Keyboard Item { id: root @@ -43,6 +44,7 @@ Item { safeUpdateWorkspaces() safeUpdateWindows() queryDisplayScales() + queryKeyboardLayout() }) initialized = true Logger.i("HyprlandService", "Service started") @@ -56,7 +58,6 @@ Item { hyprlandMonitorsProcess.running = true } - // Hyprland monitors process for display scale detection // Hyprland monitors process for display scale detection Process { id: hyprlandMonitorsProcess @@ -112,6 +113,50 @@ Item { } } } + + function queryKeyboardLayout() { + hyprlandDevicesProcess.running = true + } + // Hyprland devices process for keyboard layout detection + Process { + id: hyprlandDevicesProcess + running: false + command: ["hyprctl", "devices", "-j"] + + property string accumulatedOutput: "" + + stdout: SplitParser { + onRead: function (line) { + // Accumulate lines instead of parsing each one + hyprlandDevicesProcess.accumulatedOutput += line + } + } + + onExited: function (exitCode) { + if (exitCode !== 0 || !accumulatedOutput) { + Logger.e("HyprlandService", "Failed to query devices, exit code:", exitCode) + accumulatedOutput = "" + return + } + + try { + const devicesData = JSON.parse(accumulatedOutput) + for (const keyboard of devicesData.keyboards) { + if (keyboard.main) { + const layoutName = keyboard.active_keymap + KeyboardLayoutService.setCurrentLayout(layoutName) + Logger.d("HyprlandService", "Keyboard layout switched:", layoutName) + } + } + } catch (e) { + Logger.e("HyprlandService", "Failed to parse devices:", e) + } finally { + // Clear accumulated output for next query + accumulatedOutput = "" + } + } + } + // Safe update wrapper function safeUpdate() { safeUpdateWindows() @@ -330,6 +375,27 @@ Item { return defaultValue } + function handleActiveLayoutEvent(ev) { + try { + let beforeParenthesis + const parenthesisPos = ev.lastIndexOf('(') + + if (parenthesisPos === -1) { + beforeParenthesis = ev + } else { + beforeParenthesis = ev.substring(0, parenthesisPos) + } + + const layoutNameStart = beforeParenthesis.lastIndexOf(',') + 1 + const layoutName = ev.substring(layoutNameStart) + + KeyboardLayoutService.setCurrentLayout(layoutName) + Logger.d("HyprlandService", "Keyboard layout switched:", layoutName) + } catch (e) { + Logger.e("HyprlandService", "Error handling activelayout:", e) + } + } + // Connections to Hyprland Connections { target: Hyprland.workspaces @@ -358,9 +424,14 @@ Item { updateTimer.restart() const monitorsEvents = ["configreloaded", "monitoradded", "monitorremoved", "monitoraddedv2", "monitorremovedv2"] + if (monitorsEvents.includes(event.name)) { Qt.callLater(queryDisplayScales) } + + if (event.name == "activelayout") { + handleActiveLayoutEvent(event.data) + } } } diff --git a/Services/Compositor/NiriService.qml b/Services/Compositor/NiriService.qml index 5d02080f..c7f0db11 100644 --- a/Services/Compositor/NiriService.qml +++ b/Services/Compositor/NiriService.qml @@ -49,7 +49,6 @@ Item { niriOutputsProcess.running = true } - // Niri outputs process for display scale detection Process { id: niriOutputsProcess @@ -452,6 +451,4 @@ Item { Logger.e("NiriService", "Failed to logout:", e) } } - - } diff --git a/Services/Keyboard/KeyboardLayoutService.qml b/Services/Keyboard/KeyboardLayoutService.qml index c993e688..65423956 100644 --- a/Services/Keyboard/KeyboardLayoutService.qml +++ b/Services/Keyboard/KeyboardLayoutService.qml @@ -25,29 +25,6 @@ Singleton { } } - // Process to get current keyboard layout using hyprctl (Hyprland) - Process { - id: hyprlandLayoutProcess - running: false - command: ["hyprctl", "-j", "devices"] - stdout: StdioCollector { - onStreamFinished: { - try { - const data = JSON.parse(text) - // Find the main keyboard and get its active keymap - const mainKeyboard = data.keyboards.find(kb => kb.main === true) - if (mainKeyboard && mainKeyboard.active_keymap) { - root.currentLayout = extractLayoutCode(mainKeyboard.active_keymap) - } else { - root.currentLayout = I18n.tr("system.unknown-layout") - } - } catch (e) { - root.currentLayout = I18n.tr("system.unknown-layout") - } - } - } - } - // Process for X11 systems using setxkbmap Process { id: x11LayoutProcess @@ -229,9 +206,9 @@ Singleton { function updateLayout() { // Try compositor-specific methods first if (CompositorService.isHyprland) { - hyprlandLayoutProcess.running = true + } else if (CompositorService.isNiri) { - // do nothing, niri calls setCurrentLayout + } else { // Try detection methods in order of preference if (Qt.platform.os === "linux") {