为 Linux 设置与 macOS 一致的开发体验:键盘设置

发布时间:2018-12-08
浏览次数:1087次

引言

  穿过最后一朵云,云宝的前面就是空旷的蓝天,整个天空,一片湛蓝。没有什么可以阻挡我啦,她双翅一振,声波以同心圆的方式向四周传出、一道巨大的美丽彩虹出现在天空中。

  彩虹音爆!哈哈~,今天发明的新工具,值得庆贺。

  云宝一个高空急转弯、俯冲下去,那里是悦勤办公室,紫悦她们正在那里忙着呢。

  “嗨,紫悦,看看我这个新工具,我们不是正好开设了新板块:白科技园地 Ruby Nice 吗?要不把这个新工具的介绍文字,放到这个板块中?” 云宝飘到紫悦身边,还拿出了一片文章。

  紫悦也很激动,为好朋友的新工具而开心:“好啊,让我先看看。” ,果然这是一篇抽丝剥茧、徐徐道来的文章。“不过,我有些担心,这个工具有极客范的、适合有些编程基础、还喜欢折腾的同学看吧?内容比较进阶,白科技园地一开始就这么发布吗?”,紫悦说出了自己的疑问。碧琪在一边,却信心十足:“聊一下技术吧,有的读者就是喜欢硬菜呢。”

  “别犹豫了,紫悦,让我来吧”,云宝展开这篇文章,开始了演讲。

起因

  当我离开小马谷来到上海后、很快就喜欢上了这里的电子产品、从电脑到手机、一口气买了好多。最近,看到了锤子科技发布的 TNT 系统,其中有一个细节,引起了我的兴趣:你瞧,它有一个 mac 风格还是 pc 风格的按键选项:

tnt_mac_win

  如果用户选择了 macOS 风格,那么使用空格左边的按键(alt 或 command),配合 c v w t 可以实现复制,粘贴,关闭tab, 新建tab 等操作啦(当然仅限于锤子自家的 app)。

  我尝试了一下,突然冒出了一个想法:既然锤子的 TNT 系统是在安卓系统上改的,安卓又是基于 Linux 系统的一个变形,那么在 Linux 系统上,也应该可以按照类似的思路,使用 macOS 风格的快捷键啦?这个想法,让我决定试试看、正好把有关键盘配置的片段知识串起来:

基础说明

  首先,我们比较 Mac 和 Linux(PC) 的键盘,看看有什么异同:

pc-mac-keyboard

  可以看到,按键数量是一样的,不过布局有点不同,为了下文能被正确理解,我们要先理清一些概念。说到这里,云宝展开了查阅的笔记:是李杀先生的解释,紫悦赶快进行了翻译。

To work with keys in Linux X11, you must understand {scancode, keycode, keysym} because many key tools use their concept and syntax.
在Linux X11应用中,我们需要了解 scancode, keycode, keysym 三个概念,因为很多按键方面的工具,都用到这三个概念。
 
Scancode → a number your keyboard send to computer. For USB keyboards, it's defined by the USB standard.
Scancode → 键盘传给计算机的编码,在USB键盘中、按照USB的标准进行定义。
 
Keycode → a number used by Linux kernel to represent key (or mouse button/wheel). The Linux kernel translate scancode to keycode.
Keycode → Linux内核中代表按键的编码(也包括鼠标按钮/滚轮),Linux内核,进行Scancode 向 Keycode 的转换。
 
Keysym → a short string (usually descriptive) that are received by X11 applications.

Keysym → X11 应用接收到了字符串(通常是简单的表述)

  好啦,为了表述方便,我喜欢采用表格的方式。说完,云宝就列出了一个表格:

