最近我把主要的工作环境转移到了Windows系统。之前 Windows 最困扰我的是 Shift + Space 的快捷键。在中文输入法状态下稍微打字快一点,就会误触发切换半角全角的功能,打乱输入的节奏。既然我决定长期使用 Windows 系统,就花了一些时间全面解决了这个问题。

TL;DR

安装 AutoHotkey v2 版。将以下代码加入到一个 .ahk 为后缀的文件中,比如“文档”目录中的 main.ahk 文件:

<+Space::Send (A_PriorKey = "LShift" ? "+{Space}" : "{Blind}{Shift up}{Space}{Shift down}{LWin}")  
>+Space::Send (A_PriorKey = "RShift" ? "+{Space}" : "{Blind}{Shift up}{Space}{Shift down}{LWin}")

双击文件 main.ahk 即可生效,如果要启动时自动生效,可以为这个文件创建一个快捷方式,然后将快捷方式移到到“启动”目录中。可以通过以下办法快速打开“启动”目录。

  • 使用快捷键 Win + r 打开运行窗口
  • 输入 shell:startup 并使用 Enter 确认

思路说明

Shift + Space 烦人的地方在于它会吞掉本想输入的空格。输入需要 Shift 组合键的符号时,通常在前或者在后要加上空格,比如 :(){} 这些符号。如果输入速度很快,很可能会在 Shift 尚未完全松开时按下 Space ,这时候没有输入空格反而是切换了半角全角,如果当前需要使用半角,还得再按一次切换回来。

基于上述分析,我想实现在按下 Shift 键后,如果在按下空格键之前按下了其他键,便视为 Shift 键没有及时松开,应该输入一个空格符号。如果在按下 Shift 键后立即按下空格键,应保留原来的半角全角切换功能。这样的配置不但能避免误触发,还可以被利用来快速输入 ) { 这样的序列,因为全程 Shift 不用松开了。

上面的 AutoHotkey 代码即实现了这里描述的功能。

代码说明

代码有两行,分别对应的左右手 Shift 触发的情况。我尝试过合并成一条但失败了,具体原因我也不清楚,也不知道为什么分开就能工作了。

下面以左手的第一行为例说明:

<+Space::Send (A_PriorKey = "LShift" ? "+{Space}" : "{Blind}{Shift up}{Space}{Shift down}{LWin}")
AutoHotkey 代码说明
<+Space::Shift + Space 设置命令,并只有使用左手的 Shift 才能触发。
Send发送指定的按键序列。
(A_PriorKey = "LShift" ? X : Y)如果变量 A_PriorKey 的值等于 LShift 时返回 X 否则返回 Y。
+{Space}发送组合按键 Shift + Space 以触发其原本的功能,即切换半角全角。
{Blind}{Shift up}{Space}{Shift down}{LWin}这么一大串其实只是为了实现在 AutoHotkey 里在 Shfit 按下的情况下输入一个空格符号。

第一个比较重要的点是自动变量 A_PriorHotkey。它记录的是组合键所有键被按下之前上一个按键状态有变化的键。因为组合键最后一个按下的一定是非修饰键,所以如果按下 Shift 后立即按下 SpaceA_PriorHotkey 就是 LShift 或者 RShift。相反,如果 A_PriorHotkey 等于其它值就表示按下 Shift 到按下 Space 之间有按过其它按键。

第二个点是用来模拟输入空格的一长串 {Blind}{Shift up}{Space}{Shift down}{LWin}

  • {Blind} 的作用是让 {Shift up} 强制修改 Shift 的状态改为松开保证后面 {Space} 输入一个空格符号。
  • {Shift down} 是恢复 Shift 按下的状态,这样后面可以继续输入还 Shift 的组合键。
  • {LWin} 不会触发任何操作。它的作用是如果在中文输入法里启用了点按 Shift 来切换中英文,在下面的按键序列中会正确输入 : (冒号+空格) 并且不会误触发中英文切换:
    • 按下 Shift
    • 按下 :
    • 松开 :
    • 按下 Space
    • 松开 Space
    • 松开 Shift