Search code examples
haskellfunctional-programmingxmonadio-monadxmobar

How can I change XMobar's Kbd monitor plugin such that clicking on it loops throught the layouts?


The Kbd monitor plugin can be installed in the xmobar status bar like this,

Run $ Kbd [("it", "IT"), ("ru(phonetic)", "RU")]

and then switch keyboard via setxkbmap, the monitor will reflect the change.

So far so good.

Now, assume that

  • I want to make the monitor clickable,
  • and that the click should "rotate" the keyboard layout (among those provided, see the [] above)

even if this means writing MyOwnKbd plugin.

Also assume that another requirement is that I don't want the logic of rotation to be encoded in an external script.


Since I don't want to bind a key to switching between keyboards¹, I was thinking about allowing the switch via clicking on the monitor itself.

I know I can just wrap the text of the monitor in <action=`the command`> and </action> to make it clickable, but I have no clue what the command should be.

I know that I could write a shell script that detects the state of the keyboard and sets the other one, but I want to use the very list above, [("it", "IT"), ("ru(phonetic)", "RU")] as the source of what keyboard layouts clicking the monitor should loop through, so the question becomes: can I feed the click-on-monitor event back to the business logic of the monitor?

Or, if that's not possible, what other alternatives do I have?


(¹) E.g. I could have done

setxkbmap -layout it,ru -variant ,phonetic -option 'grp:caps_toggle'

once and for all, and Caps Lock would allow to switch between those two layouts, and the plugin, as is, would reflect which layout is in use. But I don't want to map any key to the layout switching action.

Well, it's not that I don't want that solution, but I'm curious to know what another solution would be.


(I've deleted a previous question because the specific scenario that led me to formulate it was actually complicating the matter. I'll un-delete it if the answer to this question will be insufficient for that.)


Solution

  • In reality, the best solution is simply to hardcode the actions at the point of creation of Kbd:

    Run $ Kbd [("it", "<action=`setxkbmap -layout ru -variant phonetic` button=1>it</action>"),
               ("ru(phonetic)", "<action=`setxkbmap -layout it` button=1>ru</action>")]
    

    Old answer

    Eventually I came up with a solution myself, which was merged with the PR #696.

    When I wrote

    I know I can just wrap the text of the monitor in <action=`the command`> and </action> to make it clickable, but I have no clue what the command should be.

    I was making the mistake of thinking that I have to know the command that does the right thing whatever the current layout, but that's incorrect, as I can just compute a different command for each layout, which will simply switch to the next one.

    To give a concrete example, if I install the plugin like this,

    Run $ Kbd [("it", "IT"), ("ru(phonetic)", "RU"), ("us", "US")]
    

    the text I want to print when each of the 3 layouts is selected is as follows:

    • "<action=`setxkbmap -layout ru -variant phonetic` button=1>IT</action>"
    • "<action=`setxkbmap -layout us` button=1>RU</action>"
    • "<action=`setxkbmap -layout it` button=1>US</action>"

    This allow switching layouts in the order IT->RU->US. In the code I've contributed to xmobar, I've also wrapped those in actions to navigate the opposite direction with button=3.