Change keyboard maps

From awesome
Jump to: navigation, search

Display/change keyboard map[edit]

Introduction[edit]

This widget displays the layout used by the keyboard. If clicked, it switchs between the list of user defined layouts. You have to set the current index to your default layout in order to be consistent with your system configuration.

This widget uses 'setxkbmap' to set the layout.

Widget code (awesome 3.5)[edit]

Paste the following code into your rc.lua somewhere before the wibox definition.

-- Keyboard map indicator and changer
kbdcfg = {}
kbdcfg.cmd = "setxkbmap"
kbdcfg.layout = { { "us", "" }, { "de", "" } }
kbdcfg.current = 1  -- us is our default layout
kbdcfg.widget = wibox.widget.textbox()
kbdcfg.widget:set_text(" " .. kbdcfg.layout[kbdcfg.current][1] .. " ")
kbdcfg.switch = function ()
  kbdcfg.current = kbdcfg.current % #(kbdcfg.layout) + 1
  local t = kbdcfg.layout[kbdcfg.current]
  kbdcfg.widget:set_text(" " .. t[1] .. " ")
  os.execute( kbdcfg.cmd .. " " .. t[1] .. " " .. t[2] )
end

 -- Mouse bindings
kbdcfg.widget:buttons(
 awful.util.table.join(awful.button({ }, 1, function () kbdcfg.switch() end))
)
-- Add widget to your layout
right_layout:add(kbdcfg.widget)

Widget code (awesome <= 3.4)[edit]

Paste the following code into your rc.lua somewhere before the wibox definition.

    -- Keyboard map indicator and changer
    kbdcfg = {}
    kbdcfg.cmd = "setxkbmap"
    kbdcfg.layout = { "us", "fr", "dvorak" }
    kbdcfg.current = 1  -- us is our default layout
    kbdcfg.widget = widget({ type = "textbox", align = "right" })
    kbdcfg.widget.text = " " .. kbdcfg.layout[kbdcfg.current] .. " "
    kbdcfg.switch = function ()
       kbdcfg.current = kbdcfg.current % #(kbdcfg.layout) + 1
       local t = " " .. kbdcfg.layout[kbdcfg.current] .. " "
       kbdcfg.widget.text = t
       os.execute( kbdcfg.cmd .. t )
    end
    
    -- Mouse bindings
    kbdcfg.widget:buttons(awful.util.table.join(
        awful.button({ }, 1, function () kbdcfg.switch() end)
    ))

Then add kbdcfg.widget to your wibox and restart Awesome.

Enabling accelerator keys[edit]

At this point, accelerator keys (e.g. CTRL-C in Firefox) will not work when you are in an "exotic" layout. A simple way to fix this is to always pass the "us" layout to setxkbmap after the primary layout.

   kbdcfg.current = kbdcfg.current % #(kbdcfg.layout) + 1
   local layout = kbdcfg.layout[kbdcfg.current]
   kbdcfg.widget.text = " " .. layout .. " "
   os.execute( kbdcfg.cmd .. " " .. layout .. ",us" )

The astute reader will observe that we are occasionally passing "us" twice to setxkbmap. This does not seem to cause problems on my box. You are welcome to come up with a more sophisticated solution.


Another example[edit]

Recently one user requested a version of this widget that will allow passing additional custom arguments to setxkbmap, for example when using the "ru" layout he wanted to add the "phonetic" option. Let's see a quick modification of the above widget that will allow that.

Widget code[edit]

    -- Keyboard map indicator and changer
    kbdcfg = {}
    kbdcfg.cmd = "setxkbmap"
    kbdcfg.layout = { { "us", "" }, { "ru", "phonetic" } }
    kbdcfg.current = 1  -- us is our default layout
    kbdcfg.widget = widget({ type = "textbox", align = "right" })
    kbdcfg.widget.text = " " .. kbdcfg.layout[kbdcfg.current][1] .. " "
    kbdcfg.switch = function ()
       kbdcfg.current = kbdcfg.current % #(kbdcfg.layout) + 1
       local t = kbdcfg.layout[kbdcfg.current]
       kbdcfg.widget.text = " " .. t[1] .. " "
       os.execute( kbdcfg.cmd .. " " .. t[1] .. " " .. t[2] )
    end
    
    -- Mouse bindings
    kbdcfg.widget:buttons(awful.util.table.join(
        awful.button({ }, 1, function () kbdcfg.switch() end)
    ))



