From 9921e1a09fdb5606a7906e8fbde2b728fb09b77a Mon Sep 17 00:00:00 2001 From: Ala Alkhafaji <3akevdev@gmail.com> Date: Mon, 10 Nov 2025 21:25:58 +0100 Subject: [PATCH] KeyboardLayout: update on keyboard layout change events (niri) --- Services/Compositor/NiriService.qml | 31 +++++++++++++++++++++ Services/Keyboard/KeyboardLayoutService.qml | 25 ++++------------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/Services/Compositor/NiriService.qml b/Services/Compositor/NiriService.qml index 7eb3a6e0..5d02080f 100644 --- a/Services/Compositor/NiriService.qml +++ b/Services/Compositor/NiriService.qml @@ -2,6 +2,7 @@ import QtQuick import Quickshell import Quickshell.Io import qs.Commons +import qs.Services.Keyboard Item { id: root @@ -16,6 +17,8 @@ Item { property bool overviewActive: false + property var keyboardLayouts: [] + // Signals that match the facade interface signal workspaceChanged signal activeWindowChanged @@ -46,6 +49,7 @@ Item { niriOutputsProcess.running = true } + // Niri outputs process for display scale detection Process { id: niriOutputsProcess @@ -191,6 +195,10 @@ Item { queryDisplayScales() } else if (event.ConfigLoaded) { queryDisplayScales() + } else if (event.KeyboardLayoutsChanged) { + handleKeyboardLayoutsChanged(event.KeyboardLayoutsChanged) + } else if (event.KeyboardLayoutSwitched) { + handleKeyboardLayoutSwitched(event.KeyboardLayoutSwitched) } } catch (e) { Logger.e("NiriService", "Error parsing event stream:", e, data) @@ -391,6 +399,27 @@ Item { } } + function handleKeyboardLayoutsChanged(eventData) { + try { + keyboardLayouts = eventData.keyboard_layouts.names + const layoutName = keyboardLayouts[eventData.keyboard_layouts.current_idx] + KeyboardLayoutService.setCurrentLayout(layoutName) + Logger.d("NiriService", "Keyboard layouts changed:", keyboardLayouts.toString()) + } catch (e) { + Logger.e("NiriService", "Error handling keyboardLayoutsChanged:", e) + } + } + + function handleKeyboardLayoutSwitched(eventData) { + try { + const layoutName = keyboardLayouts[eventData.idx] + KeyboardLayoutService.setCurrentLayout(layoutName) + Logger.d("NiriService", "Keyboard layout switched:", layoutName) + } catch (e) { + Logger.e("NiriService", "Error handling KeyboardLayoutSwitched:", e) + } + } + // Public functions function switchToWorkspace(workspace) { try { @@ -423,4 +452,6 @@ Item { Logger.e("NiriService", "Failed to logout:", e) } } + + } diff --git a/Services/Keyboard/KeyboardLayoutService.qml b/Services/Keyboard/KeyboardLayoutService.qml index 5db74868..c993e688 100644 --- a/Services/Keyboard/KeyboardLayoutService.qml +++ b/Services/Keyboard/KeyboardLayoutService.qml @@ -25,24 +25,6 @@ Singleton { } } - // Process to get current keyboard layout using niri msg (Wayland native) - Process { - id: niriLayoutProcess - running: false - command: ["niri", "msg", "-j", "keyboard-layouts"] - stdout: StdioCollector { - onStreamFinished: { - try { - const data = JSON.parse(text) - const layoutName = data.names[data.current_idx] - root.currentLayout = extractLayoutCode(layoutName) - } catch (e) { - root.currentLayout = I18n.tr("system.unknown-layout") - } - } - } - } - // Process to get current keyboard layout using hyprctl (Hyprland) Process { id: hyprlandLayoutProcess @@ -170,6 +152,11 @@ Singleton { localectlProcess.running = true } + // Updates current layout from various format strings. Called by compositors + function setCurrentLayout(layoutString) { + root.currentLayout = extractLayoutCode(layoutString) + } + // Extract layout code from various format strings using Commons data function extractLayoutCode(layoutString) { if (!layoutString) @@ -244,7 +231,7 @@ Singleton { if (CompositorService.isHyprland) { hyprlandLayoutProcess.running = true } else if (CompositorService.isNiri) { - niriLayoutProcess.running = true + // do nothing, niri calls setCurrentLayout } else { // Try detection methods in order of preference if (Qt.platform.os === "linux") {