自己動手,豐衣足食。普通鍵盤實現鍵盤宏(Windows和Mac版)


很多高端機械鍵盤,支持宏定義,例如我們可以設置"D"鍵為"dota",這樣當我們按一下宏開啟鍵,再按一下"D"鍵,就等價於分別按了"d" "o" "t" "a"四個鍵。這時就可以把一些敲代碼時常用的模板定義成鍵盤宏,到時候一鍵補全代碼,既高效又裝X。另外,玩游戲時想按出“下前下前拳”這樣的組合技能也容易多了。

那么問題來了。。

山里來的買不起機械鍵盤的窮B同時又是程序員應該怎么辦。。

其實這樣簡單的功能不一定非要硬件支持,借助一些現有軟件模擬一下鍵盤就好了,在windows下有按鍵精靈和AutoHotKey這些神器,模擬起來很容易,而且體驗非常完美。

我是借助按鍵精靈實現的,按鍵精靈語法很簡單,例如 KeyPress "A", 3 就表示按A鍵3次,而且支持全局快捷鍵啟動,支持監聽用戶輸入,真是簡單到無情。

不過問題又來了。。

鍵盤宏主要是按一系列按鍵,如果每個按鍵都寫一行 KeyPress "X", 1 ,有的還得配合Shift鍵才能按出來,也是累,而且一行一句代碼,看上去不直觀,容易寫錯。

那就寫個代碼生成器就好了,我是用C語言+std::string實現的,直接把宏寫成字符串,生成器自動輸出相應的按鍵,粘貼到按鍵精靈中編譯保存就好了。

貼一下代碼:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <ctype.h>
  5 #include <string>
  6 
  7 using std::string;
  8 
  9 enum class OpType {
 10     Press,
 11     Down,
 12     Up
 13 };
 14 
 15 enum class CombKey {
 16     Shift,
 17     Ctrl,
 18     Alt
 19 };
 20 
 21 void initTransHash(); //初始化按shift才能打出的字符
 22 void transfer(char c); //shift打出的字符轉化為真正的按鍵
 23 void procOpType(OpType type); //輸出按鍵操作
 24 void callKey(OpType type, char key, int count=1); //按鍵
 25 void callKey(OpType type, string key, int count=1); //重載,按功能鍵
 26 void keyComb(CombKey comb, char key); //組合鍵
 27 
 28 
 29 const int delay = 2;
 30 string transChar;
 31 char transHash[256];
 32 
 33 
 34 int main() {
 35     initTransHash();
 36     
 37     string keys = "function() {\n},";
 38     
 39     for(char key : keys) {
 40         if(strchr(transChar.c_str(), key) != NULL) {
 41             transfer(key);
 42         } else {
 43             if(isupper(key)) {
 44                 keyComb(CombKey::Shift, key);
 45             } else {
 46                 callKey(OpType::Press, key);
 47             }
 48         }
 49     }
 50 }
 51 
 52 void initTransHash() {
 53     memset(transHash, 0, sizeof(transHash));
 54     
 55     //
 56     //   ~ ! @ # $ % ^ & * ( ) _ + { } |  : \" < > ?
 57     //   ` 1 2 3 4 5 6 7 8 9 0 - = [ ] \\ ; '  , . /
 58     
 59     transChar = "~!@#$%^&*()_+{}|:\"<>? \n";
 60     string keys = "`1234567890-=[]\\;',./\0\0";
 61     
 62     // transChar空格后面的字符不加入hash表
 63     for(int i = 0; i < keys.size(); i++) {
 64         transHash[transChar[i]] = keys[i];
 65     }
 66 }
 67 
 68 void transfer(char c) {
 69     if(transHash[c]) {
 70         keyComb(CombKey::Shift, transHash[c]);
 71         return;
 72     }
 73     switch(c) {
 74         case '\n':
 75             callKey(OpType::Press, "Enter");
 76             break;
 77             
 78         case ' ':
 79             callKey(OpType::Press, "Space");
 80             break;
 81             
 82         default:
 83             printf("[Red] cant transfer: %c\n", c);
 84             break;
 85     }
 86 }
 87 
 88 void procOpType(OpType type) {
 89     switch(type) {
 90         case OpType::Press:
 91             printf("KeyPress "); break;
 92         case OpType::Down:
 93             printf("KeyDown "); break;
 94         case OpType::Up:
 95             printf("KeyUp "); break;
 96     }
 97 }
 98 
 99 void callKey(OpType type, char key, int count) {
100     procOpType(type);
101     printf("\"%c\", %d\n", islower(key) ? key-32 : key, count);
102     printf("Delay %d\n", delay); //每次按鍵后延遲10毫秒
103 }
104 
105 void callKey(OpType type, string key, int count) {
106     procOpType(type);
107     //printf("\"%s\"\n", key.c_str());
108     printf("\"%s\", %d\n", key.c_str(), count);
109     printf("Delay %d\n", delay); //每次按鍵后延遲10毫秒
110 }
111 
112 void keyComb(CombKey comb, char key) {
113     string combKey;
114     switch(comb) {
115         case CombKey::Shift:
116             combKey = "Shift"; break;
117         case CombKey::Ctrl:
118             combKey = "Ctrl"; break;
119         case CombKey::Alt:
120             combKey = "Alt"; break;
121         default:
122             return;
123     }
124     
125     callKey(OpType::Down, combKey);
126     callKey(OpType::Press, key);
127     callKey(OpType::Up, combKey);
128 }
按鍵精靈_鍵盤宏_代碼生成器

