Skip to content

Add omarchy keyboard layout bar widget - #6358

Open
heyssh wants to merge 21 commits into
basecamp:quattrofrom
heyssh:add/omarchy-keyboard-layout
Open

Add omarchy keyboard layout bar widget#6358
heyssh wants to merge 21 commits into
basecamp:quattrofrom
heyssh:add/omarchy-keyboard-layout

Conversation

@heyssh

@heyssh heyssh commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Omarchy Keyboard Layout

A keyboard layout bar widget for Omarchy. Shows your active
keyboard language in the bar, and gives you a clean panel to add,
remove, and switch between languages — plus configure the shortcut
used to cycle between them, all without leaving the keyboard.

screenshot-2026-07-29_19-14-31

Features

  • Live language indicator in the bar, showing the active layout
    at a glance (e.g. EN, FA, DE) — even with only one language
    configured, so you always know what layout is active without
    opening the panel.
  • One-click switching — open the panel and pick any configured
    language, or right-click the bar icon to instantly cycle to the
    next one.
  • Add languages from a clean, searchable list of real system
    keyboard layouts — type to filter by name or code.
  • Remove languages you no longer need, with the system's primary
    layout always kept safe from accidental removal.
  • Switch-shortcut picker — choose how you cycle layouts system-wide:
    • Alt+Shift
    • Ctrl+Shift
    • Right Alt
  • Stays in sync with Hyprland — if you switch layouts using the
    keyboard shortcut directly, the bar updates automatically.
  • Full keyboard navigation inside the panel — no mouse required.
  • Setup > Show Keyboard Layout — a menu toggle for anyone who
    only ever uses one language and doesn't want the icon sitting in
    the bar. Toggle it off any time, and back on the same way whenever
    you want it back. An OSD notification confirms the new state.

How it works

The widget is made up of three parts that work together:

Part Role
bin/omarchy-keyboard-layout CLI that reads/writes the layout state and talks to Hyprland
input/input.lua Hyprland input config — applies the active layout(s) and switch shortcut
keyboard/ (Panel.qml, Model.js, manifest.json) The bar widget UI itself

Usage

Click the keyboard icon in the bar to open the panel:

  • Languages — tap a language to switch to it, or hit the + to
    add a new one from the full list.
  • Switch shortcut — tap any of the four presets to change how the
    keyboard shortcut cycles your layouts.
  • Right-click the bar icon to instantly cycle to your next
    configured language.
  • Setup > Keyboard Layout — toggle the bar icon on or off.
    Handy if you only work in one language and prefer a cleaner bar;
    turning it back on brings the icon right back.
  • Add a keybinding (SUPER+CTRL+K) to open the panel via a new open
    subcommand, which checks show_bar_icon itself so the panel only
    opens when its bar icon is enabled/visible.

Test

screenrecording-2026-07-26_15-41-21.mp4

Copilot AI review requested due to automatic review settings July 23, 2026 22:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new “Keyboard Layout” bar widget/panel plugin for Omarchy, backed by a new CLI command and Hyprland input configuration that persists selected layouts and the layout-switch shortcut in a per-user state file.

Changes:

  • Adds a new omarchy.keyboard bar widget/panel UI with language switching, add/remove, and switcher preset selection.
  • Adds bin/omarchy-keyboard-layout to read/write keyboard layout state, query available XKB layouts, and drive Hyprland layout switching.
  • Updates Hyprland input configuration to read the keyboard layout state file and apply the selected switcher preset.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
