Keyboard Layout
经过好长好长一段时间的犹豫,我终于下定决心,买下了心仪已久的 Surface Book
。
于是我也开始用起了,好多年没有正经使用的windows系统。与此同时,我也集齐了三大操作系统,linux,windows,macOS。其实我对Surface并没有抱有太大的期望,我仅仅只是把它当作一个极具生产力的平板。iPad除了玩游戏,还能做什么,至于所谓的iPad Pro,我也不是它的目标用户。虽然我不打算在Surface上写代码,但是也好歹需要装一个Emacs。于是问题也随之而来了——没有用的 Caps Lock
键。在macOS和linux系统我可以分别通过系统设置和gnome-tweak-tools或者xmodmap或者XKB,将 Caps Lock
和 Ctrl
互换。
那么如何修改windows的 Caps Lock
呢。上一次大规模使用windows的时候,我用修改注册表的方法,改了 Caps Lock
的行为,然而这种方法用过一次就忘记如何设置了,而且也不好打理,万一要改回来呢。注册表可不是个好东西啊。经过一番搜索,我找到了 SharpKeys
这个应用。虽然这个应用归根结底,还是写的注册表,然而有个简易的界面,还是让人比较安心的。
然而这种方法还是有个问题,当我插上我心爱的 HHKB
的时候,我心爱的 Ctrl
就变成了 Caps Lock
了。我并不想这个键位更改发生在我的 HHKB
上。
至于macOS,虽然我之前有一百个槽要吐,但是它总是在一些很奇怪的地方,做的格外用心。macOS的键盘设置可以分不同的键盘。比如内置的键盘,可以交换两个键位,而 HHKB
则什么都不做。
最后,今天的槽点来了。当我选定用 Emacs
作为我的人生伴侣的时候,我被日益难按的 Ctrl
键,折磨得死去活来。于是,我学会了改键。我最开始用的改键软件就是 xmodmap
。
xmodmap ~/.Xmodmap
~/.Xmodmap
的内容如下:
remove lock = Caps_Lock remove control = Control_L keysym Control_L = Caps_Lock keysym Caps_Lock = Control_L add lock = Caps_Lock add control = Control_L
正如 windows
的尴尬,=xmodmap ~/.Xmodmap= 会把所有的键盘的布局都更改。
在查阅了Archlinux wiki之后,我又发现了一个新命令 setxkbmap
。
setxkbmap -device 11 -option ctrl:swapcaps setxkbmap -device 15 -option ""
里面的11就是要修改键位的键盘的device id。通过 xinput
命令可以查看当前所有输入设备的信息。以下是这个命令在我的macbook pro上的输出。
⎡ Virtual core pointer id=2 [master pointer (3)] ⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)] ⎜ ↳ bcm5974 id=12 [slave pointer (2)] ⎜ ↳ Broadcom Corp. Bluetooth USB Host Controller id=14 [slave pointer (2)] ⎣ Virtual core keyboard id=3 [master keyboard (2)] ↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)] ↳ Power Button id=6 [slave keyboard (3)] ↳ Video Bus id=7 [slave keyboard (3)] ↳ Video Bus id=8 [slave keyboard (3)] ↳ Power Button id=9 [slave keyboard (3)] ↳ Sleep Button id=10 [slave keyboard (3)] ↳ Apple Inc. Apple Internal Keyboard / Trackpad id=11 [slave keyboard (3)] ↳ Broadcom Corp. Bluetooth USB Host Controller id=13 [slave keyboard (3)] ↳ Topre Corporation HHKB Professional id=15 [slave keyboard (3)]
然而,总不能每次插上键盘的时候,还要执行一下命令吧,这很不linux。当然我可以写个定时任务,检查是否插入了HHKB,然后设置键盘布局。
xorg.conf中有一个Section —— InputClass,专门用来设置输入设备。于是我在 /etc/X11/xorg.conf.d/00-keyboard.conf
,中加入了这些配置。然而,在 gnome 3.24
下死活不生效。
Section "InputClass" Identifier "system-keyboard" MatchIsKeyboard "on" Option "XkbLayout" "us" Option "XkbOptions" "ctrl:swapcaps" EndSection
Section "InputClass" Identifier "hhkb" MatchProduct "HHKB" Option "XkbLayout" "us" Option "XkbOptions" "," EndSection
推测是 gnome
,在启动 gnome-session
的时候,对键盘布局做了些手脚。网友们说是 gnome-settings-daemon
的手脚。
$ gsettings set org.gnome.settings-daemon.plugins.keyboard active false No such schema “org.gnome.settings-daemon.plugins.keyboard”
然而,gnome 3.24之后已经不能用这个命令了。
$ gsettings list-keys org.gnome.settings-daemon.plugins whitelisted-plugins $ gsettings describe org.gnome.settings-daemon.plugins whitelisted-plugins A list of strings representing the plugins that are allowed to be loaded (default: “all”). This is only evaluated on startup. $ gsettings get org.gnome.settings-daemon.plugins whitelisted-plugins ['all']
所以通过 gsettings get org.gnome.settings-daemon.plugins whitelisted-plugins
这个值,可以屏蔽 keyboard
插件。
gsettings set org.gnome.settings-daemon.plugins whitelisted-plugins "['a11y-keyboard', 'a11y-settings', 'clipboard', 'color', 'common', 'datetime', 'dummy', 'housekeeping', 'media-keys', 'mouse', 'orientation', 'power', 'print-notifications', 'rfkill', 'screensaver-proxy', 'sharing', 'smartcard', 'sound', 'wacom', 'xrandr', 'xsettings']"
然而并没有什么卵用。
既然是开源,就去查 gnome-settings-daemon
的源代码。然而在读了源代码之后,我发现,这个 whitelisted-plugins
,根本就没有用到过。这个配置项,在 gnome-3.22
才是有用的。这不是坑爹吗。
那我自己把 gsd-keyboard
kill掉吧。
$ ps -ef | grep '[g]sd-keyboard' gdm 717 598 0 00:22 tty1 00:00:00 /usr/lib/gnome-settings-daemon/gsd-keyboard shane 14166 8246 0 07:22 tty2 00:00:00 /usr/lib/gnome-settings-daemon/gsd-keyboard
$ ps -ef | grep '[g]sd-keyboard' | grep `whoami` | awk '{print $2}' | xargs kill $ ps -ef | grep '[g]sd-keyboard' gdm 717 598 0 00:22 tty1 00:00:00 /usr/lib/gnome-settings-daemon/gsd-keyboard shane 14268 8246 0 07:25 tty2 00:00:00 /usr/lib/gnome-settings-daemon/gsd-keyboard
有守护啊。那我就这样。
ps -ef | grep '[g]sd-keyboard' | grep `whoami` | awk '{print $2}' | xargs kill -9
没想到 gnome-shell
退出了。 gsd-keyboard
应该是 gnome-settings-daemon
包中的一部分,让我来查查这个包里有什么。
$ pacman -Ql gnome-settings-daemon | grep '[kK]eyboard' gnome-settings-daemon /etc/xdg/autostart/org.gnome.SettingsDaemon.A11yKeyboard.desktop gnome-settings-daemon /etc/xdg/autostart/org.gnome.SettingsDaemon.Keyboard.desktop gnome-settings-daemon /usr/lib/gnome-settings-daemon/gsd-a11y-keyboard gnome-settings-daemon /usr/lib/gnome-settings-daemon/gsd-keyboard
自动启动, 那就把 org.gnome.SettingsDaemon.Keyboard.desktop
移动到别的地方去。
sudo mv /etc/xdg/autostart/org.gnome.SettingsDaemon.A11yKeyboard.desktop ~/Desktop
然后还是启动不了。原来 gnome-session
依赖于 gsd-keyboard
,修改 gnome-session
把这个依赖去掉。
$ sudo vim /usr/share/gnome-session/sessions/gnome.session [sudo] password for shane: Name[zh_CN]=GNOME Name[zh_HK]=GNOME Name[zh_TW]=GNOME RequiredComponents=org.gnome.Shell;org.gnome.SettingsDaemon.A11yKeyboard;org.gnome.SettingsDaemon.A11ySettings;org.gnome.SettingsDaemon.Clipboard;org.gnome.SettingsDaemon.Color;org.gnome.SettingsDaemon.Datetime;org.gnome.SettingsDaemon.Housekeeping;org.gnome.SettingsDaemon.MediaKeys;org.gnome.SettingsDaemon.Mouse;org.gnome.SettingsDaemon.Orientation;org.gnome.SettingsDaemon.Power;org.gnome.SettingsDaemon.PrintNotifications;org.gnome.SettingsDaemon.Rfkill;org.gnome.SettingsDaemon.ScreensaverProxy;org.gnome.SettingsDaemon.Sharing;org.gnome.SettingsDaemon.Smartcard;org.gnome.SettingsDaemon.Sound;org.gnome.SettingsDaemon.Wacom;org.gnome.SettingsDaemon.XRANDR;org.gnome.SettingsDaemon.XSettings;
然后 gnome-session
正常启动了,HHKB插上去,键位还是变了。我有点懵逼了。我决定尝试使用其他桌面环境—— awesome 和 KDE。实验的结果是:awesome完全遵照了,xorg里面的设置,没有修改HHKB的键位;而KDE的行为和gnome的一样。所以肯定是gnome做了些手脚。我把矛头指向了 gnome-shell
。
修改了 gnome-shell
中关于键盘的代码:
diff --git a/js/ui/status/keyboard.js b/js/ui/status/keyboard.js index d4b14d538..5796afd5e 100644 --- a/js/ui/status/keyboard.js +++ b/js/ui/status/keyboard.js @@ -266,7 +266,7 @@ const InputSourceSessionSettings = new Lang.Class({ _init: function() { this._settings = new Gio.Settings({ schema_id: this._DESKTOP_INPUT_SOURCES_SCHEMA }); this._settings.connect('changed::' + this._KEY_INPUT_SOURCES, Lang.bind(this, this._emitInputSourcesChanged)); - this._settings.connect('changed::' + this._KEY_KEYBOARD_OPTIONS, Lang.bind(this, this._emitKeyboardOptionsChanged)); + // this._settings.connect('changed::' + this._KEY_KEYBOARD_OPTIONS, Lang.bind(this, this._emitKeyboardOptionsChanged)); this._settings.connect('changed::' + this._KEY_PER_WINDOW, Lang.bind(this, this._emitPerWindowChanged)); },
keyboard.js
注释掉269行,从字面上看,这行代码应该注册了一个事件。当 _KEY_KEYBOARD_OPTIONS
发生变化时,执行 this._emitKeyboardOptionsChanged
,这样可以防止 org.gnome.desktop.input-sources xkb-options
变化时,设置键盘布局。
diff --git a/js/misc/keyboardManager.js b/js/misc/keyboardManager.js index 95afb4a8c..129e5bbe9 100644 --- a/js/misc/keyboardManager.js +++ b/js/misc/keyboardManager.js @@ -65,27 +65,27 @@ const KeyboardManager = new Lang.Class({ }, apply: function(id) { - let info = this._layoutInfos[id]; - if (!info) - return; - - if (this._current && this._current.group == info.group) { - if (this._current.groupIndex != info.groupIndex) - this._applyLayoutGroupIndex(info.groupIndex); - } else { - this._applyLayoutGroup(info.group); - this._applyLayoutGroupIndex(info.groupIndex); - } - - this._current = info; + // let info = this._layoutInfos[id]; + // if (!info) + // return; + + // if (this._current && this._current.group == info.group) { + // if (this._current.groupIndex != info.groupIndex) + // this._applyLayoutGroupIndex(info.groupIndex); + // } else { + // this._applyLayoutGroup(info.group); + // this._applyLayoutGroupIndex(info.groupIndex); + // } + + // this._current = info; }, reapply: function() { - if (!this._current) - return; + // if (!this._current) + // return; - this._applyLayoutGroup(this._current.group); - this._applyLayoutGroupIndex(this._current.groupIndex); + // this._applyLayoutGroup(this._current.group); + // this._applyLayoutGroupIndex(this._current.groupIndex); }, setUserLayouts: function(ids) {
keyboardManager.js
文件中注释掉 apply
和 reapply
方法,让设置键盘布局的方法失效。
重新打包安装 gnome-shell
,插上HHKB,终于成功了,键盘没有被改。macbook内置的键盘也保持了 Caps Lock
和 Ctrl
交换。但还是有一点瑕疵,如果键盘是跟着 gnome-shell
启动话,布局还是会被修改,但是只要拔下再插上就好了。