如何模擬數位鍵盤/小鍵盤以與設計軟體(例如 Blender)一起使用?

如何模擬數位鍵盤/小鍵盤以與設計軟體(例如 Blender)一起使用?

問題

使用某些軟體時,例如攪拌機,能夠使用數位鍵盤非常重要,使用者可以在設計空間中進行諸如定位自己等操作,但許多筆記型電腦沒有配備實體數字鍵盤。由於常規數字欄輸入(鍵盤頂部的 1-9)實際上對電腦代表不同的“符號”,因此在這些類型的軟體中通常具有完全不同的功能,這一事實使情況變得更加複雜。

嘗試的解決方案

由於許多筆記型電腦沒有配備數字鍵盤,許多平台上的常見解決方案是模擬小鍵盤,例如按住一個按鍵的同時使用鍵盤上的其他按鍵(例如 jkluio789 代表 123456789)。許多筆記型電腦在 BIOS 層級上實現此功能(例如使用 Fn 鍵)。然而,如果沒有這樣的低階實現,要實現這種模擬是非常困難的。

網路上有一些解決方案,但是它們通常不足以與設計軟體一起使用(因為它們沒有實現正確的符號,並且還需要使用修飾鍵),或者他們沒有深入解釋。大多數解決方案都集中在使用xkb,這是一個複雜且極難開始使用的架構。

良好解決方案的要求

解決此問題的一個好方法是使用模擬鍵盤,圖形軟體將其視為真正的鍵盤輸入,並且易於使用。另一個限制是,即使被告知明確的修飾符, Blender 也會檢測到修飾鍵的使用(例如ShiftAltSuper(“Command”、“Windows 鍵”等)、 ) ,因此會解釋“鍵盤模擬”持有修改鍵」解決方案作為完全不同的輸入(即 [ + ] 而不是只是)。因此,理想的解決方案實際上涉及鎖定機制(例如 Caps Lock 大寫)而不是保持機制(例如 Shift 大寫),以便不會意外地將修飾符傳遞給軟體。HyperxkbNumpad1AltNumpad1

答案1

快速開始

如果您不關心任何解釋(我知道我可能會囉嗦),請按照{大括號中的粗體數字}在某些段落的開頭。按順序執行每個步驟,您可能可以在幾分鐘內完成此操作。請注意,本指南假設您具有一定程度的 Unix 能力(能夠建立目錄、建立檔案、sudo提升至 root 存取權等)。另請注意僅在指定的情況下才需要 root 存取權限sudo,所以除非被告知,否則您不需要使用。

解決方案的一般描述

