Add KeyboardLayoutService, add KeyboardLayout Widget, add KeyboardLayout to LockScreen

This commit is contained in:
Ly-sec 2025-08-23 13:02:37 +02:00
parent 2029b5e1eb
commit ca7e0cc105
4 changed files with 173 additions and 1 deletions

View file

@ -65,7 +65,7 @@ QtObject {
// This is where you should add your Modules/Bar/Widgets/
// so it gets registered in the BarTab
function discoverAvailableWidgets() {
const widgetFiles = ["ActiveWindow", "Battery", "Bluetooth", "Brightness", "Clock", "MediaMini", "NotificationHistory", "PowerProfile", "ScreenRecorderIndicator", "SidePanelToggle", "SystemMonitor", "Tray", "Volume", "WiFi", "Workspace"]
const widgetFiles = ["ActiveWindow", "Battery", "Bluetooth", "Brightness", "Clock", "KeyboardLayout", "MediaMini", "NotificationHistory", "PowerProfile", "ScreenRecorderIndicator", "SidePanelToggle", "SystemMonitor", "Tray", "Volume", "WiFi", "Workspace"]
const availableWidgets = []

View file

@ -0,0 +1,34 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import Quickshell.Io
import qs.Commons
import qs.Services
import qs.Widgets
Item {
id: root
width: pill.width
height: pill.height
// Use the shared service for keyboard layout
property string currentLayout: KeyboardLayoutService.currentLayout
NPill {
id: pill
icon: "keyboard_alt"
iconCircleColor: Color.mPrimary
collapsedIconColor: Color.mOnSurface
autoHide: false // Important to be false so we can hover as long as we want
text: currentLayout
tooltipText: "Keyboard Layout: " + currentLayout
onClicked: {
// You could open keyboard settings here if needed
// For now, just show the current layout
}
}
}

View file

@ -163,6 +163,13 @@ Loader {
}
}
// Keyboard layout indicator component
Item {
id: keyboardLayout
property string currentLayout: (typeof KeyboardLayoutService !== 'undefined' && KeyboardLayoutService.currentLayout) ? KeyboardLayoutService.currentLayout : "Unknown"
}
// Wallpaper image
Image {
id: lockBgImage
@ -580,6 +587,25 @@ Loader {
font.weight: Style.fontWeightBold
}
}
// Keyboard layout indicator
Row {
spacing: Style.marginS * scaling
NText {
text: keyboardLayout.currentLayout
color: Color.mOnSurface
font.family: Settings.data.ui.fontFixed
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
}
NIcon {
text: "keyboard_alt"
font.pointSize: Style.fontSizeM * scaling
color: Color.mOnSurface
}
}
}
}

View file

@ -0,0 +1,112 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import qs.Commons
import qs.Services
Singleton {
id: root
property string currentLayout: "Unknown"
property int updateInterval: 1000 // Update every second
// Timer to periodically update the layout
Timer {
id: updateTimer
interval: updateInterval
running: true
repeat: true
onTriggered: {
updateLayout()
}
}
// 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 = mapLayoutNameToCode(layoutName)
} catch (e) {
root.currentLayout = "Unknown"
}
}
}
}
// 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 = mapLayoutNameToCode(mainKeyboard.active_keymap)
} else {
root.currentLayout = "Unknown"
}
} catch (e) {
root.currentLayout = "Unknown"
}
}
}
}
// Layout name to ISO code mapping
property var layoutMap: {
"German": "de",
"English (US)": "us",
"English (UK)": "gb",
"French": "fr",
"Spanish": "es",
"Italian": "it",
"Portuguese (Brazil)": "br",
"Portuguese": "pt",
"Russian": "ru",
"Polish": "pl",
"Swedish": "se",
"Norwegian": "no",
"Danish": "dk",
"Finnish": "fi",
"Hungarian": "hu",
"Turkish": "tr",
"Czech": "cz",
"Slovak": "sk",
"Japanese": "jp",
"Korean": "kr",
"Chinese": "cn"
}
// Map layout names to ISO codes
function mapLayoutNameToCode(layoutName) {
return layoutMap[layoutName] || layoutName // fallback to raw name if not found
}
Component.onCompleted: {
Logger.log("KeyboardLayout", "Service started")
updateLayout()
}
function updateLayout() {
if (CompositorService.isHyprland) {
hyprlandLayoutProcess.running = true
} else if (CompositorService.isNiri) {
niriLayoutProcess.running = true
} else {
currentLayout = "Unknown"
}
}
}