[Mac] 用 Karabiner 讓美式鍵盤能正確在遠端的德式鍵盤上打字
最近公司的產品大概是賣得還不錯,相對應的客戶問題也變多了,
已經有好幾次要遠端連線,到客戶電腦去解決問題,
不過也因此遇到一個大麻煩:不同的鍵盤配置…
最常見到的就是西歐語系的客戶 (像德國鍵盤),我們遠端連線進去之後,
通常就是打開 terminal 開始要打指令,
然後就會發現 / 按下去不是 /、y 按下去不是 y,一整個爆炸…
舉例來說,假設我分別在 Mac 上打了下面這些字:
cd Windows [email protected] echo abc > abc.txt
結果 變成了 #,@ 變成了 “,> 也變成 : 了:
要解決這個問題,最簡單當然是請客戶切換成美式 (en_US) 的鍵盤,
這樣子我們打什麼就會出現什麼 (因為我們的通常也是美式鍵盤)~
但有時候這個請求可能會被拒絕 (不想改、或是沒有權限改),
這時候通常就只能用複製/貼上大法、或是叫出螢幕小鍵盤等等,頗為麻煩…
一直在想說有沒有什麼方法,
可以讓我送出的按鍵 scan code,是可以正確對應到遠端電腦的鍵盤配置的,
今天終於找到一個理念很接近的東西,那就是 Karabiner~
它可以重新定義 (remap) 鍵盤按下的每一個鍵,某種程度上可以達到我的需求,來看看怎麼做吧~
1. 安裝 Karabiner
下載 Karabiner 後安裝,安裝好之後第一次執行會需要給 Karabiner 相關的權限:
在 System Preferences > Security & Privacy > Accessibility > Privacy 這邊,
把 Karabiner_AXNotifier.app 加入,這樣它才能有足夠權限:
2. 設定 Karabiner:使用內建設定
執行 Karabiner 之後,可以看到如下的視窗,
基本上是一堆非常多的設定,主要的設定就是 Change Key 這個分頁:
像我們在剛剛的德國鍵盤裡面,可以注意到按下 y 會跑出 z,按下 z 會跑出 y,
這是因為他們用的是 QWERTZ 排列的鍵盤,跟我們常用的 QWERTY 是不一樣的。
如果只是要解決這個問題,Karabiner 已經有內建的設定可以搞定,
鍵入 swap y z 來搜尋符合的設定 (也可以一個個慢慢找,只是很累),
把 Change QWERTY to QWERTZ layout 勾起來:
這時候你只要打入 y,就會跑出 z 了,反之亦然,不過當然這不是為了給你這樣玩的,
而是像我遠端連線到德國人的電腦上時,勾了這個選項,
那麼我在我的美式鍵盤上按 y,遠端出現的就是 y (而不是 z) 了~
Karabiner 還有提供非常多的內建設定,但真的是太多了,
有需要的話就一個個打開來看看吧~
3. 設定 Karabiner:使用客製化設定
我們雖然可以用上面的 y<–>z 交換來解決 y z 錯位的問題,
但還有很多鍵是會出問題的 (像是按下 > 會出現冒號 :)…
Karabiner 沒有辦法提供所有的鍵盤對應 (可能會有語言數目*語言數目這麼多種),
但我們可以自己寫一個我們需要的對應來使用~
假設在美式鍵盤上按下 X 鍵之後,在遠端的德國電腦上跑出了 Y 字元,
那就表示,要是我真的想要出現的是 Y 字元的話,那我只要打 X 鍵就行了~
要建立這樣的對應表,我們要修改預設的 private.xml 檔案,
到 Karabiner Preferences > Misc & Uninstall > Open private.xml:
private.xml 的內容預設只有一個空的 <root> 節點,
我們可以在裡面加入一個 <include path=”設定檔路徑” />,例如:
<?xml version="1.0"?> <root> <include path="/Users/testuser/en_to_german_keyboard.xml" /> </root>
然後我們要建立 /Users/testuser/en_to_german_keyboard.xml 這個檔案,內容如下:
<?xml version="1.0" ?> <root> <windownamedef> <name>GermanVM</name> <regex>Windows7de</regex> </windownamedef> <item> <name>Map U.S layout to German layout</name> <identifier>private.entogerman</identifier> <windowname_only>GermanVM</windowname_only> <autogen>__KeyToKey__ KeyCode::Y, KeyCode::Z</autogen> <autogen>__KeyToKey__ KeyCode::Z, KeyCode::Y</autogen> <autogen>__KeyToKey__ KeyCode::KEY_0, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::KEY_9, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen> <autogen>__KeyToKey__ KeyCode::KEY_2, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::Q, ModifierFlag::OPTION_R</autogen> <autogen>__KeyToKey__ KeyCode::KEY_3, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::BACKSLASH</autogen> <autogen>__KeyToKey__ KeyCode::KEY_6, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::BACKQUOTE, KeyCode::SPACE</autogen> <autogen>__KeyToKey__ KeyCode::KEY_7, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::KEY_6, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen> <autogen>__KeyToKey__ KeyCode::KEY_8, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::BRACKET_RIGHT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen> <autogen>__KeyToKey__ KeyCode::KEY_9, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::KEY_8, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen> <autogen>__KeyToKey__ KeyCode::EQUAL, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::BRACKET_RIGHT</autogen> <autogen>__KeyToKey__ KeyCode::EQUAL, KeyCode::KEY_0, ModifierFlag::CAPSLOCK</autogen> <autogen>__KeyToKey__ KeyCode::MINUS, KeyCode::SLASH</autogen> <autogen>__KeyToKey__ KeyCode::BACKSLASH, KeyCode::MINUS, ModifierFlag::OPTION_R</autogen> <autogen>__KeyToKey__ KeyCode::BACKQUOTE, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::BRACKET_RIGHT, ModifierFlag::OPTION_R</autogen> <autogen>__KeyToKey__ KeyCode::QUOTE, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::KEY_2, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen> <autogen>__KeyToKey__ KeyCode::QUOTE, KeyCode::BACKSLASH, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen> <autogen>__KeyToKey__ KeyCode::SEMICOLON, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::DOT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen> <autogen>__KeyToKey__ KeyCode::SEMICOLON, KeyCode::COMMA, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen> <autogen>__KeyToKey__ KeyCode::SLASH, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::MINUS, ModifierFlag::CAPSLOCK</autogen> <autogen>__KeyToKey__ KeyCode::SLASH, KeyCode::KEY_7, ModifierFlag::CAPSLOCK</autogen> <autogen>__KeyToKey__ KeyCode::BRACKET_LEFT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::7, ModifierFlag::OPTION_R</autogen> <autogen>__KeyToKey__ KeyCode::BRACKET_LEFT, KeyCode::8, ModifierFlag::OPTION_R</autogen> <autogen>__KeyToKey__ KeyCode::BRACKET_RIGHT, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::0, ModifierFlag::OPTION_R</autogen> <autogen>__KeyToKey__ KeyCode::BRACKET_RIGHT, KeyCode::9, ModifierFlag::OPTION_R</autogen> </item> </root>
嗯… 上面這個 XML 的檔案顯然一開始是看不懂的,這是 Karabiner 入門難度高的地方,
但是不寫自己的 XML、只靠內建設定的話,能做到的事情有限,因此還是得學一下~
來稍微解釋一下這個我寫的 XML 吧,
但最好是先看過 Karabiner 的 private.xml Reference Manual 後,會比較清楚~
首先,這個 XML 一樣根節點是 <root>,
我們在裡面定義了一個 <windownamedef>,這是為了讓 Karabiner 只在特定視窗才作用,
例如我定義了視窗名稱 GermanVM (自己隨意訂),而比對的方式是用正規表示法 (regular expression),
當視窗標題中有 Windows7de 這個字串的話,這個視窗就是一個 GermanVM 視窗:
<windownamedef> <name>GermanVM</name> <regex>Windows7de</regex> </windownamedef>
接下來要定義一個 <item> 節點,這個節點代表了一個可以在 Karabiner 中勾選的設定。
<name> 是這個設定的說明字串,
<identifier> 要取一個唯一的識別名,通常是用 private. 開頭,
而如果這個設定只套用在某些視窗上的話,就加上 <windowname_only> 節點:
<item> <name>Map U.S layout to German layout</name> <identifier>private.entogerman</identifier> <windowname_only>GermanVM</windowname_only> </item>
像上面的就代表要建立一個「美式鍵盤轉德式鍵盤」的設定,
並且只有在 GermanVM 視窗上作用 (也就是視窗標題中有 Windows7de 的視窗)。
當我們的 XML 寫好之後,按下 Change Key 分頁中的 Reload XML 按鈕,
我們寫的 <item> 就會出現,變成可以勾選的設定:
那這個設定勾選之後可以做什麼事呢?這就要靠 <autogen> 節點了~
通常我們會用 <autogen> 搭配 __KeyToKey__ 來代表將某鍵替換成某鍵,
例如下面的寫法表示要將 Y 和 Z 兩鍵交換:
<autogen>__KeyToKey__ KeyCode::Y, KeyCode::Z</autogen> <autogen>__KeyToKey__ KeyCode::Z, KeyCode::Y</autogen>
來看另一個較複雜的例子~
在美式鍵盤按下 Shift+0 的時候,出現的是小右括號 “)”,但在德式鍵盤出現的是等號 “=”。
在美式鍵盤按下 Shift+9 的時候,出現的是小左括號 “(“,但在德式鍵盤出現的是小右括號 “)”。
也就是說,假設我想要在德式鍵盤上打出小右括號的話,我應該要在美式鍵盤上打 Shift+9,
但我希望的是看著美式鍵盤,按下熟悉的 Shift+0,
但送出 Shift+9 的鍵盤碼給德式鍵盤,讓它在德式鍵盤上打出我想要的小右括號~
於是就可以像下面這樣寫:
<autogen>__KeyToKey__ KeyCode::KEY_0, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::KEY_9, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT</autogen>
再一個例子~
當我在美式鍵盤上按下最左上角的 ` 鍵時,好像沒什麼反應,
但只要再加一個空白鍵,就會跑出 ^ 這個字元 (美式鍵盤的 Shift+6)~
所以我也可以設定當 Shift+6 被按下時,送出 ` 加一個空白鍵,就會有我想要的 ^ 字元:
<autogen>__KeyToKey__ KeyCode::KEY_6, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::BACKQUOTE, KeyCode::SPACE</autogen>
其他的 <autogen> 設定大同小異,就是先找出來要怎樣才會出現某字元,
再將這個對應寫上去,只是有時可能要特定左右邊的鍵才能作用,
因此才會有 OPTION_R (右邊的 Option 鍵) 這種寫法 (左邊的就是 OPTION_L) 了~
還有一點很容易忘記的,就是這個設定檔是只要有一個符合,就不會再往下找了,
因此要把「比較複雜」的按鍵組合放在上面~
像下面分別定義按下 Shift+= 以及單按 = 之後要送出的鍵,
因為 Shift+= 比較複雜,所以要放在上面。
如果 = 這個規則放在 Shift+= 上面的話,那麼按下 Shift+= 時也會符合按下 = 這個規則,
而導致執行了錯誤的轉換:
<autogen>__KeyToKey__ KeyCode::EQUAL, MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT, KeyCode::BRACKET_RIGHT</autogen> <autogen>__KeyToKey__ KeyCode::EQUAL, KeyCode::KEY_0, ModifierFlag::CAPSLOCK</autogen>
看到這裡應該有些疑問,就是怎麼知道要用 KeyCode::BACKQUOTE 表示 ` 這個鍵呢?
這可以利用 Karabiner 內建的 EventViewer 來查看,
從 Mac 最上方圖示列找到 Karabiner > Launch EventViewer:
在 Main 分頁,按下想要觀察的鍵,就會出現對應的說明了~
像下圖中的紅色框,是我按下 ` 這個鍵後出現的,
代表出現了一個 BACKQUOTE 的 KeyDown 事件和 KeyUp 事件~
而藍色框,是我按下 < 鍵 (Shift+,) 後出現的,
可以看到 flags 這邊是 Shift (KeyCode 可以是 SHIFT_L 或 SHIFT_R,
若是不限制左右邊的話,就可以寫成 MODIFIERFLAG_EITHER_LEFT_OR_RIGHT_SHIFT),
按下的主鍵則是 COMMA:
EventViewer 還可以用來觀察視窗的一些資訊,
先切到要觀察的視窗,再回到 EventViewer > App 分頁,就能看到視窗的標題與識別字,
像我用的 Windows7de 這個視窗標題,就是從這邊的 Windows Name 查到的:
當 XML 都寫好之後,就要按下 Change Key 分頁中的 Reload XML 按鈕,
並且將我們的設定打勾 (本例中的 Map U.S. layout to German layout),設定就會立刻生效~
這時再到德文 VM 裡面打字,就可以發現大部分的字元/符號都能正確的打出來,
只剩下 `, |, <, > 這幾個字元還沒找到對應~
Karabiner 真的是個很不錯的工具,
之後在遠端連線到客戶端電腦前,可以先準備好對應的設定檔,
如果客戶不能讓我們設定美式鍵盤的話,Karabiner 就能立刻派上用場囉~^^
參考資料:Reconfigure Your Mac Keyboard for More Geek Power [Mac]