我們將使用 xkb 向 Linux 添加「鎖定」(如大寫鎖定)數位鍵盤模擬。我希望我的鍵“jkluio789”代表數字“123456789”的數字鍵盤表示,以及一些其他包含內容(“m,”->“0”,“-=[]”->[numpad]” -+*" , "."->[小鍵盤]".")。我將使用 [ Shift+ Mod4+ [key]]組合鍵切換此“小鍵盤模式”,其中Mod4是我的作業系統鍵的修飾符代碼(也稱為“Command”或“Windows 鍵”,有時會指派給Super或的修飾符代碼Hyper) ,並且[key]是我的模擬小鍵盤中使用的任何鍵(例如“j”或“[”)。閱讀完整的解決方案後,對此設定的簡單修改應該相對簡單。

為此,我們將定義一個自訂xkb「類型」文件,它告訴xkb 如何解釋我們將用於初始化鍵盤模擬的各種修飾鍵,以及一個自訂xkb「符號」文件,它告訴xkb 每個修飾鍵如何我們按下的鍵應該表現正常(第 1 組),它在數字鍵盤模擬期間應該如何表現(第 2 組),以及如何在兩者之間切換(兩個組的 3 級操作)。最後,我們將在每次啟動新會話時將其整合到當前的 xkbmap 中,從而使我們的解決方案永久化sed(這樣我們的解決方案就不會在每次xkb更新時被刪除)。

解決方案詳細說明

目錄結構

{1}我們要做的第一件事是定義目錄來保存各種檔案。

/home
  +-<username>
    +-.xkb
      +-symbols
      +-types
      +-keymap
      +-log

類型文件

一旦我們有了目錄樹,就可以在我們的解決方案中定義實際的檔案。我們要做的第一件事是定義我們的“類型”文件。該文件將告訴您xkb如何在“級別”之間移動(例如如何Shift將字母大寫,從小寫字母的第一個級別移動到大寫字母的大寫級別)。這些層次有點難以掌握,特別是對於以英語為母語的人來說,但國際鍵盤使用它們對替代字母和符號以及變音符號起到了很大的作用。

我們將使用它來定義我們打算如何指示密鑰的更改。換句話說,我們告訴它,當沒有按下修飾符時,我們期望“級別1”行為(通常,在“正常模式”下是標準小寫字母),當我們按住按鍵時,我們期望“級別2 」行為Shift(通常,我們的「正常模式」中的標準大寫字母),以及當我們同時按住Shift+時的「3 級」行為Mod4(對於我們的目的而言,這是一種特殊情況,我們用它來指示,當用於修改某個鍵時,該鍵現在將模式之間切換)。

{2}打開一個新文件,我們將其命名為togglekeypad.將以下程式碼區塊複製到其中,並將其儲存到您的types目錄下的\home\<username>\.xkb\types.注意:您可能需要將所有實例變更為Mod4「命令」/「Windows 鍵」按鈕對應的任何修飾符(您可能需要進行試驗,請參閱此網頁位於修飾鍵下以獲得指導)或您想要的任何其他修飾符。

partial default xkb_types "togglekeypad" { // Name of this type file
        type "TOGGLEKEYPAD" { // Name of this "type"
                modifiers = Shift+Mod4; // The modifiers that this type concerns itself with
                map[Shift] = level2; // Shift brings us to level 2
                map[Mod4+Shift] = level3; // Windows key plus shift brings us to level 3
                level_name[Level1] = "Base"; // Human-readable names for each level (not really used, but convenient)
                level_name[Level2] = "Shift";
                level_name[Level3] = "Transfer";
        };
};

{3}我們還必須將此文件複製到目錄中/usr/share/X11/xkb/types/。這將需要 root 權限,不幸的是,這有點違背了xkb作為用戶空間應用程式的目的,但setxkbmap如果不這樣做,我似乎無法識別該檔案。歡迎提出建議!

符號檔案

接下來我們將告訴xkb每個鍵在以我們在類型文件中描述的每種方式修改時應該做什麼。

我們會說我們想在符號檔案中使用兩個組。這意味著每個按鍵都有兩種不同的一般行為,我們將以某種方式在它們之間切換,這些行為是正常的打字行為和新的數字鍵盤模擬行為。對於每個鍵,我們會說 1) 我們想要使用類型TOGGLEKEYPAD,2) 我們將定義與所有級別的兩個組中的每個物理鍵相關的符號(即計算機看到的內容),以及3) 我們將定義xkb與所有層級的兩個群組的每個鍵關聯的)。這聽起來相當令人困惑,但看例子應該會更有意義。

我們在下面貼上的符號檔案中看到的第一個鍵就是鍵<AC07>。這對應於大多數鍵盤上的“J”鍵,根據這裡看到的地圖(圖2)。對於這個物理鍵,我們是說,在正常模式下:在級別 1(無修飾符,根據我們的類型文件)中,它將僅鍵入“j”,在級別 2(Shift修飾符)中,它將僅鍵入“J”。在等級 3 中,它做了一些特殊的事情:沒有與等級 3 關聯的符號,但有一個操作,該操作是 to LockGroup(group=2)。換句話說,將我們轉到第二組,即「鍵盤」組。如果我們查看接下來的幾行,我們會發現我們為同一個鍵的第 2 組定義了更多符號和操作。它表示,在等級 1(無修飾符)中,不鍵入任何符號,但RedirectKey(keycode=<KP1>).換句話說,註冊該鍵就好像我們實際上剛剛按下了該<KP1>鍵一樣,該鍵對應於鍵盤上的“1”。 (注意:我們可以再次放置 NoAction() 並使用符號KP_1,這是 key 對應的符號<KP1>,但我認為這將提供最佳的相容性)。對於等級 2,執行相同的操作,但將Shift修飾符新增至鍵上。最後,對於第 3 級,我們將自己鎖定到第 1 組「標準」模式。

{4}打開一個新文件,我們將其命名為togglekeypad_symbols.將以下程式碼區塊複製到其中,並將其儲存到您的symbols目錄下的\home\<username>\.xkb\symbols.