键帽字符 实际按键 应用接收到的按键
control control control

  Scancode 是最底层,相当一个按键的唯一标识,Keycode 是 Linux 内核层面的抽象,而 Keysym 就是 X11 应用层的抽象了(没想到吧,小小一个键盘的传输过程,也有 TCP/IP 七层模型的一半了)。 因此,在讨论快捷键的时候,具体执行什么功能,很大程度上是由 GUI 层进行配置的。 对于macOS (包括 Windows) , 它的 GUI 是和系统紧密集合的,所以有着一致的操作,但是对 Linux 来说是分离的,它有着 Gnome, KDE 之类的桌面环境。

  现在,网上有大量的 macOS 主题的 Linux 或者 Windows 的主题,如果完全不涉及按键的使用配置,那么这样的主题就徒有其表、没有灵魂的。想到这些,云宝不由地发表了一下感叹。

  好吧,继续!我们选用 Linux 的 GTK (Gnome 使用的主要 GUI toolkit) 进行下面的步骤。云宝一边说着,一边打开了火狐游览器:

开始实战

  同样,先列个表格,对比清楚火狐游览器,在 macOS,Linux 中的快捷键:

按键 在 mac 下的功能 在Linux下的功能
command + d 添加当前链接到收藏夹

control + d
添加当前链接到收藏夹

command + f 查找 control + f
查找
command + s 保存 control + s
保存
command + l 定位到地址栏 control + l
定位到地址栏
control + a 移动光标到地址栏开头  
control + b 在地址栏移动光标到后一个字符  
control + e 移动光标到地址栏结尾  
control + f 在地址栏移动光标到前一个字符  
control + p 在地址栏弹出的历史记录中向上移动  
control + n 在地址栏弹出的历史记录中向下移动  
command + p 打印 control + p
打印
command + n 新建浏览器窗口 control + n
新建浏览器窗口
command + c 复制 control + c
复制
command + v 粘贴 control + v
粘贴
command + 数字 切换 tab  
alt + 数字   切换 tab

  对比一下就可以发现,在 linux 下,除了切换 tab 用了一下 alt 之外,所有活都是 control 干的。 而 mac 这边,和应用本身的相关的快捷键都是 command 负责,而 control 负责的都是 emacs 风格的按键绑定。

  观察应用本身需要的按键,不难发现它们都是一样的,这样看来,只要把 Linux 下的 alt 改成 control, 就能大范围的适配 macOS 的键位了。

  可以使用 Xmodmap 来对换 alt 和 control 键。

  在 ~~/.Xmodmap~ 文件中

clear control
clear mod1
keycode 37 = Alt_L Meta_L
keycode 64 = Control_L
add control = Control_L Control_R
add mod1 = Alt_L Meta_L

  执行命令  xmodmap ~/.Xmodmap 后,键盘的按键效果如下:

键帽字符 实际按键 应用接收到的按键
alt control control
control alt alt

  这样一来,几乎所有的应用层的快捷键都可以通过用大拇指按一下空格左边的键来实现了,这下 macOS 和 Linux 的体验一致了(包括复制和粘贴)。 这里还稍微有点不同,本来 GTK 下的火狐,切换 tab 是用的 alt 加数字,但是 alt 被 remap 到 control 了,要想办法再挪回来。

  这里就要介绍两个小工具了: xbindkey 和 xvkbd。其中,xbindkey 是一个键盘映射工具,它可以把一个按键事件绑定到一个脚本。 xvkbd 是一个虚拟键盘应用,把它们两组合起来就可以把 alt+数字 和 control+数字 给关联起来了,看代码:

"xvkbd -no-jump-pointer -xsendevent -text '\A1'"
   Control+1

"xvkbd -no-jump-pointer -xsendevent -text '\A2'"
   Control+2

"xvkbd -no-jump-pointer -xsendevent -text '\A3'"
   Control+3
...

  这样一来,按下 control+ 1 实际发送的式 alt+1, 如果需要为不同的应用设置特殊的按键映射,那么可以改为调用 shell 脚本, 在脚本中判断当前的应用并发送不同的结果。 __注意__: 这样写非常容易出现无限循环的情况,并且不易察觉,可能有点危险,不建议过多使用这招,最终效果如下:

