Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: keyboard layout #66

Closed
eternal-sorrow opened this issue Oct 28, 2018 · 43 comments · May be fixed by #556
Closed

Feature request: keyboard layout #66

eternal-sorrow opened this issue Oct 28, 2018 · 43 comments · May be fixed by #556
Labels
enhancement New feature or request
Milestone

Comments

@eternal-sorrow
Copy link

Would be really nice to have the module showing current keyboard layout. Or maybe a help to write the custom module script with this capability.

@Alexays Alexays added the enhancement New feature or request label Oct 28, 2018
@harishkrupo
Copy link
Contributor

Create a custom module with something like this in a script and run it in the exec: ?
setxkbmap -query | grep layout | cut -f2 -d":" | tr -d '[:space:]'

@eternal-sorrow
Copy link
Author

@harishkrupo it doesn't work. It always shows us (my default layout) even when I use another layout.

@harishkrupo
Copy link
Contributor

okay, will need to check. How do you pick a different layout?

@alecmev
Copy link
Contributor

alecmev commented Nov 2, 2018

@harishkrupo If you're using Sway: https://github.com/swaywm/sway/wiki#input-configuration

@harishkrupo
Copy link
Contributor

I have opened a PR for this issue: #85

@ghost
Copy link

ghost commented Dec 24, 2018

if somebody needs it:

"custom/lang": {
    "exec": "swaymsg -t get_inputs|grep -4 'AT T'|tail -1|sed 's/.*: //;s/\"//g'|cut -c 1-2|tr '[a-z]' '[A-Z]'",
    "interval": 1
},
  • Note: grep -4 'AT T' finds my particular keyboard, you probably want to change values in the script

this polls it every second, but ideally it should work as in pulseaudio module, to update whenever layout updates.
for that it needs some integration with wlroots/sway or something, and values like "name": "AT T" to identify which exact keyboard to use

@harishkrupo
Copy link
Contributor

@rvi64 Thanks!
Similar suggestions here:

There is an ongoing work to create a new protocol to get this information. See here
Unfortunately, I got busy with some other work . :(
I will try to start work on this again.

@ghost
Copy link

ghost commented Apr 1, 2019

here's a version without jq, only unix utils, shows EN by default, and first two upper case letters otherwise

  "custom/lang": {
    "exec": "swaymsg -t get_inputs | grep layout_name | grep -v En | awk 'END{if(NR == 0){print \"EN\"}else{print toupper(substr($2,2,2))}}'",
    "interval": 1,
    "format": "{} "
  },

@krtko1
Copy link

krtko1 commented May 15, 2019

here's a another version with only unix utils, shows proper language two letters shortcut

.config/waybar/modules/layout.sh

#!/bin/bash

KEYBOARD=$(swaymsg -pt get_config | awk '{if ($1 == "input") {name=$2}; if($1 == "xkb_layout") {print name; exit}}')

ACTIVE_LANGUAGE=$(swaymsg -t get_inputs | grep -5 $KEYBOARD | tail -1 | sed 's/.*"\(.*\)".*$/\1/gi')

MANPAGE=$(man --where xkeyboard-config)
case `file -bi $MANPAGE | grep -o "^[^/]*/[^;]*"` in
    'application/x-gzip') CAT='zcat';;
    'application/x-bzip2') CAT='bzcat';;
    'application/x-tar') CAT='tar -O -xf';;
    'application/x-xz') CAT='xzcat';;
    'text/plain') CAT='cat';;
esac

$CAT $MANPAGE | awk -F'[\t(]' -v var="$ACTIVE_LANGUAGE" 'index($0,var)>=1 {print $1; exit}'

.config/waybar/config

    "custom/layout": {
        "exec": "~/.config/waybar/modules/layout.sh",
        "interval": 1,
        "format": "{} "
    }

EDIT: add support for other man formats. Sadly /usr/share/X11/xkb/rules/evdev.xml is not contain needed informations

@eternal-sorrow
Copy link
Author

eternal-sorrow commented May 15, 2019

gzip: skipping: /usr/share/man/man7/xkeyboard-config.7.bz2 unrecognized format

You assume that man page is compressed with gzip.

Also, don't you think, parsing man isn't the right way to do this? The right way is parsing /usr/share/X11/xkb/rules/evdev.xml I guess.

@krtko1
Copy link

krtko1 commented May 16, 2019

@eternal-sorrow
EDIT2: I change to script to not start every time

.config/waybar/modules/layout.sh

#!/bin/bash
  
KEYBOARD=$(swaymsg -pt get_config | awk '{if ($1 == "input") {name=$2}; if($1 == "xkb_layout") {print name; exit}}')