default partial
xkb_symbols "togglekeypad" {
    name[Group1]= "Standard";
    name[Group2]= "Keypad";

    key <AC07> { // J
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ j,  J, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP1>), RedirectKey(keyCode=<KP1>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AC08> { // K
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ k,  K, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP2>), RedirectKey(keyCode=<KP2>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AC09> { // L
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ l,  L, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP3>), RedirectKey(keyCode=<KP3>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD07> { // U
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ u,  U, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP4>), RedirectKey(keyCode=<KP4>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD08> { // I
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ i,  I, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP5>), RedirectKey(keyCode=<KP5>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD09> { // O
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ o,  O, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP6>), RedirectKey(keyCode=<KP6>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE07> { // 7
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 7,  ampersand, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP7>), RedirectKey(keyCode=<KP7>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE08> { // 8
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 8,  asterisk, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],     
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP8>), RedirectKey(keyCode=<KP8>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE09> { // 9
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 9,  parenleft, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP9>), RedirectKey(keyCode=<KP9>), LockGroup(group=1)]
    };
    
    // NumLock
    key <AE06> { // 6
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 6,  asciicircum, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<NMLK>), RedirectKey(keyCode=<NMLK>), LockGroup(group=1)]
    };
    
    // Bottom Row (and zero)
    key <AB07> { // M
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ m,  M, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP0>), RedirectKey(keyCode=<KP0>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE10> { // 0
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ 0,  parenright, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KP0>), RedirectKey(keyCode=<KP0>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AB09> { // .
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ period,  greater, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPDL>), RedirectKey(keyCode=<KPDL>, modifiers=Shift), LockGroup(group=1)]
    };
    
    // Arithmetic Operators
    key <AE11> { // -
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ minus,  underscore, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPSU>), RedirectKey(keyCode=<KPSU>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AE12> { // +
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ equal,  plus, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPAD>), RedirectKey(keyCode=<KPAD>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD12> { // [
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ bracketleft,  braceleft, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPDV>), RedirectKey(keyCode=<KPDV>, modifiers=Shift), LockGroup(group=1)]
    };
    
    key <AD12> { // ]
        type = "TOGGLEKEYPAD",
        symbols[Group1] = [ bracketright,  braceright, NoSymbol],
        actions[Group1] = [NoAction(), NoAction(), LockGroup(group=2)],
        
        symbols[Group2] = [NoSymbol, NoSymbol, NoSymbol],
        actions[Group2] = [RedirectKey(keyCode=<KPMU>), RedirectKey(keyCode=<KPMU>, modifiers=Shift), LockGroup(group=1)]
    };
};

測試我們的鍵盤

{5}若要按原樣測試鍵盤配置,請開啟一個Terminal視窗並鍵入

setxkbmap -types complete+togglekeypad -print | sed -e '/xkb_symbols/s/"[[:space:]]/+togglekeypad_symbols(togglekeypad)&/' > $HOME/.xkb/keymap/customMap
xkbcomp -I$HOME/.xkb -R$HOME/.xkb keymap/customMap $DISPLAY

這將獲取地圖的當前設定xkb(使用setxkbmap - print),同時設定用於的類型complete+togglekeypad(文件中的所有內容/usr/share/X11/xkb/types/complete,還包括位於 的類型文件/usr/share/X11/xkb/types/togglekeypad)。然後它將把它輸入到sed,這會將我們togglekeypad文件中的符號添加togglekeypad_symbols到使用的符號文件中。最後,我們用來xkbcomp編譯新的鍵盤映射。

請注意,在我的機器上,NumLock 被假定為關閉(因為我的機器上沒有小鍵盤),因此小鍵盤按鍵實際上會將其主要功能發送到計算機,即Home、End、PG Up、PG Down等要在使用類比數字鍵盤時輸入數字,請按住 Shift 鍵。我嘗試了各種方法來翻轉這種行為(modifers在符號檔案中的層級之間交換參數,分配一個新鍵來模擬 NumLock 鍵<NMLK>並切換它),但對我來說還沒有任何效果。不過值得慶幸的是,在 Blender 中進行測試時,它的表現完全符合預期,無需按住 Shift 鍵。

{6}如果此時出現嚴重錯誤,請不要擔心,只需登出/登入(或最壞的情況是重新啟動),調試,然後重試。如果一切正常,就讓它永久化吧。

使解決方案永久化

當然有一些更優雅的方法可以使我們的解決方案在會話之間持久存在,但對我來說最簡單、最可靠的方法是簡單地將上述命令放在文件末尾~/.bashrc。我用的是這裡提出的解決方案它添加了一些錯誤檢查,並添加了更多內容(這樣我就可以看到任何錯誤輸出)。

{7}打開文件~/.bashrc。將以下腳本新增至其末尾:

    # Setup custom keyboard remapping to emulate a number pad when "Shift+Cmd+numap_key" is pressed to initialize
if [ -d $HOME/.xkb/keymap ]; then
  setxkbmap -types complete+togglekeypad -print | \
    sed -e '/xkb_symbols/s/"[[:space:]]/+togglekeypad_symbols(togglekeypad)&/' > $HOME/.xkb/keymap/customMap 2> $HOME/.xkb/log/sedErrors
  xkbcomp -w0 -I$HOME/.xkb -R$HOME/.xkb keymap/customMap $DISPLAY > $HOME/.xkb/log/outputOfCommand 2>&1
fi

{8}重新啟動後,數位鍵盤模擬現在應該永久生效!

結論

雖然解釋很長,但方法本身相對較短。缺點是 Blender 需要一種鎖定方法才能正常工作,而我更喜歡一種保持方法,而且xkb由於某種原因它需要 root 存取權才能識別我們的自訂類型檔案。然而,總的來說,這對我來說似乎效果很好。如果您有任何疑問或建議,請隨時在下方留言!

相關內容