Keyboard bindings[edit]

Example globalkeys binding that will switch the layout:

    -- Alt + Right Shift switches the current keyboard layout
    awful.key({ "Mod1" }, "Shift_R", function () kbdcfg.switch() end),

Debugging[edit]

You might encounter something like:

/home/qubodup/.config/awesome/rc.lua:147: attempt to index global 'kbdcfg' (a nil value)

In such a case, make sure to define kbdcfg before it is added to the wibox.

Per-window keyboard layout[edit]

This is the feature I missed most after the transition from KDE 4 to awesome. KDE has an option to remember the last layout used on every window (or application), and change the current layout accordingly when the active window changes. This is extremely useful when switching between, say, an IM window and a terminal.

The KDE 4 keyboard service can be started manually. To do this you will need some KDE packages installed (in Ubuntu you'll need at least kdelibs-bin and kde-workspace-bin) and the qdbus utility. Add the following to your ~/.xinitrc file:

(pidof kded4 || kded4) && qdbus org.kde.kded /kded loadModule keyboard &

Once the service is running, you'll see a neat keyboard layout indicator (with country flags, if you have them installed). You can right click it and choose Configure (alternatively, you can run 'kcmshell4 keyboard' from the command line), and set the Switching Policy to your preference.

Using xkb-switch[edit]

xkb-switch tool can switch keyboard layout groups using common X-server interface. It is a small C++ application which uses J. Bromley's XKeyboard library. Here is what it does:

    $ xkb-switch -h
    Usage: xkb-switch -s ARG            Sets current layout group to ARG
           xkb-switch -l|--list         Displays all layout groups
           xkb-switch -h|--help         Displays this message
           xkb-switch -v|--version      Shows version number
           xkb-switch -w|--wait [-p]    Waits for group change and exits
           xkb-switch -W                Infinitely waits for group change
           xkb-switch [-p]              Displays current layout group
    $ xkb-switch -l
    us
    ru
    $ xkb-switch -s ru

Well, application is poorly tested (I'am using only few layout schemes) so any feedback is welcome.

Installing xkb-switch[edit]

To install it type

    $ git clone git://github.com/ierton/xkb-switch 
    $ cd xkb-switch
    $ cmake . && make
    $ sudo make install
    

Keyboard layout indicator[edit]

I'am using pipelets to update keyboard indicator. The main shell-script is as short as

    $ cat pipelets/kbd
    #!/bin/sh
    xkb-switch
    exec xkb-switch -W

it will monitor X event queue and print new layout symbol every time it changes. To receive these notifications in lua, one should obtain pipelet files (check my config) and register widget like this:

    require("pipelets")
    
    -- Pipelets
    pipelets.config.script_path = awful.util.getdir("config").."/pipelets/"
    pipelets.init() -- will launch pipeman
    
    -- Somewhere in widgets part..
    mykbd = {}
    mykbd = widget({ type = "textbox", align="right" })
    pipelets.register_fmt(mykbd, "kbd", " $1 ")
    -- Now use mykbd widget as usual


Switching layouts[edit]

There is no need for any lua-based keyboard layout switching. Just configure your X server with ~/.xinitrc or similar. Here is my startup script for example:

    % cat ~/.xinitrc 
    #!/bin/bash
    setxkbmap -layout us,ru
    setxkbmap -option
    setxkbmap -option 'grp:alt_space_toggle'
    setxkbmap -option 'grp:shift_toggle'
    setxkbmap -option 'grp_led:caps'
    setxkbmap -option 'ctrl:swapcaps'
    setxkbmap -option 'ctrl:nocaps'
    xset r rate 260
    xscreensaver -nosplash &
    exec /usr/local/bin/awesome