MANPAGE=$(man --where xkeyboard-config)
case `file -bi $MANPAGE | grep -o "^[^/]*/[^;]*"` in
    'application/x-gzip') CAT='zcat';;
    'application/x-bzip2') CAT='bzcat';;
    'application/x-tar') CAT='tar -O -xf';;
    'application/x-xz') CAT='xzcat';;
    'text/plain') CAT='cat';;
esac

while true; do
    ACTIVE_LANGUAGE=$(swaymsg -t get_inputs | grep -5 $KEYBOARD | tail -1 | sed 's/.*"\(.*\)".*$/\1/gi')
    $CAT $MANPAGE | awk -F'[\t(]' -v var="$ACTIVE_LANGUAGE" 'index($0,var)>=1 {print $1; exit}'

    sleep 1
done

.config/waybar/config

    "custom/layout": {
        "exec": "~/.config/waybar/modules/layout.sh", // DO NOT RUN multiple times
        "format": "{} "
    }

@eternal-sorrow
Copy link
Author

Here's my python version. You'll need the latest git version of acrisci/i3ipc-python installed.
Set KBD_NAME to the name of your keyboard device (see swaymsg -t get_inputs).

#!/usr/bin/env -S python3 -u

import time
import i3ipc

KBD_NAME = "1:1:AT_Translated_Set_2_keyboard"

sway = i3ipc.Connection()

while True:
	inputs = sway.get_inputs()
	keyboard = [i for i in inputs if i['identifier'] == KBD_NAME][0]
	layout = keyboard['xkb_active_layout_name']
	print(layout[:2].lower())
	time.sleep(1)

@crabvk
Copy link

crabvk commented Dec 1, 2019

We can get updates from swaymsg -mrt subscribe (no "interval" setting needed) #85 (comment)

@exdeniz
Copy link

exdeniz commented Dec 25, 2019

Here's my python version. You'll need the latest git version of acrisci/i3ipc-python installed.
Set KBD_NAME to the name of your keyboard device (see swaymsg -t get_inputs).

#!/usr/bin/env -S python3 -u

import time
import i3ipc

KBD_NAME = "1:1:AT_Translated_Set_2_keyboard"

sway = i3ipc.Connection()

while True:
	inputs = sway.get_inputs()
	keyboard = [i for i in inputs if i['identifier'] == KBD_NAME][0]
	layout = keyboard['xkb_active_layout_name']
	print(layout[:2].lower())
	time.sleep(1)

Not work for me.

print inputs [<i3ipc.replies.InputReply object at 0x7f988d156dc0>, <i3ipc.replies.InputReply object at 0x7f988d1379d0>, <i3ipc.replies.InputReply object at 0x7f988d137b50>, <i3ipc.replies.InputReply object at 0x7f988cfc0910>, <i3ipc.replies.InputReply object at 0x7f988cd69d60>, <i3ipc.replies.InputReply object at 0x7f988cd69dc0>, <i3ipc.replies.InputReply object at 0x7f988cd69e20>, <i3ipc.replies.InputReply object at 0x7f988cd69e50>, <i3ipc.replies.InputReply object at 0x7f988cd69e80>, <i3ipc.replies.InputReply object at 0x7f988cd69eb0>]
Traceback (most recent call last):
  File "./layout.py", line 13, in <module>
    keyboard = [i for i in inputs if i['identifier'] == KBD_NAME][0]
  File "./layout.py", line 13, in <listcomp>
    keyboard = [i for i in inputs if i['identifier'] == KBD_NAME][0]
TypeError: 'InputReply' object is not subscriptable

@eternal-sorrow
Copy link
Author

eternal-sorrow commented Dec 25, 2019

@exdeniz This version is very outdated. It uses polling and old i3ipc API. Use that one #85 (comment) or one of others from that thread.

@vyamkovyi
Copy link

vyamkovyi commented Jan 13, 2020

Sway IPC protocol now has subscribe message type. Here is my Waybar config entry that prints current layout:

"custom/layout": {
    "tooltip": false,
    "exec": "swaymsg -mrt subscribe '[\"input\"]' | jq -r --unbuffered \"select(.change == \\\"xkb_layout\\\") | .input | select(.identifier == \\\"1:1:AT_Translated_Set_2_keyboard\\\" and .type == \\\"keyboard\\\") | .xkb_active_layout_name | .[0:2] | ascii_upcase\""
},

However:

  • When killed, Waybar disowns sh process and it keeps running until you kill swaymsg -mrt subscribe ["input"] process.
  • Notice that "1:1:AT_Translated_Set_2_keyboard" - it seems that keyboard identification is a fundamental problem to wayland protocol. There seems to be no reliable way to differentiate between a real keyboard and "keyboards" that are actually power buttons and other special buttons.
  • Remember to install jq

