修正 Windows 中德語和俄語鍵盤佈局之間撤消 (Ctrl-Z) 和重做 (Ctrl-Y) 快捷鍵的實體位置

修正 Windows 中德語和俄語鍵盤佈局之間撤消 (Ctrl-Z) 和重做 (Ctrl-Y) 快捷鍵的實體位置

我正在模仿鍵盤佈局混亂的另一個受害者,它也遇到類似但略有不同的問題。

我在 Windows 10 工作站上廣泛使用德語和俄語鍵盤佈局,並經常在它們之間切換。這個問題與以下事實有關:與標準英語 QWERTY 佈局相比,德語鍵盤佈局中的字母 Y 和 Z 被交換。

如果我使用德語佈局,則「撤銷」快速鍵(Ctrl-Z) 會綁定到Z 鍵,該鍵位於T 和U 之間的第一個字母行的中間。會綁定到Y 鍵,位於德語 QWERTZ 佈局中低行字母 X 的左側。

如果你把佈局切換到俄語,就會突然發生一件邪惡的事。撤銷和重做快速鍵會互相更改其在鍵盤上的位置。撤銷 (Ctrl-Z) 現在位於 Y(下排,X 左側),重做位於 Z(上排,T 和 U 之間)。此位置與標準英文鍵盤佈局上 Ctrl-Z 和 Ctrl-Y 的位置相同。

這意味著每當我切換鍵盤佈局時,「撤消」和「重做」快捷鍵的位置就會更改為相反的位置。正如你可以想像的那樣,我總是按錯了捷徑,因為不可能學習兩種相反的振盪模式,至少我的脊椎大腦抗議。由於我經常使用「撤銷」和「重做」快捷鍵,這種行為讓我很惱火。

我想將整套 Windows 應用程式中“重做”和“撤消”快捷鍵的實體位置(鍵)修復為德語或更好​​的英語佈局。

對所有基於拉丁語的文本永久使用英語佈局雖然解決了跳轉撤消/重做快捷方式的問題,但這對我來說不是一個選擇,因為我需要輸入帶有所有元音變音和ß 的德語文字(不建議使用國際佈局輸入重音符號,因為德語是我的主要語言,我想透過一次按鍵輸入其母語字母)。

正如參考問題中的同事已經提到的,網路上沒有明顯的答案。 Ubuntu 上透過建立自訂鍵盤佈局解決了相同的問題。我找不到任何有關為 Windows 建立自訂佈局或修補當前佈局的資訊。

這種行為在我所知道的所有 Windows 版本中都是一致的,並且與最初的鍵盤佈局設計密切相關,這對於像我這樣碰巧使用德語-俄語對的用戶來說是不相容的。

好的解決方案應該直接在Windows中實現,無需任何附加軟體,或僅使用免費的開源軟體。歡迎涉及 AutoHotKey 的工作解決方案。

在 @miroxlav 的幫助下,我想出了這個半工作的 AHK 腳本:

; Undo
$^z::
    hWnd := WinExist("A")
    ThreadID := DllCall("GetWindowThreadProcessId", "UInt", hWnd, "UInt", 0)
    hKL := DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
    If (hKL = 0x4070409)   ; revert undo-redo hotkey mapping if in German layout
        Send ^y
    Else
        Send ^н            ; pass the keystroke through
Return

; Redo
$^y::
    hWnd := WinExist("A")
    ThreadID := DllCall("GetWindowThreadProcessId", "UInt", hWnd, "UInt", 0)
    hKL := DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
    If (hKL = 0x4070409)   ; revert undo-redo hotkey mapping if in German layout
        Send ^z
    Else
        Send ^я            ; pass the keystroke through
Return

這個腳本完美地重新映射了德語佈局上的 Ctrl-Y <-> Ctrl-Z,但破壞了俄語佈局上的兩個熱鍵。我使用 ^н 和 ^я 希望能夠模擬俄語佈局的 Ctrl-Y 或 Ctrl-Z 掃描程式碼等效項,但它不起作用(為 Ctrl-Y 生成 н,而為 Ctrl-Z 生成任何可見內容)。對俄語使用 ^z 和 ^y 也不起作用,分別產生字母 z 和 y。

與 Miroxlav 的答案不同,我必須使用鍵盤鉤子($)來避免循環並刪除標籤(可能是複製貼上錯誤)

威廉斯建議的解決方案:

^SC02c::Send ^y
^SC015::Send ^z

