使用 AutoHotKey(或其他工具)创建自定义键盘布局

Create custom keyboard layout with AutoHotKey (or something else)

我想创建一个自定义键盘布局,主要用于键入 unicode 数学符号。我需要的符号集非常多,我想出的方案涉及多种布局和特殊组合。

我键入 `(反引号)一次,但我得到了一个特殊字符,我们将用 * 表示它。通过键入额外的键,我可以获得与特定主题相关的特定键盘布局。 (我想用一个特殊符号替换反勾,这样我就记得它是某种控制代码。通过输入两次,我得到一个正常的反勾)

下面是一些示例映射:

*s -> Set theory layout:
    [ -> ∈ (element of)
    o -> ∅ (empty set)

*r -> General math:
    s -> ∫ (integral sign)
    S -> ∬ (double integral sign)

*e -> Misc operators:
    8 -> ∗ (convolution asterisk)
    * -> ⋆ (star operator)

*g -> Greek alphabet

输入一个字符后,例如=,我可以输入一些其他的特殊组合来修饰那个字符。例如:

*x -> Negates the previous character:
    = -> ≠ (unequal)
    ≡ -> ≢ (negation of three line equality)

*w -> Expands the previous character:
    ∫ -> ∭ (triple integral)
    ∬ -> ⨌ (quad integral)

映射是助记的。我可以想象将所有我想要的符号塞进一个布局中,但它无法使用,所以我想尝试坚持这个方案或类似的方案。

键盘是针对Windows环境的,但我自己写键盘DLL是没有问题的。我调查了一下,它太复杂了。

现在,我正在寻找 AHK 的解决方案。可以在 AHK(或类似的东西)中完成吗?如果是这样,你能给我一些例子让我开始吗?

我也想知道是否有其他方法可以做到这一点

我知道 Microsoft Keyboard Layout Creator,过去也使用过它,但它的功能还不够强大。我也知道 Tavultesoft 的 Keyman,我知道它确实可以做我想做的事,但它贵得离谱,所以不是一个选择。

你所需要的,AutoHotkey 绝对可以做到。

棘手的部分是:您需要分配热键和 Hotstrings dynamically. The former is possible with the Hotkey-command,后者尚未实现,而且可能永远不会实现。 您可以将它们写入新的 .ahk 文件并单独执行该脚本,或者使用 polyethene's really awesome dynamical regEx hotstring creator. autohotkey.net's repository has been down for years, but I found the script here。 要获得以下示例脚本 运行,您需要将该脚本下载到 Hotstrings.ahk 并将其放在主 .ahk 文件所在的同一目录中。

但是,我无法将布局更改器热键分配给

`

,所以我设置为ä

我知道这个网站不是代码提供者网络,但我也对这个问题很感兴趣。

#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
#include Hotstrings.ahk

lastKey := ""

; KEYS OF THE NORMAL LAYOUT WHICH SHOULD BE NEGATABLE:
hotstrings("=", "_equals")  ;

; CHOOSE LAYOUT OR NEGATE/EXPAND LAST CHARACTER:
:*?:ä::
; backSpacePressed:  ; wtf is this? sorry just saw this now. Does not belong here, does not belong anywhere
    sendRaw *
    tooltip, 
    (
    n   normal layout

    s   set theory
    r   general math

    x   negate previous
    w   expand previous

    {esc}   cancel
    ), %A_CaretX%, %A_CaretY%
    input, layout, L1, {Escape}, s,r,e,g,x,w
    send {Backspace}    ; remove the *
    if layout in n,s,r,e,g,x,w
    {
        tooltip, %layout%, %A_CaretX%, %A_CaretY%

        ; RESET
        if layout = n
        {
            reset_all_hotstrings()

            ; KEYS OF THE NORMAL LAYOUT WHICH SHOULD BE NEGATABLE:
            hotstrings("=", "_equals")
        }



        ; NEW LAYOUT
        else if layout = s
        {
            reset_all_hotstrings()

            ; SET THEORY SHORTCUTS
            hotstrings("o", "_emptySet")
            hotstrings("\[", "_elementOf")
        }
        else if layout = r
        {
            reset_all_hotstrings()

            ; MATH SHORTCUTS
            hotstrings("s", "_integral")
            hotstrings("S", "_doubleIntegral")
            hotstrings("=", "_identical")
        }
        ; and so on
        ; ...



        ; EDIT PREVIOUS CHARACTER
        else if layout = x
        {
            send {backSpace}

            if lastKey = identical
                sendUnicodeChar(0x2262)
            else if lastKey = equals
                sendUnicodeChar(0x2260)
        }
        ; EXPAND PREVIOUS CHARACTER
        else if layout = w
        {
            send {backSpace}

            if lastKey = integral
                sendUnicodeChar(0x222D)
            else if lastKey = doubleIntegral
                sendUnicodeChar(0x2A0C)
        }
    }
    else
    {
        tooltip, cancelled, %A_CaretX%, %A_CaretY%
    }
    sleep, 500
    tooltip
return

reset_all_hotstrings() {
    hotstrings("=")
    hotstrings("\[")
    hotstrings("o")
    hotstrings("s")
    hotstrings("S")
    ; and so on
}

; NORMAL LAYOUT SHORTCUTS:
_equals:
    sendUnicodeChar(0x003D)
    lastKey = equals
return



; SPECIAL LAYOUT SHORTCUTS:
_emptySet:
    ;sendUnicodeChar(0x00D8)
    altNumpad(0216)
        ; to find out numpad combination or unicode: press WIN+R, type in "charmap"
        ; or for unicode only, go to http://www.fileformat.info/info/unicode/category/index.htm
        ; (sendUnicodChar() needs 0x before the unicode string)
    ;altNumpad(0248)
    ;send Ø
    ;send ø
    ;   choose whatever works best for you
    lastKey = emptySet
return

_elementOf:
    sendUnicodeChar(0x2208)
    lastKey = elementOf
return

_integral:
    sendUnicodeChar(0x222B)
    lastKey = integral
return

_identical:
    sendUnicodeChar(0x2261)
    lastKey = identical
return

_doubleIntegral:
    sendUnicodeChar(0x222C)
    lastKey = doubleIntegral
return

; -------------------------------------------

altNumpad(numbers) {
    stringSplit, n, numbers
    setkeydelay, 100
    send {alt down}
    loop, %n0%
    {
        t := n%a_index%
        send {numpad%t%}
    }
    send {alt up}
}


SendUnicodeChar(charCode)
{
    VarSetCapacity(ki, 28 * 2, 0)
    EncodeInteger(&ki + 0, 1)
    EncodeInteger(&ki + 6, charCode)
    EncodeInteger(&ki + 8, 4)
    EncodeInteger(&ki +28, 1)
    EncodeInteger(&ki +34, charCode)
    EncodeInteger(&ki +36, 4|2)

    DllCall("SendInput", "UInt", 2, "UInt", &ki, "Int", 28)
}

EncodeInteger(ref, val)
{
    DllCall("ntdll\RtlFillMemoryUlong", "Uint", ref, "Uint", 4, "Uint", val)
}

^e::reload

显然还有很大的改进空间