I would be really happy to see this inside Waybar.

@krtko1
Copy link

krtko1 commented Jan 15, 2020

@Hexawolf I created pull request with waybar module which shows keyboard layout. Yes it still use 1:1:AT_Translated_Set_2_keyboard but only on startup. Also it can show short layout names from /usr/share/X11/xkb/rules/evdev.xml.

@vyamkovyi
Copy link

One might want to use a more generic version while pull request is still not merged:

"custom/layout": {
    "tooltip": false,
    "exec": "swaymsg -mrt subscribe '[\"input\"]' | jq -r --unbuffered \"select(.change == \\\"xkb_lay
out\\\") | .input | select(.type == \\\"keyboard\\\") | .xkb_active_layout_name | .[0:2] | ascii_upcase\""
}

@donnex
Copy link

donnex commented Feb 16, 2020

I just built a little bit on the previous answers and uses the following to show flags for layouts in waybar.

"custom/keyboard_layout": {
    "exec": "waybar_sway_keyboard_layout",
    "tooltip": false
}

waybar_sway_keyboard_layout

#!/bin/sh

DEFAULT_LAYOUT="English (US)"

# Kill old instances since waybar don't kill them when exited
[ "$(pgrep -a 'swaymsg' | grep -c '["input"]')" -gt 0 ] &&
  pgrep -a 'swaymsg' | grep '["input"]' | cut -d ' ' -f1 | xargs -r kill

# Sleep for a short while in order to prevent startup issues in waybar
sleep 0.5

keyboard_flag() {
  while read -r layout; do
    if [ "$layout" = "English (US)" ]; then
      layout_waybar="🇺🇸"
    elif [ "$layout" = "Swedish" ]; then
      layout_waybar="🇸🇪"
    else
      layout_waybar="$layout"
    fi

    printf '%s\n' "$layout_waybar"
  done
}

echo "$DEFAULT_LAYOUT" | keyboard_flag
swaymsg -mrt subscribe '["input"]' | jq -r --unbuffered "select(.change == \"xkb_layout\") | .input | select(.type == \"keyboard\") | .xkb_active_layout_name" | keyboard_flag

@vyamkovyi
Copy link

I made a simple C program for displaying layouts using sway IPC subscription:
https://github.com/Hexawolf/swaylay

@BlueGone
Copy link
Contributor

#659 should solve this.

@asahaf
Copy link

asahaf commented Apr 11, 2020

I've a custom python script to get the layout using i3ipc library (python-i3ipc). it subscribes to input changes to get notified when the layout changes without the need to poll in a loop.

xkblayout.py:

#!/usr/bin/env -S python3 -u
# vi:syntax=python


import os
import signal

import i3ipc

pri_layout_code = "EN"
sec_layout_code = "AR"
sec_layout_name = "arabic"
input_event_change = "xkb_layout"

sway_sock_path = os.environ["SWAYSOCK"]
sway = i3ipc.Connection(socket_path=sway_sock_path, auto_reconnect=False)


def on_posix_signal(sig, frame):
    sway.main_quit()


signal.signal(signal.SIGHUP, on_posix_signal)
signal.signal(signal.SIGINT, on_posix_signal)
signal.signal(signal.SIGQUIT, on_posix_signal)
signal.signal(signal.SIGTERM, on_posix_signal)

# print the primary layout as it's the default
print(pri_layout_code)


def on_input_change(conn, event):
    if event.change != input_event_change:
        return
    if event.input.xkb_active_layout_name.lower() == sec_layout_name:
        print(sec_layout_code)
    else:
        print(pri_layout_code)


def on_shutdown_or_reload(conn, event):
    conn.main_quit()


sway.on(i3ipc.Event.INPUT, on_input_change)
sway.on(i3ipc.Event.SHUTDOWN, on_shutdown_or_reload)
sway.on(i3ipc.Event.SHUTDOWN_EXIT, on_shutdown_or_reload)
sway.on(i3ipc.Event.SHUTDOWN_RESTART, on_shutdown_or_reload)
sway.on(i3ipc.Event.BARCONFIG_UPDATE, on_shutdown_or_reload)
sway.main()

make sure you make xkblayout.py executable

config:

.......
.......
"custom/xkblayout": {
        "exec": "path/to/xkblayout.py",
        "format": " {}",
        "tooltip": false
    },
.......
.......

@krtko1
Copy link

krtko1 commented Apr 11, 2020

if I read correctly, #659 also interact just to input change

@asahaf
Copy link

asahaf commented Apr 11, 2020

@krtko1 yes it does subscribe to input change events

@mxkrsv
Copy link

mxkrsv commented Oct 3, 2020