然后把每一個鍵盤宏寫成一個函數,通過按下按鍵精靈的全局快捷鍵啟動,然后腳本監聽用戶按鍵,然后調用相應函數執行鍵盤宏就可以了,模板類似這樣:

 1 choose = WaitKey()
 2 TracePrint choose
 3 
 4 Select Case choose
 5     Case 70
 6         KeyPress "BackSpace", 1
 7         Call F()
 8     Case 72
 9         KeyPress "BackSpace", 1
10         Call H()
11 End Select
12 
13 // 按下F鍵
14 Sub F()
15 End Sub
16 
17 // 按下H鍵
18 Sub H()
19 End Sub
按鍵精靈_鍵盤宏_模板

(宏鍵也會打印出來,所以我在調用函數打印鍵盤宏之前,調用BackSpace刪除了宏鍵的字符)

 

然后問題又來了。。

上班用的是Mac,Mac沒有按鍵精靈呀。最簡單的辦法是安裝windows虛擬機,物理機和虛擬機共享代碼目錄,在虛擬機中敲代碼,其他工作仍然在物理機中進行,不影響工作流。(其實用了5個月的Mac了,個人感覺,在新鮮感過了之后,實用性比windows差遠了)

另外如果不想通過虛擬機的方式,還可以使用AppleScript,但是AppleScript本身沒有像按鍵精靈那樣的全局啟動快捷鍵,可以通過Automator把AppleScript設置為系統服務,然后給服務設置快捷鍵,但是AppleScript不方便監聽用戶按鍵事件,目前我只能通過dialog讀取用戶輸入,所以做不到按鍵精靈那樣完美,上面的生成器的代碼稍微改動一下,就能作為AppleScript的鍵盤宏生成器了,下面是AppleScript的模板:

 1 tell application "System Events"
 2     display dialog "choose" default answer ""
 3     set ans to text returned of result
 4     
 5     if ans = "p" then
 6         keystroke "1"
 7         keystroke "0"
 8         keystroke "0"
 9         keystroke "8"
10                 keystroke "6"
11     else
12         display dialog "unknown"
13     end if
14     
15 end tell
AppleScript_鍵盤宏_模板

但是焦點會被dialog獲取,需要在鍵盤宏之前把接收鍵盤宏的進程設為最前。

tell process "XXXXXX"
    set frontmost to true
end tell

還是安裝虛擬機好得多。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM