How to change Keyboard Layout (a X11 API solution)

前端 未结 4 2214
Happy的楠姐
Happy的楠姐 2020-12-17 05:15

I want to change keyboard layout in Linux by programming, What X11\'s API function does this?

相关标签:
4条回答
  • 2020-12-17 06:03

    A pure X11 API solution should look something like this:

    #include <stdio.h>
    #include <X11/XKBlib.h>
    
    int main() {
        Display* _display;
        char* displayName = "";
        _display = XOpenDisplay(displayName);
    
        XkbDescRec* _kbdDescPtr = XkbAllocKeyboard();
        XkbGetNames(_display, XkbSymbolsNameMask, _kbdDescPtr);
        Atom symName = _kbdDescPtr -> names -> symbols;
        char* layoutString = XGetAtomName(_display, symName);
    
        XCloseDisplay(_display);
        printf("%s\n", layoutString);
    }
    

    Compile with -lX11 flag

    This will print something like pc+us+inet(evdev) for English (USA) qwerty layout, pc+ru+us:2+inet(evdev) for Russian йцукен layout, pc+us(dvorak)+us:2+inet(evdev) for English dvorak layout.

    0 讨论(0)
  • 2020-12-17 06:05

    I found one good solution. It's a c++ class wrriten by Jay Bromley, that I can add to my app and using it.

    source code

    It's very easy to use:

    #include "XKeyboard.h"
    
    XKeyboard xkb;
    
    std::string cGrpName=xkb.currentGroupName(); //return somethings like "USA"
    std::string cGrpSymb=xkb.currentGroupSymbol(); //return somethings like "us"
    
    xkb.setGroupByNum(0);//set keyboard layout to first layout in available ones
    

    you can read source code and found some another useful functions. for compiling standalone version you need to un-comments "int main" function present in "XKeyboard.cpp" (or write your own main.cpp) and use somethings like this:

    g++ *.cpp -o getxkblayout -L/usr/lib -lX11
    
    0 讨论(0)
  • 2020-12-17 06:09

    Yesterday I was trying to make auto layuout switcher to EN for Google's xsecurelock. I tryed to find some existing solutions for X11 api, but...

    So I decided to write my own with some help from S. Razi. Here is the code: (run with gcc -lX11)

    #include <stdio.h>
    #include <stdlib.h>
    #include <X11/XKBlib.h>
    
    int main(){
    
    Display* _display;
    char* displayName = "";
    _display = XOpenDisplay(displayName);
    
    int _deviceId = XkbUseCoreKbd;
    int i = 0;
    int _groupCount = 0;
    
    XkbDescRec* kbdDescPtr = XkbAllocKeyboard();
    if (kbdDescPtr == NULL) {
    printf("%s\n", "Failed to get keyboard description."); 
    return False;
    }
    
    kbdDescPtr->dpy = _display;
    if (_deviceId != XkbUseCoreKbd) {
        kbdDescPtr->device_spec = _deviceId;
    }
    
    XkbGetControls(_display, XkbAllControlsMask, kbdDescPtr);
    XkbGetNames(_display, XkbSymbolsNameMask, kbdDescPtr);
    XkbGetNames(_display, XkbGroupNamesMask, kbdDescPtr);
    
             /* count groups */
    
    Atom* groupSource = kbdDescPtr->names->groups;
    if (kbdDescPtr->ctrls != NULL) {
        _groupCount = kbdDescPtr->ctrls->num_groups;
    } else {
        _groupCount = 0;
        while (_groupCount < XkbNumKbdGroups &&
               groupSource[_groupCount] != 0) {
            _groupCount++;
        }
    }
    
            /* get group names */
    Atom* tmpGroupSource = kbdDescPtr->names->groups;
    Atom curGroupAtom;
    char* groupName;
    for (i = 0; i < _groupCount; i++) {
        if ((curGroupAtom = tmpGroupSource[i]) != None) {
            char* groupNameC = XGetAtomName(_display, curGroupAtom);
                if (groupNameC == NULL) {
                continue;
    
            } else {
                groupName =  groupNameC;
                char *temp = "English";
    
                if (strncmp(temp, groupName, 7) == 0){
                    printf ("%s\n", groupName);
                    printf ("%d\n", i);
                    XkbLockGroup(_display, _deviceId, i);
                    XFree(groupNameC);
                    XCloseDisplay(_display);
                }
                return 0;
            }
        } 
    }
    }
    

    Here you can change char* temp = "English" to name of the group of your layout (exmp: "Russian"), and this simple code will switch your current layout :)

    0 讨论(0)
  • 2020-12-17 06:12

    I'm not sure what the X11 library function is but setxkbmap is the bash command I use to achieve it. Maybe searching along these lines will find what you want (or at a pinch you could just execute the bash command).

    Example

    setxkbmap dvorak
    setxkbmap us
    

    EDIT: After a strace of setxkbmap didn't turn up anything useful I suggest just calling:

    system(“setxkbmap us”);
    
    0 讨论(0)
提交回复
热议问题