You are not logged in.

#1 2024-11-09 10:28:53

sgp
Member
Registered: 2023-06-02
Posts: 19

Multiple layout switching hotkeys

I have a total of 4 keyboard layouts: us, ru, jp(hiragana), jp(katakana), that can be switched with Ctrl+Space hotkey:

setxkbmap -layout us,ru,jp_custom,jp_custom -variant workman,,hiragana,katakana -option grp:ctrl_space_toggle

Because of the JP layouts, switch from RU -> US requires pressing Ctrl+Space 3 times which can be really annoying sometimes, considering I rarely use JP layouts.
I wonder if I can set a distinct hotkeys for switching between RU, US and JP layouts accordingly, i.e. Ctrl+Space for US-RU and Alt+Shift for JP?  Can it be achieved with XKB only?

Offline

#2 2024-11-09 15:59:19

seth
Member
Registered: 2012-09-03
Posts: 58,659

Re: Multiple layout switching hotkeys

Use "xdotool key ISO_First_Group" or "xdotool key ISO_Last_Group" to move to a defined point and then a sequence of "xdotool key ISO_Next_Group" or "xdotool key ISO_Prev_Group" to get to the desired position.

Offline

#3 2024-11-15 16:04:24

sgp
Member
Registered: 2023-06-02
Posts: 19

Re: Multiple layout switching hotkeys

Though `xev` recognizes ISO_Next_Group (and all other ISO_..._Group) press generated with `xdotool`, it's not changing the keyboard layout.

KeyPress event, serial 29, synthetic NO, window 0x3600001,
    root 0x1db, subw 0x0, time 17571611, (443,920), root:(1727,928),
    state 0x1, keycode 64 (keysym 0xfe08, ISO_Next_Group), same_screen YES,
    XKeysymToKeycode returns keycode: 50
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyRelease event, serial 29, synthetic NO, window 0x3600001,
    root 0x1db, subw 0x0, time 17571618, (443,920), root:(1727,928),
    state 0x1, keycode 50 (keysym 0xffe1, Shift_L), same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyRelease event, serial 29, synthetic NO, window 0x3600001,
    root 0x1db, subw 0x0, time 17571618, (443,920), root:(1727,928),
    state 0x0, keycode 64 (keysym 0xffe9, Alt_L), same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False

It appears that the ISO_Next_Group triggers Shift+Alt combination. Do I need to change the XKB configuration to make ISO_Next_Group work?

Offline

#4 2024-11-15 16:26:46

seth
Member
Registered: 2012-09-03
Posts: 58,659

Re: Multiple layout switching hotkeys

setxkbmap -print -query

Sanity check: this isn't a wayland session, is it?

Offline

#5 2024-11-17 15:21:33

sgp
Member
Registered: 2023-06-02
Posts: 19

Re: Multiple layout switching hotkeys

$ setxkbmap -print -query
xkb_keymap {
	xkb_keycodes  { include "evdev+aliases(qwerty)"	};
	xkb_types     { include "complete"	};
	xkb_compat    { include "complete"	};
	xkb_symbols   { include "pc+us(workman)+ru:2+jp_custom(hiragana):3+jp_custom(katakana):4+inet(evdev)+group(ctrl_space_toggle):1+group(ctrl_space_toggle):2+group(ctrl_space_toggle):3+group(ctrl_space_toggle):4"	};
	xkb_geometry  { include "pc(pc104)"	};
};
rules:      evdev
model:      workman,,hiragana,katakana
layout:     us,ru,jp_custom,jp_custom
variant:    workman,,hiragana,katakana
options:    grp:ctrl_space_toggle
seth wrote:

Sanity check: this isn't a wayland session, is it?

No, it isn't

Offline

#6 2024-11-17 15:48:18

seth
Member
Registered: 2012-09-03
Posts: 58,659

Re: Multiple layout switching hotkeys

So next to the clearly wrong release event you're also not getting any "MappingNotify event"?
But ctrl+space principally works?? Does it generate the same kind of events?

Try https://wiki.archlinux.org/title/Xorg/K … tion_files instead of setxkbmap.

Offline

#7 2024-11-18 20:18:01

sgp
Member
Registered: 2023-06-02
Posts: 19

Re: Multiple layout switching hotkeys

With 00-keyboard.conf instead of setxkbmap I get these (xdotool key ISO_Next_Group):

MappingNotify event, serial 28, synthetic NO, window 0x0,
    request MappingKeyboard, first_keycode 8, count 248

