You are not logged in.
Hello all,
I'm trying to figure out how to programmatically detect what is the current X keyboard layout. I use us, latam, and br and it's a pain to never be sure what the active layout is without hitting a key. What I want to do is to be able to make a keyboard layout plugin for ruby-wmii that will show me the current layout and possibly let me change it. Though the target language is eventually Ruby, using C will work too, since I could just make a Ruby extension if necessary. I'm currently looking at some code to see if I can figure out how to read the current layout and then possibly change it, but it'd be great if someone could point out the correct way.
Thanks and regards,
j
Offline
I was wondering about the same thing. I use 4 keyboard layouts, never sure which one I'm using at the moment...
Offline
Well, I think I've got it figured out. I studied up on some other programs and created a program that will now let me retrieve the current layout. There are three things that are missing:
1. A way to get the layout abbreviation. My program will return the full name of the group. In my case I get "USA", "Latin American" or "Brazil" when something like "us", "latam" or "br" would be better for a status bar indicator. I am working on this right now.
2. A way to set the layout. This way I can use a ruby-wmii bar applet to also change the group by clicking with the mouse or rolling the wheel. It would be nice to have it integrated into my code, but I may just end up scripting something with setxkbmap.
3. Error handling - the program is more proof of concept right now. I will clean it up to do at least some error handling.
What window manager do you use? If you use ruby-wmii I'd be glad to give you the bar applet once its done. If you're using something else I could give you some code that would dump the current layout name to stdout.
Regards,
j
Offline
Would the output of 'setxkbmap -print' be any use?
Maybe something like:
setxkbmap -print | grep xkb_symbols | sed 's|.*+\([^"]\+\).*|\1|'
That gives me:
de(nodeadkeys)
You can send this sort of thing back to setxkbmap using the -layout option to set the map, e.g.:
setxkbmap -layout 'de(nodeadkeys)'
larch: http://larch.berlios.de
Offline
Xfce's xkb plugin knows all about short country codes and switching layouts. It might be worth a browse.
http://svn.xfce.org/index.cgi/xfce-good … ugin/xkb.c
http://svn.xfce.org/index.cgi/xfce-good … b-plugin.c
The first file seems more interesting. The 2nd one is mostly GTK2 GUI stuff.
Offline
Would the output of 'setxkbmap -print' be any use?
Maybe something like:
setxkbmap -print | grep xkb_symbols | sed 's|.*+\([^"]\+\).*|\1|'
That gives me:
de(nodeadkeys)
I looked at setxkbmap, but it didn't pan out. Here's the xkb_symbols line from the output of setxkbmap -print for me:
xkb_symbols { include "pc+us+latam:2+br:3+group(shifts_toggle)" };
When I ran your command, I got "group(shifts_toggle)." Note the xkb_symbols line contains all three of the layouts I am using. This presents two problems. First, I did some experiments and there is no way to know which is the active layout. Second, I can get the layout abbreviations (maybe) but it's not clear that I could reliably associate the abbreviations with a layout, given the other noise in the line. Thanks for the suggestion, though.
Xfce's xkb plugin knows all about short country codes and switching layouts. It might be worth a browse.
http://svn.xfce.org/index.cgi/xfce-good … ugin/xkb.c
Thanks for the suggestion, I was looking at some of KDE's stuff and that's how I've gotten as far as I have, but I couldn't find where it set the layout (I believe it is managing the layouts via Qt rather than directly through libX11.) Perhaps the XFCE stuff will be a bit simpler.
Regards,
j
Offline
I looked at setxkbmap, but it didn't pan out. Here's the xkb_symbols line from the output of setxkbmap -print for me:
xkb_symbols { include "pc+us+latam:2+br:3+group(shifts_toggle)" };
... Note the xkb_symbols line contains all three of the layouts I am using.
Oh, wow, I see your problem. Out of interest, could you post the xorg.conf line(s) - or whatever else it was - that led to this?
Another idea that might get round this: if you are using some sort of gui for reading/setting keymap, you wouldn't really need all your layouts included in xorg.conf - you could just put them in the setter utility. But there might be some layouts that intrinsically wouldn't work with this method, I only tested a couple.
Anyway, if you find an acceptable solution, please let us know, it could be quite useful.
larch: http://larch.berlios.de
Offline
Here is the keyboard InputDevice section of my xorg.conf:
Section "InputDevice"
Identifier "Keyboard0"
Driver "keyboard"
Option "CoreKeyboard"
Option "XkbRules" "xorg"
Option "XkbModel" "pc101"
Option "XkbLayout" "us,latam,br"
Option "XkbOptions" "grp:shifts_toggle"
EndSection
The setxkbmap output looked kind of odd to me. I don't get the "pc+us+latam" part. Anyway, as you can see it is pretty much textbook setting up multiple language layouts. I don't use any GUI tools to manage the layout because I've never really needed it. In the past, when I used KDE, I used kkbswitch to show the current layout, but I still had the layouts in xorg.conf. I use xmodmap to map my multimedia keys, add a Mod3 key and a number of other custom keys and I've found that most GUI tools completely nuke my xmodmap setup because they are not aware of anything except the basic maps themselves.
Anyway, I've browsed the code for the XFCE xkb panel app (suggested by peart, thank you) and it looks promising. I just need to integrate switching layouts into the code I've already got and I think I'll be good. When I finish I'll be glad to post any code and Ruby scripts if anyone is interested.
Regards,
j
Offline
I was wondering about the same thing. I use 4 keyboard layouts, never sure which one I'm using at the moment...
I've got a solution. I've got a C++ class that I wrapped with SWiG to make a ruby extension. This is useful for me since I use ruby-wmii. This allows me to get the group names and symbols and change the current group. I'd like to be able to respond to layout change events, but this is a bit more complicated and what I've got right now is useful.
If anyone else wants this or some variation (CLI program, etc.) let me know and I can probably put something together.
Regards,
j
Offline
I've got a solution. I've got a C++ class that I wrapped with SWiG to make a ruby extension. This is useful for me since I use ruby-wmii. This allows me to get the group names and symbols and change the current group. I'd like to be able to respond to layout change events, but this is a bit more complicated and what I've got right now is useful.
If anyone else wants this or some variation (CLI program, etc.) let me know and I can probably put something together.
Regards,
j
A CLI version would be great, but please post at least the C++ class.
larch: http://larch.berlios.de
Offline
A CLI version would be great, but please post at least the C++ class.
OK, then. You can get the tarball here. There is a README file in the tarball that will explain everything. The tarball contains the C++ class, the files necessary to build a Ruby extension, and a Ruby CLI script that can query and change XKB state.
Enjoy,
j
Offline
Hi
OK, then. You can get the tarball here.
I don't succeed in building the ruby extension, I get the following errors after using swig and extconf, when running make:
g++ -I. -I/usr/lib/ruby/1.8/i686-linux -I/usr/lib/ruby/1.8/i686-linux -I. -D_FILE_OFFSET_BITS=64 -fPIC -march=i686 -mtune=generic -O2 -pipe -fPIC -c XKeyboard_wrap.cxx
XKeyboard_wrap.cxx: In function 'int _wrap_XKeyboard_group_names(void*, Tcl_Interp*, int, Tcl_Obj* const*)':
XKeyboard_wrap.cxx:1926: erreur: lvalue required as left operand of assignment
XKeyboard_wrap.cxx:1929: erreur: invalid conversion from 'Tcl_Obj*' to 'VALUE'
XKeyboard_wrap.cxx:1929: erreur: initializing argument 1 of 'void rb_ary_store(VALUE, long int, VALUE)'
XKeyboard_wrap.cxx: In function 'int _wrap_XKeyboard_group_symbols(void*, Tcl_Interp*, int, Tcl_Obj* const*)':
XKeyboard_wrap.cxx:1953: erreur: lvalue required as left operand of assignment
XKeyboard_wrap.cxx:1956: erreur: invalid conversion from 'Tcl_Obj*' to 'VALUE'
XKeyboard_wrap.cxx:1956: erreur: initializing argument 1 of 'void rb_ary_store(VALUE, long int, VALUE)'
make: *** [XKeyboard_wrap.o] Erreur 1
I use ruby-wmii and am trying to write a much simpler keyboard plugin for it. But I don't know anything about programming. I use only two layouts, us and dk.
It would be something like that in the big lines
-- info = %x{setxkbmap -print}.grep(/xkb_symbols/).first.split[3].sub(/\"pc\+/,'').sub(/\"/,'') -->This gives in my case either "us" or "dk"
-- bar.data = #{info}
-- bar.on_click(....) do
if info == "us" 'setxkbmap dk' bar.data = "dk"
else 'setxkbmap us' bar.data = "us"
The problem is I don't know programming and I don't figure out how to update the #{info} when bar is clicked, and I don't succeed in actually changing the layout.
If anyone would give me some tips
Thanks
Skualito
Last edited by skualito (2008-12-04 19:40:23)
Offline
You can also use the following script to change the keyboard layout:
if [ `setxkbmap -print | grep xkb_symbols | awk '{print $4}' | awk -F"+" '{print $2}'` = us ] ;then echo "EN"; echo "changing to RU..."; setxkbmap ru ; else echo "RU"; echo "Changing to US..."; setxkbmap us ; fi
Register Linux User # 498995
Offline
Thanks jazz1303. That's what I needed
Offline
btw, have you seen libxklavier?
it's a somewhat more high-level library for doing keyboard layout stuff.
Offline
I don't succeed in building the ruby extension, I get the following errors after using swig and extconf, when running make:
g++ -I. -I/usr/lib/ruby/1.8/i686-linux -I/usr/lib/ruby/1.8/i686-linux -I. -D_FILE_OFFSET_BITS=64 -fPIC -march=i686 -mtune=generic -O2 -pipe -fPIC -c XKeyboard_wrap.cxx XKeyboard_wrap.cxx: In function 'int _wrap_XKeyboard_group_names(void*, Tcl_Interp*, int, Tcl_Obj* const*)': XKeyboard_wrap.cxx:1926: erreur: lvalue required as left operand of assignment XKeyboard_wrap.cxx:1929: erreur: invalid conversion from 'Tcl_Obj*' to 'VALUE' XKeyboard_wrap.cxx:1929: erreur: initializing argument 1 of 'void rb_ary_store(VALUE, long int, VALUE)' XKeyboard_wrap.cxx: In function 'int _wrap_XKeyboard_group_symbols(void*, Tcl_Interp*, int, Tcl_Obj* const*)': XKeyboard_wrap.cxx:1953: erreur: lvalue required as left operand of assignment XKeyboard_wrap.cxx:1956: erreur: invalid conversion from 'Tcl_Obj*' to 'VALUE' XKeyboard_wrap.cxx:1956: erreur: initializing argument 1 of 'void rb_ary_store(VALUE, long int, VALUE)' make: *** [XKeyboard_wrap.o] Erreur 1
Hello there. I realize this is some months late, but just for posterity, I've looked at the problem and it turns out that for some reason the std::vector<std::string> to ruby array mapping in XKeyboard.i wasn't working any more. I fixed the problem and uploaded a new tarball. You can get it here.
Regards.
Offline
thanks jbromley,
your code really helped me.
...
I'm glad to hear someone has made use of it. I've just patched up the ruby wrappers, so the ruby extension should be working again.
Enjoy.
Offline
jbromley, bergundy - thanks for the code, weird there was no such utility already.
Offline
I thought a bit and made it into a package: http://aur.archlinux.org/packages.php?ID=29137
There're some issues so far, though: no LICENSE defined, a few improvements needed to be made to the Makefiles (so far done during package build).
Offline
I thought a bit and made it into a package: http://aur.archlinux.org/packages.php?ID=29137
There're some issues so far, though: no LICENSE defined, a few improvements needed to be made to the Makefiles (so far done during package build).
You can make the license whatever you'd like. If this code helps anyone then let's just get it out there.
Offline
I'd make it GPLv3 (or v2), but as a packager I have no authorito to put a license in. It must be distributed with the code; or, I guess, the authors must at least explicitly specify it on the site.
Alternatively, just say it's in the public domain.
Last edited by veox (2009-08-13 10:45:28)
Offline
I'd make it GPLv3 (or v2), but as a packager I have no authorito to put a license in. It must be distributed with the code; or, I guess, the authors must at least explicitly specify it on the site.
Alternatively, just say it's in the public domain.
This weekend I'll try to add some license information so you can package it up.
Offline
thanks for the code, weird there was no such utility already.
You need to install an RTFM interface.
Offline
veox wrote:thanks for the code, weird there was no such utility already.
I looked at it and it was not satisfying. Here is why I wrote the code under discussion.
1. I use xmodmap to modify my keyboard layout. Switching with xxkb (or any other layout switcher, I've tried those from GNOME, KDE, and XFCE) nuked my custom key configuration. I could find no way to make these tools pay attention to my custom layout. This was a huge problem for me.
2. Most switchers are tray apps. At the time I was wrote this I was using wmii, which had (has?) no system tray. These tools also generally require that you use the mouse, something that I avoid.
3. I was writing a bunch of modules for wmii-ruby and I thought, why not?
So certainly similar software existed, but still there was none that did exactly what I wanted.
Regards.
Offline
jbromley, thanks for the code, it works perfectly.
Just to complete it, I have created a very simple bar applet for ruby-wmii that displays the current layout, and allows me to change it on a click of a mouse:
bar_applet("xkb", 900) do |wmii, bar|
require 'ruby-wmii/xkb'
xkb = Xkb::XKeyboard.new
Thread.new do
loop do
bar.data = xkb.current_group_symbol
sleep 1
end
end
bar.on_click do |name, button|
curr_group = xkb.current_group_num
curr_group += 1
xkb.set_group_by_num curr_group
bar.data = xkb.current_group_symbol
end
end
Offline