不幸的是也不起作用。它在俄語佈局上產生純字母“y”和“z”,而在德語佈局上沒有變化(Ctrl-Z 和 Ctrl-Y 在原始映射中傳遞)。

仍在尋找解決方案。

答案1

您可以簡單地使用以下命令創建自己的鍵盤佈局來自 Microsoft 官方下載中心的 Microsoft Keyboard Layout Creator 1.4

Youtube 提供了大量如何使用它的影片教學(例如與俄語語言環境) - 只需搜尋其名稱。但基本上,您可以克隆現有的鍵盤佈局之一併根據您的需求進行修改。

自動熱鍵解決方案:

(注意:將0x4090409常數(美國鍵盤)替換為適用於您的佈局的值)

$^z::
    hWnd := WinExist("A")
    ThreadID := DllCall("GetWindowThreadProcessId", "UInt", hWnd, "UInt", 0)
    hKL := DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
    If (hKL = 0x4090409)
        Send ^z
    Else
        Send ^y
Return

$^y::
    hWnd := WinExist("A")
    ThreadID := DllCall("GetWindowThreadProcessId", "UInt", hWnd, "UInt", 0)
    hKL := DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
    If (hKL = 0x4090409)
        Send ^y
    Else
        Send ^z
Return

需要 Hook ($) 來避免遞歸,即Send ^zSend ^y呼叫另一個 AHK 巨集。

我測試了鍵盤檢測條件,效果很好。

當然,您可以將鍵盤檢測放入函數中,從而優化程式碼等。 :)

答案2

我終於找到了一個適合我的工作解決方案(AutoHotKey 腳本):

; Undo Ctrl-Z
^sc02C::
    Send, ^{sc015}
Return

; Redo Ctrl-Y
^sc015::
    Send, ^{sc02C}
Return

它完美地將撤消鍵 (Ctrl-Z) 保留在其邏輯位置 - 左下行 - 獨立於鍵盤佈局。

感謝@Miroxlav 和@Williams 為解決方案帶來了一些內容。

答案3

根據 Anton 的回答,我已將程式碼更新為 AHK v2 並添加了對 Ctrl+Shift 變體的支持,因為許多程式現在都使用它來重做。

#Requires AutoHotkey v2.0

;Remapping upper mid Y/Z key (Y in EN layout)
^sc015::Send "^{sc02C}"
^+sc015::Send "^+{sc02C}"

;Remapping lower left Y/Z key (Z in EN layout)
^sc02C::Send "^{sc015}"
^+sc02C::Send "^+{sc015}"

該腳本的要點是將「撤消」操作修復為左下 Y/Z 鍵,因為不同的佈局(QWERTZ 與 QWERTY)會將 Z 移動到中上,這是不切實際的。重做也是如此,現在固定為中上 Y/Z 鍵。

由於撤消/重做通常透過 Ctrl+Z/Y 執行,因此可以透過捕捉按下的鍵並重新發出「正確」鍵來實現。這些就是^sc0**線條。這些^+sc0**行用於重新發出 Ctrl+Shift+Z/Y 事件,因為許多程式使用 Ctrl+Shift+Z 進行重做。

「正確」鍵用引號引起來,因為如果您查看腳本,它實際上應該只是在各處翻轉 Ctrl(+Shift)+Y/Z...因此什麼也沒實現。然而,事實並非如此,它只是起作用......儘管我和原作者都不知道為什麼。

如果您對為什麼這對您有用或對您不起作用有任何見解...請說出來

答案4

儘管接受的答案有效,但它僅在當時選定的佈局是德國佈局的情況下才有效,否則它會翻轉所有其他佈局中的撤消功能。

要解決這個問題,您只需將美國代碼替換0x4090409為德國代碼0x4070407。您也可以像這樣更改 if 語句:

$^z::
    hWnd := WinExist("A")
    ThreadID := DllCall("GetWindowThreadProcessId", "UInt", hWnd, "UInt", 0)
    hKL := DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
    If (hKL = 0x4070407)
        Send ^y
    Else
        Send ^z
Return

$^y::
    hWnd := WinExist("A")
    ThreadID := DllCall("GetWindowThreadProcessId", "UInt", hWnd, "UInt", 0)
    hKL := DllCall("GetKeyboardLayout", "UInt", ThreadID, "UInt")
    If (hKL = 0x4070407)
        Send ^z
    Else
        Send ^y
Return

相關內容