I rewrote a jq version in sed and embedded it into the single 'exec' object, so it doesn't need any external script execuion:

"exec": "swaymsg --type get_inputs | grep \"xkb_active_layout_name\" | sed -u '1!d; s/^.*xkb_active_layout_name\": \"//; s/ (US)//; s/\",//' && swaymsg --type subscribe --monitor '[\"input\"]' | sed -u 's/^.*xkb_active_layout_name\": \"//; s/\",.*$//; s/ (US)//'",

@kblcuk
Copy link

kblcuk commented Jan 10, 2021

FWIW those running Waybar in Sway can just use sway/language: https://github.com/Alexays/Waybar/blob/master/man/waybar-sway-language.5.scd

@tigerjack
Copy link

FWIW those running Waybar in Sway can just use sway/language: https://github.com/Alexays/Waybar/blob/master/man/waybar-sway-language.5.scd

Great, I just added it and it seems to work. Do you think it would be possible to add also the variant together with the layout name?

@Anakael
Copy link
Contributor

Anakael commented Apr 18, 2021

Any updates here?

@hirmanpour
Copy link

Two enhancements to sway/language could be added:

  • The first is to minimally differentiate between several keyboards belonging to the same language by adding an index to the indicator. For example, I use a standard US keyboard and a US keyboard with dead keys. They both show as EN. In Gnome they would show as EN1 and EN2
  • The second, perhaps easier to implement, is to offer the formatting option to show the full name of the keyboard used : e.g. "US Intl Keyboard (with dead keys)" could be displayed when hovering on the indicator.

@Anakael
Copy link
Contributor

Anakael commented Jul 11, 2021

@hirmanpour
I think I can implement the first option.

@hirmanpour
Copy link

That would be great !

As a side note regarding the first option, according to ArchWiki one can get the current layout with this command:

swaymsg -t get_inputs | jq -r '.[] | select(.identifier == "kbd_identifier") | .xkb_active_layout_name'

But that depends on kbd_identifier, which is different for each computer model.

For a plug-in general solution, one would need, unless a kbd_identifier is manually specified by the end user, to automatically extract the kbd_identifier from the list of inputs (assuming there is only one input with type "keyboard" attached, which seems a reasonable assumption that would work for 99%+ of users), and feed it into this command.

@bnjw5jhyxn
Copy link

@hirmanpour I might just be in the 1% of users who got unlucky here, but here is the output of

swaymsg -t get_inputs | jq -r '.[] | select(.type == "keyboard") | .identifier'

on my laptop:

0:0:HP_WMI_hotkeys
0:0:HP_Wireless_hotkeys
1:1:AT_Translated_Set_2_keyboard
1032:21248:HP_Wide_Vision_HD_Camera:_HP_Wi
0:1:Power_Button
0:6:Video_Bus
0:1:Power_Button

@Anakael
Copy link
Contributor

Anakael commented Jul 23, 2021

@hirmanpour
Implemented in #1159

@hirmanpour
Copy link

@bnjw5jhyxn Oh god ! Lucky one percenter ;-)

Could it be that I might also be the proud owner of 7 keyboards, without knowing it ???

@hirmanpour
Copy link

@Anakael Many thanks !

@gbrlsnchs
Copy link

Does this only work for Sway?

@Anakael
Copy link
Contributor

Anakael commented Jul 28, 2021

@gbrlsnchs
Yes, sway/language works only with sway.

@soppelmann
Copy link

sway/language currently doesn't differentiate between English layouts.
I use a UK keyboard on my laptop and a US keyboard at home but both show up as EN.
English is the language not the layout. Perhaps a sway/layout would be a better name.

@Anakael
Copy link
Contributor

Anakael commented Aug 19, 2021

sway/language currently doesn't differentiate between English layouts.
I use a UK keyboard on my laptop and a US keyboard at home but both show up as EN.
English is the language not the layout. Perhaps a sway/layout would be a better name.

Renaming the module name will break compatibility.

@Anakael
Copy link
Contributor

Anakael commented Aug 19, 2021

sway/language currently doesn't differentiate between English layouts.
I use a UK keyboard on my laptop and a US keyboard at home but both show up as EN.

keyboard != layout.

With last update UK layout should be written as gb for flag {name} and English (UK) for {long} flag.
image
image

@boredland
Copy link

boredland commented Jan 8, 2022

I really like the default sway/language module, but would it be possible to display it conditionally if there is more than one layout configured? otherwise it is wasting that precious space 🌴

@keithbowes
Copy link

setxkbmap -query | grep layout | cut -f2 -d":" | tr -d '[:space:]'

bash: setxkbmap: Command not found

Hm.

@Anakael
Copy link
Contributor

Anakael commented Feb 27, 2022

could you try install libxkbcommon?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.