键帽字符 实际按键 应用接收到的按键
alt + 1 control+1 alt+1
alt + 2 control+2 alt+2

  嗯,到目前为止,一切都还不错。云宝顿了一顿,接着说:从现在开始、要绑定 emacs 按键啦,这可是一款很棒的编辑器哦,我的最爱,呵呵。

  首先,我们还是先用搜索引擎查查看。搜索一下 gtk emacs keybinding 之类的关键字,不难找到答案: gtk-key-theme. 执行下面的命令就可以一键切换 Gnome 环境为 Emacs 风格的按键绑定。 ~gsettings set org.gnome.desktop.interface gtk-key-theme ‘Emacs’~

  如果直接执行这行配置,那么,前面就白搞了。。。因为它还是绑定的 control 键啊。 因此需要做一些小 hack, 首先找到这个 theme 的配置文件,并复制一份到本地配置。 cp /usr/share/themes/Emacs/gtk-3.0/gtk-keys.css ~/.themes/theme_name/gtk-3.0/ 打开 home 目录下的配置,看到 key theme 的本质了吧,就是一个配置文件,依葫芦画瓢,修改下,把 control 都换成 alt. 最后执行 ~gsettings set org.gnome.desktop.interface gtk-key-theme ‘theme_name’~ ,这下 emacs keybinding 也搞定了。

  下面是真正的 Emacs 配置了,作为最具配置性的编辑器,只需要几行配置就能反转 ctrl 和 alt (一定要使用 emacs26, ubuntu 自带的 25 还没这个功能)

(set-keyboard-coding-system nil)
(setq x-ctrl-keysym 'alt)
(setq x-ctrl-keysym 'meta)
(setq x-alt-keysym 'ctrl)
(setq x-meta-keysym 'ctrl)

  好了,最后还有一个困难户,就是 terminal 了。Ubuntu 的 Gnome 环境默认 terminal 是 Gnome-terminal, 它的默认快捷键如下:

按键 功能
ctrl+c 中断
ctrl+shift+c 复制
ctrl+shift+v 粘贴

  在 terminal 中输入 ctrl+c 是发送中断信号的,所以复制的快捷键只好加上 shfit 了。 反观 macOS, control+c 负责中断,command + c 负责复制,互不干涉。 下面我们要做的就是把中断的快捷键改为 alt+c, 这个设置比较高级,不太会出现在 GUI 的配置窗口中, 不过只要输入 stty -a 就能看到很多熟悉的命令(比如 susp = ^Z 这个就是挂起了)。 可以使用 stty intr ^E 来把 control+e 改成中断命令。 那么问题来了,使用 stty 命令并不能修改 modifier (把 ctrl 改成 alt). 看来 terminal 写死了接收的是 control 键,那么只能 hack 一下了,Gnome-terminal 的自定义还不够强,我们来使用 xterm, 增加下面的配置:

XTerm.vt100.translations: #override \n\
    alt <key>C : string(0x03) \n\
    Ctrl <KeyPress> c: copy-selection(CLIPBOARD)\n
    Ctrl <KeyPress> v: insert-selection(CLIPBOARD)\n\

  0x03 就是 control 键,我们把 alt 绑定到了 0x03, 这样就实现了 alt+c 可以中断的功能了。

  现在的按键效果如下:

键帽字符 实际按键 应用接收到的按键
alt + c ctrl+c ctrl+c
alt + v ctrl+v ctrl+v
ctrl+c alt+c alt+c (中断)

总结

  好了,有了 terminal、editor 和 web browser,最最基本的开发环境就已经实现啦。云宝总结说:这个有着 macOS 风格快捷键的 Linux 系统, 体现了 Linux 系统强大的可配置性,小马们,希望这次修改按键配置的探险之旅,可以让你在 Linux系统中,舒适地使用 macOS 方式的按键,也体会到乐于探险的 Linux 系统极客精神哦。

本文故事根据真实案例改编,文中人物均为化名

推开育儿的新大门(三)
哇声觅知音

发布:2019-03-15
作者:子悦

推开育儿的新大门(一)
雨夜・壮行

发布:2019-02-22
作者:子悦

Ruby Nice
创意、美感、深情

发布:2018-11-12
作者:子悦

高效办公系统方案
审批和容错的平衡

发布:2018-11-12
作者:子悦

悦勤的品牌观

发布:2018-11-12
作者:子悦

推开育儿的新大门(三)
哇声觅知音

发布:2019-03-15
作者:子悦