xdotool、ctrl 键和键盘布局
xdotool, ctrl key and keyboard layouts
问题
我在我的应用程序中使用 xdotool keydown Control
和 xdotool keyup Control
来模拟 Ctrl 键。当布局设置为 us
时,一切正常,但当布局更改为其他内容(fr
或 ru
)时,应用程序将停止看到 ctrl 事件。
问题
为什么会这样?我该怎么做才能使 ctrl 键操作在布局中统一工作?
一些信息
我用来设置布局的命令:
setxkbmap -layout us,fr -option -option "grp:lctrl_lshift_toggle,ctrl:nocaps"
使用 us
布局的 xev 输出:
KeyPress event, serial 25, synthetic NO, window 0x4a00001,
root 0x5c, subw 0x0, time 11278564, (317,709), root:(1279,736),
state 0x10, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
KeyRelease event, serial 28, synthetic NO, window 0x4a00001,
root 0x5c, subw 0x0, time 11278676, (317,709), root:(1279,736),
state 0x14, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False
使用 fr
布局的 xev 输出:
KeyPress event, serial 109, synthetic NO, window 0x4a00001,
root 0x5c, subw 0x0, time 11343218, (312,520), root:(1274,547),
state 0x2010, keycode 8 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
KeyRelease event, serial 123, synthetic NO, window 0x4a00001,
root 0x5c, subw 0x0, time 11343460, (312,520), root:(1274,547),
state 0x2010, keycode 8 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
setxkbmap 的详细输出:
Setting verbose level to 10
locale is C
Applied rules from evdev:
rules: evdev
model: pc105
layout: us,fr
options: grp:lctrl_lshift_toggle,ctrl:nocaps
Trying to build keymap using the following components:
keycodes: evdev+aliases(qwerty)
types: complete
compat: complete
symbols: pc+us+fr:2+inet(evdev)+group(lctrl_lshift_toggle)+ctrl(nocaps)
geometry: pc(pc105)
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_symbols { include "pc+us+fr:2+inet(evdev)+group(lctrl_lshift_toggle)+ctrl(nocaps)" };
xkb_geometry { include "pc(pc105)" };
};
用于控制的 xmodmap 输出:
$ xmodmap -pme | grep -i control
control Control_L (0x25), Control_L (0x42), Control_R (0x69)
$ xmodmap -pke | grep -i control
keycode 37 = Control_L Control_L Control_L Control_L
keycode 66 = Control_L Control_L Control_L Control_L
keycode 105 = Control_R NoSymbol Control_R
正如您从 xev
输出中看到的那样,在 us 模式下 Control_L
按下键相当于键码 37,状态从 0x10 移动到
0x14,而在 fr 模式下,您的键码为 8,状态 0x2010 不是
更改和几个 MappingNotify 事件。
state 是当前应用修饰符的位图,例如 shift,
控制,Alt 等。它们可以显示为
xmodmap -pme
例如对我来说(在完全不同的键盘设置上)目前是
shift Shift_L (0x32), Shift_R (0x3e)
lock
control Control_L (0x25), Control_L (0x42), Control_R (0x69)
mod1 Meta_R (0x86)
mod2 Num_Lock (0x4d)
mod3
mod4
mod5 ISO_Level3_Shift (0x5c), Mode_switch (0xcb)
这些列出了 state 中的 8 位位置,其中:
- shift = 位 0(状态 0x1),
- lock = 位 1(状态 0x2),
- control = 位 2(状态 0x4)等
您的状态 0x2010 包括超过这 8 位的值 0x2000,这就是 2 个键映射合二为一的实现方式,并在您处于 fr 模式时显示。
如果我们看看 xdotool
是如何工作的,当您处于状态 0x2000 所示的第二个键映射时,它会查找 Control_L 以找到键码,然后在中查找键码当前状态的 xmodmap -pke
列,但未找到 Control_L。所以它取了一个备用的keycode 8,临时改变映射so keycode 8 = keysym Control_L,然后发送那个key event。不幸的是,此键码不在控制位的修饰符映射中。
因此,如果您更改键码 37 的映射,以便所有列都具有 Control_L,那么也许会起作用。我不知道你有多少列,但是做 xmodmap -pke | grep 'keycode 37'
并计算它们,然后将它们全部更改,例如:
xmodmap -e 'keycode 37 = Control_L Control_L Control_L Control_L'
如评论中所述,xdotool key
可以采用键码十进制数字而不是 keysym 参数。这在手册页中没有提到。
问题
我在我的应用程序中使用 xdotool keydown Control
和 xdotool keyup Control
来模拟 Ctrl 键。当布局设置为 us
时,一切正常,但当布局更改为其他内容(fr
或 ru
)时,应用程序将停止看到 ctrl 事件。
问题
为什么会这样?我该怎么做才能使 ctrl 键操作在布局中统一工作?
一些信息
我用来设置布局的命令:
setxkbmap -layout us,fr -option -option "grp:lctrl_lshift_toggle,ctrl:nocaps"
使用 us
布局的 xev 输出:
KeyPress event, serial 25, synthetic NO, window 0x4a00001,
root 0x5c, subw 0x0, time 11278564, (317,709), root:(1279,736),
state 0x10, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
KeyRelease event, serial 28, synthetic NO, window 0x4a00001,
root 0x5c, subw 0x0, time 11278676, (317,709), root:(1279,736),
state 0x14, keycode 37 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False
使用 fr
布局的 xev 输出:
KeyPress event, serial 109, synthetic NO, window 0x4a00001,
root 0x5c, subw 0x0, time 11343218, (312,520), root:(1274,547),
state 0x2010, keycode 8 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 109, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 116, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
KeyRelease event, serial 123, synthetic NO, window 0x4a00001,
root 0x5c, subw 0x0, time 11343460, (312,520), root:(1274,547),
state 0x2010, keycode 8 (keysym 0xffe3, Control_L), same_screen YES,
XLookupString gives 0 bytes:
XFilterEvent returns: False
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
MappingNotify event, serial 123, synthetic NO, window 0x0,
request MappingKeyboard, first_keycode 8, count 1
setxkbmap 的详细输出:
Setting verbose level to 10
locale is C
Applied rules from evdev:
rules: evdev
model: pc105
layout: us,fr
options: grp:lctrl_lshift_toggle,ctrl:nocaps
Trying to build keymap using the following components:
keycodes: evdev+aliases(qwerty)
types: complete
compat: complete
symbols: pc+us+fr:2+inet(evdev)+group(lctrl_lshift_toggle)+ctrl(nocaps)
geometry: pc(pc105)
xkb_keymap {
xkb_keycodes { include "evdev+aliases(qwerty)" };
xkb_types { include "complete" };
xkb_compat { include "complete" };
xkb_symbols { include "pc+us+fr:2+inet(evdev)+group(lctrl_lshift_toggle)+ctrl(nocaps)" };
xkb_geometry { include "pc(pc105)" };
};
用于控制的 xmodmap 输出:
$ xmodmap -pme | grep -i control
control Control_L (0x25), Control_L (0x42), Control_R (0x69)
$ xmodmap -pke | grep -i control
keycode 37 = Control_L Control_L Control_L Control_L
keycode 66 = Control_L Control_L Control_L Control_L
keycode 105 = Control_R NoSymbol Control_R
正如您从 xev
输出中看到的那样,在 us 模式下 Control_L
按下键相当于键码 37,状态从 0x10 移动到
0x14,而在 fr 模式下,您的键码为 8,状态 0x2010 不是
更改和几个 MappingNotify 事件。
state 是当前应用修饰符的位图,例如 shift, 控制,Alt 等。它们可以显示为
xmodmap -pme
例如对我来说(在完全不同的键盘设置上)目前是
shift Shift_L (0x32), Shift_R (0x3e)
lock
control Control_L (0x25), Control_L (0x42), Control_R (0x69)
mod1 Meta_R (0x86)
mod2 Num_Lock (0x4d)
mod3
mod4
mod5 ISO_Level3_Shift (0x5c), Mode_switch (0xcb)
这些列出了 state 中的 8 位位置,其中:
- shift = 位 0(状态 0x1),
- lock = 位 1(状态 0x2),
- control = 位 2(状态 0x4)等
您的状态 0x2010 包括超过这 8 位的值 0x2000,这就是 2 个键映射合二为一的实现方式,并在您处于 fr 模式时显示。
如果我们看看 xdotool
是如何工作的,当您处于状态 0x2000 所示的第二个键映射时,它会查找 Control_L 以找到键码,然后在中查找键码当前状态的 xmodmap -pke
列,但未找到 Control_L。所以它取了一个备用的keycode 8,临时改变映射so keycode 8 = keysym Control_L,然后发送那个key event。不幸的是,此键码不在控制位的修饰符映射中。
因此,如果您更改键码 37 的映射,以便所有列都具有 Control_L,那么也许会起作用。我不知道你有多少列,但是做 xmodmap -pke | grep 'keycode 37'
并计算它们,然后将它们全部更改,例如:
xmodmap -e 'keycode 37 = Control_L Control_L Control_L Control_L'
如评论中所述,xdotool key
可以采用键码十进制数字而不是 keysym 参数。这在手册页中没有提到。