shell/plugins/panels/keyboard/Panel.qml New keyboard layout widget/panel UI and Hyprland event syncing.
shell/plugins/panels/keyboard/Model.js Parsing/filtering helpers and switcher preset definitions for the panel.
shell/plugins/panels/keyboard/manifest.json Declares the new omarchy.keyboard bar-widget plugin.
config/hypr/input.lua Reads keyboard state to set kb_layout and kb_options switcher preset.
bin/omarchy-keyboard-layout CLI for status/available/add/remove/set/next/switcher and state persistence.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread shell/plugins/panels/keyboard/Panel.qml Outdated
Comment on lines +185 to +192
PanelKeyCatcher {
id: keyCatcher
anchors.fill: parent
onCloseRequested: {
if (root.viewMode === "add") root.closeAddView()
else root.close()
}

Comment thread shell/plugins/panels/keyboard/Model.js Outdated
Comment on lines +1 to +2
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in default/hypr/input.lua.
Comment thread shell/plugins/panels/keyboard/Model.js Outdated

if (needle === "") return list

return list.sort(function(a, b) { return matchRank(a, needle) - matchRank(b, needle) })
@heyssh heyssh changed the title Add omarchy keyboard layout bar plugin Add omarchy keyboard layout bar widget Jul 24, 2026
@husamemadH

Copy link
Copy Markdown
Contributor

i like this addition i spent alot of time trying to make something like this today

@heyssh

heyssh commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

i like this addition i spent alot of time trying to make something like this today

Yeah, I think this is something that's genuinely needed. For anyone who regularly works with two keyboard layouts, having a clear indicator is almost essential. It makes switching between languages much more seamless and helps avoid a lot of unnecessary typing mistakes.

@pomartel

Copy link
Copy Markdown
Contributor

Maybe this could be released as a plugin instead? It's now easy to put it in its own repo and people who use multiple keyboard layouts can install it with the omarchy plugin add command.

@heyssh

heyssh commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Maybe this could be released as a plugin instead? It's now easy to put it in its own repo and people who use multiple keyboard layouts can install it with the omarchy plugin add command.

Appreciate the idea! My concern is that as a standalone plugin, most people who'd actually want this simply won't come across it. I think it fits better in core, since it's something a lot of users would want available by default.

On a related note, I also built a calendar for Omarchy — that one's available as a plugin.

Copilot AI review requested due to automatic review settings July 25, 2026 10:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (4)

shell/plugins/panels/keyboard/Panel.qml:204

  • PanelKeyCatcher only handles close; none of the navigation/activation signals are wired (onMoveRequested/onActivateRequested/onTabRequested). As a result, arrow keys / hjkl / Enter/Space won’t drive the cursor model (focusSection/selectedIndex/cursorActive), which breaks the advertised full keyboard navigation.
    PanelKeyCatcher {
      id: keyCatcher
      anchors.fill: parent
      onCloseRequested: {
        if (root.viewMode === "add") root.closeAddView()

shell/plugins/panels/keyboard/Panel.qml:151

  • The status poll timer runs continuously even when the bar icon is hidden (barIconVisible=false), so the widget will keep spawning omarchy-keyboard-layout status in the background unnecessarily.
  Timer {
    interval: 3000
    running: true
    repeat: true
    onTriggered: root.refresh()

shell/plugins/panels/keyboard/Model.js:2

  • Model.js says the switcher presets must be kept in sync with SWITCHER_OPTIONS in default/hypr/input.lua, but that file doesn’t define SWITCHER_OPTIONS (the mapping is currently in config/hypr/input.lua). This comment will send future edits to the wrong file.
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in default/hypr/input.lua.

config/hypr/input.lua:79

  • config/hypr/input.lua is meant for personal overrides loaded after defaults, but this change re-specifies the full input + misc config (and hard-codes kb_variant to ""), which will override Omarchy defaults wholesale and block future default improvements from applying. If the goal is to let the keyboard panel control layouts/switcher, only override kb_layout/kb_options here and leave the rest to default/hypr/input.lua (and/or user overrides).
  input = {
    kb_layout = kb_layout,
    kb_variant = "",
    kb_model = "",
    kb_options = kb_options,

Comment thread shell/plugins/panels/keyboard/Panel.qml Outdated
Comment on lines +132 to +137
// Hyprland switches the layout itself for the native Alt+Shift/Ctrl+Shift/
// etc. shortcut (see default/input.lua's kb_options grp:*_toggle) -- that
// path never goes through our `omarchy-keyboard-layout` CLI, so it doesn't
// update `root.status` on its own. Listen for Hyprland's own layout-change
// event and refresh from it so the bar icon stays in sync even when the
// switch happened outside the panel. A slow poll is kept as a fallback in
Comment thread config/hypr/input.lua Outdated
Comment on lines +3 to +7
"id": "omarchy.keyboard",
"name": "Keyboard Layout",
"version": "1.0.0",
"author": "Omarchy",
"description": "Active keyboard language with add/remove and switch-shortcut picker",
"setup.monitors": {"icon":"󰍹","label":"Monitors","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/monitors.lua\""},
"setup.keybindings": {"icon":"","label":"Keybindings","when":"[[ -f ~/.config/hypr/bindings.lua ]]","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/bindings.lua\""},
"setup.input": {"icon":"","label":"Input","when":"[[ -f ~/.config/hypr/input.lua ]]","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/input.lua\""},
"setup.keyboard-layout-icon": {"icon":"󰌌","label":"Keyboard Layout","action":"omarchy-keyboard-layout bar-icon toggle"},
Copilot AI review requested due to automatic review settings July 25, 2026 13:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (1)

shell/plugins/panels/keyboard/Model.js:2

  • This header comment points at default/hypr/input.lua, but the switcher preset mapping lives in config/hypr/input.lua (SWITCHER_OPTIONS). As-is, the reference is misleading for future edits.
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in default/hypr/input.lua.

Comment thread default/omarchy/omarchy-menu.jsonc Outdated
Comment thread shell/plugins/panels/keyboard/Panel.qml Outdated

// Raw status from `omarchy-keyboard-layout status`:
// { layouts: [{code, label}], switcher, active, show_bar_icon }
property var status: ({ layouts: [], switcher: "alt_shift", active: "", show_bar_icon: true })
Comment thread shell/plugins/panels/keyboard/Panel.qml Outdated
Comment thread config/hypr/input.lua Outdated
hl.config({
input = {
kb_layout = kb_layout,
kb_variant = "",
Comment thread config/hypr/input.lua Outdated
-- dot while waiting for the next key. Bind Compose to the Menu key
-- instead: it's unused by every switcher preset above, so Caps Lock keeps
-- working normally and Compose sequences (e.g. Menu, ', e -> é) still work.
local kb_options = "compose:menu," .. grp_option
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 25, 2026 13:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

shell/plugins/panels/keyboard/Panel.qml:120

  • Comment text is split mid-sentence ("this is a" on its own line), which reads like an accidental line break.
  // Manual on/off switch for the bar icon, controlled from omarchy-menu
  // (Trigger > Toggle > Show Keyboard Layout) via `omarchy-keyboard-layout
  // bar-icon toggle`. Independent of the language-code icon above -- this
  // is a
  // deliberate user choice, not an automatic language-count heuristic.

shell/plugins/panels/keyboard/Panel.qml:138

  • The comment references default/input.lua, but that file doesn't exist in the repo; the kb_options live under default/hypr/input.lua / config/hypr/input.lua. This makes the reference hard to follow.
  // Hyprland switches the layout itself for the native Alt+Shift/Ctrl+Shift/
  // etc. shortcut (see default/input.lua's kb_options grp:*_toggle) -- that
  // path never goes through our `omarchy-keyboard-layout` CLI, so it doesn't
  // update `root.status` on its own. Listen for Hyprland's own layout-change
  // event and refresh from it so the bar icon stays in sync even when the
  // switch happened outside the panel. A slow poll is kept as a fallback in
  // case an event is ever missed.

Comment thread default/omarchy/omarchy-menu.jsonc Outdated
"setup.input": {"icon":"","label":"Input","when":"[[ -f ~/.config/hypr/input.lua ]]","action":"omarchy-launch-config-editor \"$HOME/.config/hypr/input.lua\""},
"setup.direct-boot": {"icon":"","label":"Direct Boot","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-direct-boot"},
"setup.keyboard-layout-icon": {"icon":"󰌌","label":"Keyboard Layout","action":"omarchy-keyboard-layout bar-icon toggle"},
"setup.direct-boot": {"icon":"","label":"Direct Boot","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-direct-boot"}
Comment on lines +147 to +152
Timer {
interval: 3000
running: true
repeat: true
onTriggered: root.refresh()
}
Copilot AI review requested due to automatic review settings July 25, 2026 14:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (4)

default/omarchy/omarchy-menu.jsonc:126

  • Missing commas after the new Setup menu entries makes this JSONC invalid (the following keys won't parse correctly).
  "setup.keyboard-layout-icon": {"icon":"󰌌","label":"Keyboard Layout","action":"omarchy-keyboard-layout bar-icon toggle"},
  "setup.direct-boot": {"icon":"","label":"Direct Boot","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-direct-boot"}

shell/plugins/panels/keyboard/Panel.qml:145

  • The layout-change event handler (and the fallback polling Timer below) still refreshes every time even when the bar icon is disabled/hidden. That keeps spawning omarchy-keyboard-layout status in the background after the user explicitly hid the widget.
  Connections {
    target: Hyprland
    function onRawEvent(event) {
      if (!event || !event.name) return
      if (String(event.name).indexOf("activelayout") !== -1) root.refresh()
    }
  }

shell/plugins/panels/keyboard/Model.js:115

  • The sort comparator only compares match rank. When ranks tie, ordering becomes engine-dependent (JS sort stability isn’t guaranteed), which can cause the filtered list to reorder unexpectedly between refreshes.
  return list.sort(function(a, b) { return matchRank(a, needle) - matchRank(b, needle) })

shell/plugins/panels/keyboard/Panel.qml:134

  • Comment references default/input.lua, but the referenced Hyprland defaults live under default/hypr/input.lua in this repo. The incorrect path makes it harder to trace the behavior.
  // Hyprland switches the layout itself for the native Alt+Shift/Ctrl+Shift/
  // etc. shortcut (see default/input.lua's kb_options grp:*_toggle) -- that
  // path never goes through our `omarchy-keyboard-layout` CLI, so it doesn't

Comment thread config/hypr/input.lua Outdated
Comment on lines +24 to +29
-- The keyboard panel (bin/omarchy-keyboard-layout) owns this file: it's the
-- list of layouts the user picked via "Add language" plus their chosen
-- switch shortcut. jq is already a hard dependency of the Omarchy CLI
-- scripts, so shelling out to it here is simpler and less error-prone than
-- hand-rolling JSON parsing in Lua.
local STATE_FILE = os.getenv("HOME") .. "/.local/state/omarchy/settings/keyboard.json"
Copilot AI review requested due to automatic review settings July 25, 2026 14:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

default/omarchy/omarchy-menu.jsonc:127

  • Missing trailing comma after the "setup.direct-boot" menu entry breaks the surrounding JSONC object (the next key starts immediately on the next line).
  "setup.keyboard-layout-icon": {"icon":"󰌌","label":"Keyboard Layout","action":"omarchy-keyboard-layout bar-icon toggle"},
  "setup.direct-boot": {"icon":"","label":"Direct Boot","action":"omarchy-launch-floating-terminal-with-presentation omarchy-setup-direct-boot"}
  "setup.default": {"icon":"","label":"Defaults","aliases":["default","defaults"]},

shell/plugins/panels/keyboard/Panel.qml:120

  • This comment is broken across lines ("this is a" on its own) and references a menu path that doesn’t match the current omarchy-menu entry, making it confusing to maintain.
  // Manual on/off switch for the bar icon, controlled from omarchy-menu
  // (Trigger > Toggle > Show Keyboard Layout) via `omarchy-keyboard-layout
  // bar-icon toggle`. Independent of the language-code icon above -- this
  // is a
  // deliberate user choice, not an automatic language-count heuristic.

shell/plugins/panels/keyboard/Panel.qml:130

  • The widget refreshes its status on startup and on open even when the user has hidden the bar icon (barIconVisible=false). That still spawns subprocesses and polling work for an intentionally-disabled widget.
  onOpenedChanged: if (opened) refresh()
  Component.onCompleted: refresh()

shell/plugins/panels/keyboard/Panel.qml:151

  • The fallback polling timer runs unconditionally every 3s, even when the bar icon is hidden. This keeps invoking the CLI in the background for a widget the user explicitly disabled.
  Timer {
    interval: 3000
    running: true
    repeat: true
    onTriggered: root.refresh()

@dpan

dpan commented Jul 27, 2026

Copy link
Copy Markdown

I haven't tried this first hand so apologies if I'm getting it wrong, but looking at screenshots, it feels odd. The bar should be really simple, just switching the language (maybe with an OSD showing the selected language when hitting the binding). Adding languages, selecting the keyboard bindings belong in the settings, since they don't change that often, they do not need to be so immediately accessible. Just my two cents.

@heyssh

heyssh commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

I haven't tried this first hand so apologies if I'm getting it wrong, but looking at screenshots, it feels odd. The bar should be really simple, just switching the language (maybe with an OSD showing the selected language when hitting the binding). Adding languages, selecting the keyboard bindings belong in the settings, since they don't change that often, they do not need to be so immediately accessible. Just my two cents.

Thanks for the feedback! I'd actually lean toward keeping it as one panel. Switching is already the first thing you see (click any language or use arrow keys, no digging needed) — add/shortcut are secondary and further down, so they're not really competing for attention. Splitting them out would add a navigation step for something that's currently zero clicks away.

Also tried to account for the single-language case — if someone only uses one language and doesn't want the icon taking up space in the bar, there's a toggle for that under Setup > Keyboard Layout.

Happy to revisit if real usage shows otherwise.

Copilot AI review requested due to automatic review settings July 27, 2026 13:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (5)

shell/plugins/panels/keyboard/Panel.qml:18

  • The initial status default sets show_bar_icon: false, which hides the bar widget until the first omarchy-keyboard-layout status refresh completes. Since the CLI defaults show_bar_icon to true (and Model.parseStatus also falls back to true), this causes an avoidable “missing icon” flicker on startup.
  // Raw status from `omarchy-keyboard-layout status`:
  // { layouts: [{code, label}], switcher, active, show_bar_icon }
  property var status: ({ layouts: [], switcher: "alt_shift", active: "", show_bar_icon: false })
  property var available: []

shell/plugins/panels/keyboard/Panel.qml:220

  • This comment points to a menu location that doesn’t match the actual default menu entry added in this PR (setup.keyboard-layout-icon under the Setup section). Keeping this accurate matters for future maintainers trying to trace the toggle.
  // Manual on/off switch for the bar icon, controlled from omarchy-menu
  // (Trigger > Toggle > Show Keyboard Layout) via `omarchy-keyboard-layout
  // bar-icon toggle`. Independent of the language-code icon above -- this
  // is a deliberate user choice, not an automatic language-count heuristic.

shell/plugins/panels/keyboard/Panel.qml:745

  • The comment says there are four switch-shortcut presets, but the UI hard-codes a 3-column row (count: 3) and Model.js defines 3 presets. This should be corrected to avoid confusion when changing presets later.
  // One of the four switch-shortcut presets, same pill styling as the
  // network panel's DNS provider picker.

shell/plugins/panels/keyboard/Model.js:7

  • This header comment says there are four switch-shortcut presets, but SWITCHERS defines three entries. The comment should match the actual list (and the UI’s 3-column layout).
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in config/hypr/input.lua.
var SWITCHERS = [
  { id: "alt_shift", label: "Alt+Shift" },
  { id: "ctrl_shift", label: "Ctrl+Shift" },
  { id: "right_alt", label: "Right Alt" }
]

shell/plugins/panels/keyboard/manifest.json:7

  • Other first-party panel manifests use a consistently-capitalized author string (e.g. "author": "Omarchy"). This manifest uses "omarchy", which is inconsistent with the existing convention.
  "name": "Keyboard Layout",
  "version": "1.0.0",
  "author": "omarchy",
  "description": "Active keyboard language with add/remove and switch-shortcut picker",

Copilot AI review requested due to automatic review settings July 28, 2026 07:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

shell/plugins/panels/keyboard/Panel.qml:17

  • The widget defaults to show_bar_icon: false, which keeps it invisible until the first CLI refresh completes. Since the CLI defaults show_bar_icon to true when unset, the panel should match that default to avoid a startup flicker / missing widget.
  property var status: ({ layouts: [], switcher: "alt_shift", active: "", show_bar_icon: false })

shell/plugins/panels/keyboard/Panel.qml:745

  • Comment says there are four switch-shortcut presets, but only three presets are defined/used. This can drift out of sync with the actual UI behavior and the Hyprland mapping.
  // One of the four switch-shortcut presets, same pill styling as the
  // network panel's DNS provider picker.

shell/plugins/panels/keyboard/Model.js:2

  • Comment says there are four switcher presets, but SWITCHERS only defines three. This should be corrected to avoid misleading future edits (and to match default/hypr/input.lua's SWITCHER_OPTIONS).
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in config/hypr/input.lua.

shell/plugins/panels/keyboard/Model.js:135

  • This comment still refers to four presets, but the implementation exposes three. Keeping the comment accurate helps prevent future UI/layout math from hard-coding the wrong count.
// The four presets, for the pill row -- a fresh copy each time so callers
// can't accidentally mutate the shared list.

Copilot AI review requested due to automatic review settings July 28, 2026 07:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (4)

shell/plugins/panels/keyboard/Panel.qml:18

  • status.show_bar_icon defaults to false, which makes the widget start out invisible until the first refresh() completes. That can cause the bar widget to appear late (or never, if the initial status call fails). Defaulting to true matches the CLI/model behavior where a missing show_bar_icon is treated as enabled.
  // Raw status from `omarchy-keyboard-layout status`:
  // { layouts: [{code, label}], switcher, active, show_bar_icon }
  property var status: ({ layouts: [], switcher: "alt_shift", active: "", show_bar_icon: false })
  property var available: []

shell/plugins/panels/keyboard/Panel.qml:745

  • Comment says there are "four" switch-shortcut presets, but Model.switcherPresets() only defines three. This is likely to confuse anyone updating presets later.
  // One of the four switch-shortcut presets, same pill styling as the
  // network panel's DNS provider picker.

shell/plugins/panels/keyboard/Model.js:2

  • SWITCHERS defines three presets, but the header comment says "four", and it points at config/hypr/input.lua even though SWITCHER_OPTIONS lives in default/hypr/input.lua in this repo. Keeping these comments accurate helps prevent the presets from drifting.
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in config/hypr/input.lua.

shell/plugins/panels/keyboard/Model.js:136

  • This comment says "four presets" but SWITCHERS only has three entries. Keeping the comment accurate avoids confusion when adding/removing presets later.
// The four presets, for the pill row -- a fresh copy each time so callers
// can't accidentally mutate the shared list.
function switcherPresets() {

Comment thread default/hypr/input.lua
Comment on lines +27 to +73
-- The keyboard panel (bin/omarchy-keyboard-layout) owns this file: it's the
-- list of layouts the user picked via "Add language" plus their chosen
-- switch shortcut. jq is already a hard dependency of the Omarchy CLI
-- scripts, so shelling out to it here is simpler and less error-prone than
-- hand-rolling JSON parsing in Lua.
local STATE_FILE = os.getenv("HOME") .. "/.local/state/omarchy/settings/keyboard.json"

local vconsole = read_vconsole()
-- Runs a shell command and returns its trimmed stdout, or an empty string
-- if the command couldn't even be started.
local function popen_trim(cmd)
local handle = io.popen(cmd)
if not handle then
return ""
end
local result = handle:read("*a") or ""
handle:close()
return (result:gsub("^%s+", ""):gsub("%s+$", ""))
end

local kb_layout = vconsole.XKBLAYOUT or "us"
local kb_variant = vconsole.XKBVARIANT or ""
local kb_options = "compose:caps,shift:both_capslock"

-- Hyprland resolves keybindings against the first entry in kb_layout, not the
-- layout that's currently active, so Omarchy's Latin-keysym bindings (SUPER + W
-- and friends) only fire when a Latin layout leads. Installing with a non-Latin
-- one would otherwise leave the desktop unusable.
if non_latin_layouts:find(" " .. kb_layout:match("^[^,]*") .. " ", 1, true) then
kb_layout = "us," .. kb_layout
kb_variant = "," .. kb_variant
-- Reach the original layout with Left Alt + Right Alt.
kb_options = kb_options .. ",grp:alts_toggle"
-- Reads one field out of the keyboard state file via jq. Falls back
-- cleanly if the file is missing, unreadable, or the field isn't set --
-- Hyprland should never fail to start just because this file is stale
-- or hasn't been created yet.
local function state_field(jq_filter, fallback)
local cmd = string.format("jq -r %s %q 2>/dev/null", jq_filter, STATE_FILE)
local value = popen_trim(cmd)
if value == "" or value == "null" then
return fallback
end
return value
end

local vconsole = read_vconsole()

local kb_layout = state_field("'[.layouts[].code] | join(\",\")'", vconsole.XKBLAYOUT or "us")
local switcher = state_field("'.switcher // \"alt_shift\"'", "alt_shift")

-- The three switch-shortcut presets offered by the keyboard panel's pill
-- row, mapped to the matching xkb grp option.
local SWITCHER_OPTIONS = {
alt_shift = "grp:alt_shift_toggle",
ctrl_shift = "grp:ctrl_shift_toggle",
right_alt = "grp:toggle",
}

local grp_option = SWITCHER_OPTIONS[switcher] or SWITCHER_OPTIONS.alt_shift

Copilot AI review requested due to automatic review settings July 28, 2026 09:32
@heyssh
heyssh force-pushed the add/omarchy-keyboard-layout branch from 30b168c to 29fe044 Compare July 28, 2026 09:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

shell/plugins/panels/keyboard/Panel.qml:17

  • The initial default status sets show_bar_icon:false, which hides the bar widget until the first successful CLI status refresh. Since the CLI defaults show_bar_icon to true when unset, initialize it to true to avoid a missing icon flicker on startup.
  property var status: ({ layouts: [], switcher: "alt_shift", active: "", show_bar_icon: false })

shell/plugins/panels/keyboard/Model.js:2

  • The comment says there are four switch-shortcut presets, but SWITCHERS only defines three. This is misleading for future maintenance.
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in config/hypr/input.lua.

shell/plugins/panels/keyboard/Model.js:135

  • This comment also says “four presets” but the code defines three. Update the wording to avoid confusion.
// The four presets, for the pill row -- a fresh copy each time so callers
// can't accidentally mutate the shared list.

shell/plugins/panels/keyboard/manifest.json:18

  • The repo already ships a keyboard layout bar widget plugin with id omarchy.keyboard-layout (shell/plugins/bar/widgets/KeyboardLayout.manifest.json). Adding a second widget id (omarchy.keyboard) risks confusing users (two similar widgets, and the new menu toggle only affects the new one). Consider either replacing/migrating the existing widget, or clearly differentiating/aliasing them so there’s a single obvious keyboard-layout widget.
  "id": "omarchy.keyboard",
  "name": "Keyboard Layout",
  "version": "1.0.0",
  "author": "omarchy",
  "description": "Active keyboard language with add/remove and switch-shortcut picker",
  "kinds": [
    "bar-widget"
  ],
  "entryPoints": {
    "barWidget": "Panel.qml"
  },
  "barWidget": {
    "displayName": "Keyboard Layout",
    "description": "Active keyboard language with add/remove and switch-shortcut picker",
    "category": "System",
    "allowMultiple": false

Copilot AI review requested due to automatic review settings July 28, 2026 09:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

shell/plugins/panels/keyboard/Panel.qml:18

  • The panel starts with show_bar_icon: false, which makes the widget invisible (width/height 0) until the first successful status refresh. That can cause the bar to reflow a moment after startup. Defaulting to visible (and letting the state file/CLI override it) avoids the initial layout shift.
  // Raw status from `omarchy-keyboard-layout status`:
  // { layouts: [{code, label}], switcher, active, show_bar_icon }
  property var status: ({ layouts: [], switcher: "alt_shift", active: "", show_bar_icon: false })
  property var available: []

shell/plugins/panels/keyboard/Model.js:7

  • Comments refer to “four” switch-shortcut presets, but the code defines three (alt_shift, ctrl_shift, right_alt). This is misleading for future maintenance (and contradicts the UI). Update the comments to match the actual preset count.
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in config/hypr/input.lua.
var SWITCHERS = [
  { id: "alt_shift", label: "Alt+Shift" },
  { id: "ctrl_shift", label: "Ctrl+Shift" },
  { id: "right_alt", label: "Right Alt" }
]

default/hypr/input.lua:65

  • This removes the previous non‑Latin layout guard. If the first configured layout is non‑Latin, Hyprland resolves Omarchy’s keybindings against that first layout and Latin-keysym bindings can stop working (the existing test/shell.d/hyprland-keyboard-layout-test.sh asserts the prepend behavior). Reintroduce the non‑Latin list and prepend us, (and a leading variant comma) when needed.
local kb_layout = state_field("'[.layouts[].code] | join(\",\")'", vconsole.XKBLAYOUT or "us")
local switcher = state_field("'.switcher // \"alt_shift\"'", "alt_shift")

-- The three switch-shortcut presets offered by the keyboard panel's pill
-- row, mapped to the matching xkb grp option.

default/hypr/input.lua:88

  • After reintroducing the non‑Latin prepend logic, kb_variant needs to use the computed kb_variant value (so variants stay aligned when a leading us, is inserted). Right now it always uses vconsole.XKBVARIANT directly, which will break variant alignment for the prepended layout and fails the existing keyboard-layout test expectations.
    -- Falls back to "" (xkb's default variant) if the system's vconsole.conf
    -- never set one, or the user hasn't customized their keyboard variant.
    kb_variant = vconsole.XKBVARIANT or "",

Copilot AI review requested due to automatic review settings July 29, 2026 11:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (6)

default/hypr/input.lua:72

  • default input.lua no longer implements the non‑Latin layout safety behavior (prepending us + aligning variants) that existing shell tests assert and that prevents Hyprland keybindings from becoming unusable when the first layout is non‑Latin (see test/shell.d/hyprland-keyboard-layout-test.sh). The test suite also expects the non_latin_layouts list to remain in sync with etc/mkinitcpio.conf.d/omarchy_hooks.conf, but the list/logic has been removed here.
local kb_layout = state_field("'[.layouts[].code] | join(\",\")'", vconsole.XKBLAYOUT or "us")
local switcher = state_field("'.switcher // \"alt_shift\"'", "alt_shift")

-- The three switch-shortcut presets offered by the keyboard panel's pill
-- row, mapped to the matching xkb grp option.
local SWITCHER_OPTIONS = {
  alt_shift = "grp:alt_shift_toggle",
  ctrl_shift = "grp:ctrl_shift_toggle",
  right_alt = "grp:toggle",
}

local grp_option = SWITCHER_OPTIONS[switcher] or SWITCHER_OPTIONS.alt_shift

shell/plugins/panels/keyboard/Panel.qml:17

  • The panel’s initial status sets show_bar_icon: false, which makes the widget start hidden. If the first status call fails (e.g. missing/errored CLI), the widget can remain permanently hidden with no way to recover from the UI. Defaulting to visible is safer and matches Model.parseStatus/CLI defaults.
  property var status: ({ layouts: [], switcher: "alt_shift", active: "", show_bar_icon: false })

shell/plugins/panels/keyboard/Panel.qml:232

  • This comment references an omarchy-menu path ("Trigger > Toggle > Show Keyboard Layout") that doesn’t match the actual menu entry added in this PR (it’s under setup.keyboard-layout-icon). Keeping this accurate matters because it’s effectively user-facing documentation for how the state is controlled.
  // Manual on/off switch for the bar icon, controlled from omarchy-menu
  // (Trigger > Toggle > Show Keyboard Layout) via `omarchy-keyboard-layout
  // bar-icon toggle`. Independent of the language-code icon above -- this
  // is a deliberate user choice, not an automatic language-count heuristic.
  readonly property bool barIconVisible: status.show_bar_icon !== false

shell/plugins/panels/keyboard/Model.js:2

  • The header comment says there are "four" switch-shortcut presets, but the list currently defines three. This should match to avoid confusion when updating presets alongside default/hypr/input.lua.
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in config/hypr/input.lua.

shell/plugins/panels/keyboard/Model.js:126

  • Indentation inside the filterAvailable() sort callback is inconsistent with the 2-space indentation used elsewhere in the repo’s panel Model.js files (for example shell/plugins/panels/network/Model.js).
  return list.sort(function(a, b) {
     var ra = matchRank(a, needle)
     var rb = matchRank(b, needle)
     if (ra !== rb) return ra - rb
     var la = String(a && a.label || "")

shell/plugins/panels/keyboard/manifest.json:7

  • Panel manifests in shell/plugins/panels/*/manifest.json consistently use "author": "Omarchy". This new manifest uses a different casing ("omarchy"), which is inconsistent in listings.
  "version": "1.0.0",
  "author": "omarchy",
  "description": "Active keyboard language with add/remove and switch-shortcut picker",

Copilot AI review requested due to automatic review settings July 29, 2026 15:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

shell/plugins/panels/keyboard/Panel.qml:55

  • Model.availableScales(...) is called here, but the new shell/plugins/panels/keyboard/Model.js does not define availableScales (it contains keyboard-layout helpers). This will throw at QML load time. Either import the correct model for this Panel.qml or implement/rename the functions so Panel.qml and Model.js match.
  readonly property var scalePresets: ["1", "1.25", "1.6", "2", "3", "4"]
  readonly property var scaleValues: {
    for (var i = 0; i < displays.length; i++) {
      var display = displays[i]
      if (display && display.focused)
        return Model.availableScales(scalePresets, display.width, display.height)
    }
    return scalePresets

shell/plugins/panels/keyboard/Model.js:2

  • The header comment is incorrect: there are 3 switch-shortcut presets (not 4), and SWITCHER_OPTIONS is defined in default/hypr/input.lua (not config/hypr/input.lua). Keeping this accurate helps prevent the panel and Hyprland defaults drifting out of sync.
// The four switch-shortcut presets shown as pills in the panel. Keep this in
// sync with SWITCHER_OPTIONS in config/hypr/input.lua.

Comment on lines +9 to +13
Panel {
id: root
moduleName: "omarchy.monitor"
ipcTarget: "omarchy.monitor"
manageIpc: false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants