Featured image of post 当 Windows 键盘语言有三种或以上时,使用快捷键在其中两种语言输入法间切换

当 Windows 键盘语言有三种或以上时,使用快捷键在其中两种语言输入法间切换

提供了一个详细的指南,解释了如何在 Windows 操作系统中设置和使用键盘语言和输入法。介绍了两种方法来优化键盘语言切换的过程:一种是通过删除不常用的键盘语言来简化切换过程,另一种是使用 AutoHotKey 脚本来覆写 Windows+Space 快捷键,从而实现在两种常用键盘语言之间快速切换。

键盘语言 vs. 输入法

首先需要区分一下键盘语言和输入法的概念。对于 Windows 而言,一个键盘语言可以包括多个输入法。比如我们一般会使用的简体中文键盘就包括微软输入法、搜狗输入法等:

而英文键盘就是基础的「所按即所得」输入法,或者通俗理解成没有字形输入法。每种输入法都有自己适用的键盘语言,比如不能把搜狗输入法装在英文或繁体中文的键盘下,只能用于简体中文键盘(繁体中文键盘下一般只有注音输入法)。

对于简体中文用户来说,习惯上一般配置一种或两种键盘。以下是这两种配置习惯的区别:

  • 配置一个简体中文键盘:简体中文键盘 + 简体中文输入法(搜狗等)。这时候默认一开机就是中文输入法,如果需要输入英文可以按键盘上的 Shift 键来切换。但 Shift 键经常容易误触,而且在不同应用间的中文和英文无法做到统一,即中英模式是跟着应用走的,比如在文本编辑器里已经切成了英文模式,一回到浏览器窗口又自动变成了默认的中文模式。
  • 配置一个简体中文键盘和一个英语键盘:个人推荐这种做法。在这种情况下使用 Windows+Space 键或 Alt+Shift 键切换键盘,全局生效,而简体中文键盘中的中文输入法就一直保持中文模式就好了。

多种键盘语言切换的问题

但在一些情况下,可能需要配置多种键盘。比如为了把系统语言调成繁体中文就必须增加一个繁体中文键盘:

而繁中键盘自带一个微软注音输入法。Windows 默认会保证每个键盘语言至少有一种输入法,即使用不到也无法删掉。这时候切换输入法时,Windows+Space 按键就变成了在三种输入法中来回切换,让使用起来很麻烦。

如何让 Windows+Space 按键始终保持在两种常用键盘间切换就是本文要解决的问题。

方法一:删除多余的键盘

直接强行把繁体中文键盘中的注音输入法删掉,这样切换时就只在两种键盘间切换了。因为在这种情况下繁体中文键盘根本没有对应的输入法了。

可以使用以下 Powershell 脚本:

1
2
3
4
$LangList = Get-WinUserLanguageList # 获取当前用户的语言列表
$MarkedLang = $LangList | where LanguageTag -eq "zh-Hant-TW" # 在语言列表中查找语言标签为"zh-Hant-TW"的语言
$LangList.Remove($MarkedLang) # 从语言列表中移除该语言
Set-WinUserLanguageList $LangList -Force # 强制设置更新后的语言列表

将代码保存成ps1文件然后右键管理员运行即可。

来源:https://www.majorgeeks.com/content/page/how_to_remove_a_language_from_windows_10.html

方法二:使用 AutoHotKey 覆写快捷键

如果我们不想直接删除第三种语言的输入法怎么办呢?有时候第三种语言的输入法虽然不常用但也会偶尔用到,因此我们的需求只是在日常高频使用时方便即可。这时我们可以用 AutoHotKey 覆写 Windows+Space 快捷键,代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#Requires AutoHotkey v2.0

#Space::  ; 当按下Windows+Space时触发以下代码块
{
    currentLang := GetKeyboardLanguage()  ; 获取当前键盘语言
    if (currentLang = "1033")  ; 如果当前键盘语言是1033(英语)
    {
        PostMessage(0x50, 0, 0x0804,, "A")  ; 发送消息切换到0804(简体中文)
    }
    else  ; 如果当前键盘语言不是1033
    {
        PostMessage(0x50, 0, 0x0409,, "A")  ; 发送消息切换到0409(英语)
    }
    return  ; 结束这个热键的执行
}

GetKeyboardLanguage()  ; 定义一个函数,用于获取当前键盘语言
{
    ThreadID := DllCall("GetWindowThreadProcessId", "uint", WinExist("A"), "uint", 0)  ; 获取当前窗口的线程ID
    HKL := DllCall("GetKeyboardLayout", "uint", ThreadID)  ; 获取当前线程的键盘布局
    return HKL & 0xFFFF  ; 返回键盘布局的低位字,即键盘语言ID
}

以上脚本其实是用 GPT 帮我写的,因为本身完全没学过 ahk 编程。该脚本的作用是每次按下 Windows+Space 时检查一下当前的键盘语言:

  • 如果是英文键盘,切换到简体中文键盘;
  • 如果是简体中文键盘,切换到英文键盘;
  • 如果是其他语言的键盘,一律切换到英文键盘。

这样日常操作时就方便了。如果要久违地切到第三种乃至更多其他语言的键盘时,只需要用另一个键盘语言切换的快捷键 Alt+Shift 即可,或者用鼠标直接在语言栏点选也可以。

然而,在某些情况下,以上 GetKeyboardLanguage 方法可能在一些窗口下无法获取到键盘语言,如果遇到这种情况,干脆自己维护一个全局变量。以下是相关代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#Requires AutoHotkey v2.0

currentLang := 2 ; 改成电脑开机时的初始键盘,1为英文,2为中文

#Space::
{
    Global currentLang
    if (currentLang = 1)
    {
        PostMessage(0x50, 0, 0x0804,, "A") ; cn
        currentLang := 2
    }
    else
    {
        PostMessage(0x50, 0, 0x0409,, "A") ; en
        currentLang := 1
    }
    return
}

另外,还遇到一个问题,有个别应用程序被 PostMessage 时会崩溃,我采用的解决方案是切到其他窗口再进行 Post,以下是完整代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#Requires AutoHotkey v2.0

currentLang := 2

#Space::
{
    Global currentLang
    if (currentLang = 1){
        SetKeyboard(0x0804, 2) ; cn
    }else{
        SetKeyboard(0x0409, 1) ; en
    }
    return
}

SetKeyboard(langID, currentLangUpdate){
    Global currentLang
    if(not WinExist("A")){
        return
    }
    if(WinActive("ahk_exe Fork.exe")){ ; 会崩溃的应用程序
        ;Send("!{Tab}") ; 通过模拟按键 Alt + Tab 来切换
        AltTab() ; 直接调用函数进行切换,好处是不会短暂地显示切换窗口
        Sleep 300
        SetKeyboard(langID, currentLangUpdate)
        Sleep 300
        ;Send("!{Tab}")
        AltTab()
        return
    }
    PostMessage(0x50, 0, langID,, "A")
    currentLang := currentLangUpdate
}

AltTab(){
    ids := WinGetList(,, "Program Manager")
    for this_id in ids
    {
        if(WinActive("ahk_id " this_id)){
            continue
        }
        if(WinGetTitle("ahk_id " this_id) = ""){
            continue
        }
        If (!IsWindowVisible(this_id)) 
            continue
        WinActivate("ahk_id " this_id)
        break
    }
}

IsWindowVisible(id){
    static WS_VISIBLE := 0x10000000
    Style := WinGetStyle("ahk_id " id)
    if (Style & WS_VISIBLE)
        return 1
    return 0
}
Licensed under CC BY-NC-SA 4.0