Source code for i3pystatus.xkblayout
import subprocess
from itertools import zip_longest
from i3pystatus import IntervalModule
from xkbgroup import XKeyboard
[docs]class Xkblayout(IntervalModule):
"""Displays and changes current keyboard layout.
``change_layout`` callback finds the current layout in the
``layouts`` setting and enables the layout following it. If the
current layout is not in the ``layouts`` setting the first layout
is enabled.
``layouts`` can be stated with or without variants,
e.g.: ``status.register("xkblayout", layouts=["de neo", "de"])``
Requires xkbgroup (from PyPI)
.. rubric:: Available formatters
* `{num}` — current group number
* `{name}` — current group name
* `{symbol}` — current group symbol
* `{variant}` — current group variant
* `{count}` — number of all groups
* `{names}` — names of all groups
* `{symbols}` — symbols of all groups
* `{variants}` — variants of all groups
"""
interval = 1
color = "#FFFFFF"
format = "\u2328 {symbol}"
layouts = []
uppercase = True
settings = (
("color", "RGB hexadecimal color code specifuer, defaults to #FFFFFF"),
("format", "Format string"),
("layouts", "List of layouts"),
("uppercase", "Flag for uppercase output"),
)
on_leftclick = ["change_layout", 1]
on_upscroll = ["change_layout", 1]
on_downscroll = ["change_layout", -1]
def init(self):
if self.layouts:
self.set_layouts(self.layouts)
self._xkb = XKeyboard(auto_open=True)
def set_layouts(self, layouts):
self.layouts = layouts # Set, so that it could be used as a callback
layouts_parts = [x.split() for x in self.layouts]
symbols_variants_zipped = zip_longest(*layouts_parts, fillvalue="")
symbols_variants_str = [",".join(x) for x in symbols_variants_zipped]
assert len(symbols_variants_str) > 0
if len(symbols_variants_str) == 1:
symbols = symbols_variants_str[0]
args = "setxkbmap -layout {}".format(symbols)
elif len(symbols_variants_str) == 2:
(symbols, variants) = symbols_variants_str
args = "setxkbmap -layout {} -variant {}".format(symbols, variants)
else:
raise ValueError("Wrong layouts value: {}".format(self.layouts))
subprocess.check_call(args.split())
def change_layout(self, increment=1):
self._xkb.group_num += increment
def run(self):
cdict = {
"num": self._xkb.group_num,
"name": self._xkb.group_name,
"symbol": self._xkb.group_symbol,
"variant": self._xkb.group_variant,
"count": self._xkb.groups_count,
"names": self._xkb.groups_names,
"symbols": self._xkb.groups_symbols,
"variants": self._xkb.groups_variants,
}
full_text = self.format.format(**cdict)
full_text = full_text.upper() if self.uppercase else full_text
self.data = cdict
self.output = {
"full_text": full_text,
"color": self.color,
}