KeyPress event, serial 28, synthetic NO, window 0x3400001,
    root 0x1db, subw 0x0, time 16166647, (-786,714), root:(498,722),
    state 0x0, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyPress event, serial 28, synthetic NO, window 0x3400001,
    root 0x1db, subw 0x0, time 16166647, (-786,714), root:(498,722),
    state 0x4, keycode 65 (keysym 0x20, space), same_screen YES,
    XLookupString gives 1 bytes: (00) ""
    XmbLookupString gives 1 bytes: (00) ""
    XFilterEvent returns: False

KeyRelease event, serial 29, synthetic NO, window 0x3400001,
    root 0x1db, subw 0x0, time 16166653, (-786,714), root:(498,722),
    state 0x4, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyRelease event, serial 29, synthetic NO, window 0x3400001,
    root 0x1db, subw 0x0, time 16166653, (-786,714), root:(498,722),
    state 0x0, keycode 65 (keysym 0x20, space), same_screen YES,
    XLookupString gives 1 bytes: (20) " "
    XFilterEvent returns: False

I see that there are space keypresses instead of the ISO_Next_Group which appear when I press ctrl+space:

KeyPress event, serial 28, synthetic NO, window 0x3400001,
    root 0x1db, subw 0x0, time 16227486, (-383,859), root:(901,867),
    state 0x0, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyPress event, serial 28, synthetic NO, window 0x3400001,
    root 0x1db, subw 0x0, time 16227552, (-383,859), root:(901,867),
    state 0x4, keycode 65 (keysym 0xfe08, ISO_Next_Group), same_screen YES,
    XLookupString gives 0 bytes:
    XmbLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x3400001,
    root 0x1db, subw 0x0, time 16227640, (-383,859), root:(901,867),
    state 0x2004, keycode 65 (keysym 0xfe08, ISO_Next_Group), same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False

KeyRelease event, serial 28, synthetic NO, window 0x3400001,
    root 0x1db, subw 0x0, time 16227687, (-383,859), root:(901,867),
    state 0x2004, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
    XLookupString gives 0 bytes:
    XFilterEvent returns: False

Offline

#8 2024-11-18 21:57:05

seth
Member
Registered: 2012-09-03
Posts: 58,659

Re: Multiple layout switching hotkeys

Grrr…

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/XKBlib.h>

int main(int argc, char **argv) {
    
    if (argc != 2) {
        printf("Usage: %s list|<match>\nMatch is lazy, the first layout beginning with the token is chosen\n", argv[0]);
        return False;
    }

    Display* dpy = XOpenDisplay(NULL);


    XkbDescRec* kbdDescPtr = XkbAllocKeyboard();
    if (!kbdDescPtr) {
        printf("Failed to get keyboard description.\n"); 
        return False;
    }
    kbdDescPtr->dpy = dpy;

    int deviceId = XkbUseCoreKbd;
/*     if (deviceId != XkbUseCoreKbd) {
        kbdDescPtr->device_spec = deviceId;
    } */

    XkbGetControls(dpy, XkbAllControlsMask, kbdDescPtr);
    XkbGetNames(dpy, XkbSymbolsNameMask|XkbGroupNamesMask, kbdDescPtr);

    Atom* groupSource = kbdDescPtr->names->groups;
    int groupCount = 0;
    if (kbdDescPtr->ctrls) {
        groupCount = kbdDescPtr->ctrls->num_groups;
    } else {
        while (groupCount < XkbNumKbdGroups && groupSource[groupCount]) {
            ++groupCount;
        }
    }

    Atom* tmpGroupSource = kbdDescPtr->names->groups;
    Atom curGroupAtom;
    char* groupName;
    int printList = (strncmp(argv[1], "list", 4) == 0);
    for (int i = 0; i < groupCount; i++) {
        if ((curGroupAtom = tmpGroupSource[i]) != None) {
            groupName = XGetAtomName(dpy, curGroupAtom);
            if (!groupName) {
                continue;
            }
            if (printList) {
                printf("%s\n", groupName);
            } else if (strncmp(argv[1], groupName, strlen(argv[1])) == 0) {
                printf ("Setting %s\n", groupName);
//                printf ("%d\n", i);
                XkbLockGroup(dpy, deviceId, i);
                XFree(groupName);
                XCloseDisplay(dpy);
                return True;
            }
            XFree(groupName);
        } 
    }
    XCloseDisplay(dpy);
    return printList;
}
gcc -lX11 -o xkbgroup xkbgroup.c

Offline

Board footer

Powered by FluxBB