import key.hook; import winex; namespace key class hotkey{ ctor(){{ this.hk = ..key.hook(); this.actions = {}; this.downKeys = {}; this.downCount = 0; this.say = ..key.sendString; this.log = logger(this); this.log.setEndKeys( "-","(",")","[","]","{","}",":",";","'",'"',"/","\",",",".","?","!",'\n',' ','\t'); this.log.setControlKeys("CTRL","SHIFT","ALT","WIN","LCTRL","RCTRL","LSHIFT","RSHIFT","LALT","RALT","LWIN","RWIN") this.setTimeout = function(func,tk=1,...){ if(!func) return; ..win.setTimeout( function(...){ func(...) },tk,... ) } var firstKeyDowning,hasPendingHotkey; var fireEvent = function(keyUp){ var vk,node,lastPressVkCode; node,firstKeyDowning,hasPendingHotkey,lastPressVkCode = this.log.findAction(); if(!node) { var logLen = this.log.getLength() if( logLen <= 1){ if(logLen != 0){ this.log.clear(); } if(this.onWaiting) this.setTimeout( this.onWaiting,1,..winex.getFocus() ); return; } if(this.onWaiting){ this.setTimeout(this.onWaiting,1); } return true; } if(!keyUp && node.waitUp) return; var event = node.event var tEvent = type(event); var focus; if(event || this.onWaiting){ focus = ..winex.getFocus(); } if( (!(firstKeyDowning && hasPendingHotkey)) && tEvent==type.function){ var catchKeys = { this.log.getCatchKeys() }; this.log.clear(); var send = event(focus,..table.unpack(catchKeys)); if( this.onWaiting ){ this.setTimeout( this.onWaiting,1,focus ); } if(send) { if( type(send) == type.function ){ ..win.setTimeout( function(){ send(); if(this.downKeys[vkcode]){ this.downCount = this.downCount - 1; this.downKeys[vkcode] = false; } for(k,d in this.downKeys){ if(d && !(::GetAsyncKeyState(k) & 0x8000) ){ this.downKeys[k] = false; this.downCount = this.downCount - 1; } } },1,focus,..table.unpack(catchKeys) ); return true; } return; } else { if(this.downKeys[vkcode]){ this.downCount = this.downCount - 1; this.downKeys[vkcode] = false; } for(k,d in this.downKeys){ if(d && !(::GetAsyncKeyState(k) & 0x8000) ){ this.downKeys[k] = false; } } } return true;//取消所有按键 } elseif( ( !(firstKeyDowning && hasPendingHotkey) ) && tEvent==type.string){ this.setTimeout( function(hwnd){ if( hwnd){ var str = ..string.trimright(event,"$"); this.say( str ); } if( ..string.endsWith(event,'$') ){ if( this.downKeys[lastPressVkCode] ){ ..key.down(lastPressVkCode) } else { ..key.press(lastPressVkCode) } } },1,focus ) this.log.clear(); if(this.onWaiting){ this.setTimeout( this.onWaiting,1,focus ); } return true;//取消所有按键 } else{ if(this.onWaiting){ var waitkeys = {} for(k,v in node){ if(k!="event") ..table.push(waitkeys,k==0?"[预设终止符]":..key.getName(k)); } this.setTimeout( this.onWaiting,1,focus,{ this.log.getCatchKeys() },waitkeys ); } return true; } } //录制回调函数 this.hk.proc = function(msg,vkcode,scancode,injected,flags,timeStamp,extraInfo){ if( injected ) return; select(msg) { case 0x100/*_WM_KEYDOWN*/ ,0x104/*_WM_SYSKEYDOWN*/ { if( ! this.downKeys[vkcode] ){ this.downCount = this.downCount + 1; this.downKeys[vkcode] = true; if(this.onKeyDown){ var ret = this.onKeyDown(vkcode); if(ret) { this.log.clear(); return ret; } } this.log.push( vkcode ); if( fireEvent(false) && !this.log.controlKeys[vkcode] ){ if( this.downCount == 1){ this.downKeys[vkcode] = -1; } return true; } } elseif(this.downKeys[vkcode] === -1){ return true; } } case 0x101/*_WM_KEYUP*/,0x105/*_WM_SYSKEYUP*/{ if(this.downKeys[vkcode]){ this.downCount = this.downCount - 1; this.downKeys[vkcode] = false; } var ret; if(firstKeyDowning && hasPendingHotkey) ret = fireEvent(true); if(this.onKeyUp){ var ret = this.onKeyUp(vkcode); if(ret) return ret; } return ret && !this.log.controlKeys[vkcode]; } } } }}; getEndKeys = function(){ return this.log.getEndKeys(); }; setEndKeys = function(...){ this.log.setEndKeys(...) }; getControlKeys = function(){ return this.log.getControlKeys(); }; setControlKeys = function(...){ this.log.setControlKeys(...) }; reg = function(...){ var args = [...]; if(#args<2) error("至少要指定一个热键、一个触发函数",2) return this.__regKeys__(true,args); }; __regKeys__ = function(checkCtrlKeys,args){ var func = args[#args]; var t = type(func) if( ( t != type.function) && ( t != type.string ) ){ error("最后一个参数必须是函数对象或字符串",2) } var root = {} var node = this.actions var vk ; var ctrlKeys = 0; for(i=1;#args-2;1){ if(!args[i]) error("按键不能为空值,参数位置:@"+i,2) vk = ..key.getCode(args[i] ) ; if(!vk) error("指定了错误的按键,参数位置:@"+i,2) if( ! node[ vk ] ){ node[ vk ] = {}; } node = node[ vk ] if( checkCtrlKeys && this.log.isControlKey(vk) ){ ctrlKeys++; } else{ checkCtrlKeys = false; } } vk = args[#args-1]; if(!vk) error("按键不能为空值,参数位置:@"+#args-1,2) vk = (vk != '\0' )? ( ..key.getCode(vk) ): 0 if( type(func) == type.string ){ func = loadcode(func) : func; args[#args] = func; } if( !node[ vk ] ) node[ vk ] = {}; node[ vk ].event = func; if(ctrlKeys>1){ if( ctrlKeys == 2 ){ args[1],args[2] = args[2],args[1]; this.__regKeys__(false,args); } elseif( ctrlKeys == 3 ){ args[2],args[3] = args[3],args[2]; this.__regKeys__(false,args); args[2],args[1] = args[1],args[2]; this.__regKeys__(false,args); args[1],args[3] = args[3],args[1]; this.__regKeys__(false,args); args[2],args[3] = args[3],args[2]; this.__regKeys__(false,args); args[2],args[1] = args[1],args[2]; this.__regKeys__(false,args); } elseif( ctrlKeys > 3 ){ import table.permutations; var args1 = ..table.slice(args,1,ctrlKeys); var args2 = ..table.slice(args,ctrlKeys+1); for args1 in ..table.permutations(args1){ this.__regKeys__(false,..table.append(args1,args2)); } } } return node[ vk ]; //仅供 regStr 函数使用 } regStr = function(str,proc){ if(type(str)!=type.string ) error("参数@1必须是字符串",2); if(!#str) error("参数@1不能为空字符串",2); str = ..string.upper(str); var t; if(..string.match(str,"^[A-Z]{2,}\+")){ str = ..string.replace(str,"\+\,","+<"); t = ..string.split(str,"+,") } else { if(str[1]=='@'#){ var k = ..string.right(str,-2); var vk = ..key.getCode(k); if( vk && this.log.isControlKey(vk) ){ var node = this.reg(k,proc); node.waitUp = true; return; } } if(..key.getCode(str)) return this.reg(str,proc); t = ..string.split(str); } ..table.push(t,proc); this.reg( ..table.unpack(t) ) } regEndStr = function(str,proc,sepChar){ if(..string.match(str,"^[A-Z]{2,}\+")){ str = str + ',\0' } else { str = str + '\0'; } this.regStr(str,proc); } clear = function(){ this.actions = {}; this.log.clear(); } clearKeys = function(){ this.log.clear(); } reset = function(){ this.clear(); this.close(); this.hk = ..key.hook(); } loadTable = function(cfg){ if(type(cfg)==type.table){ for k,v in ..table.eachName(cfg){ this.regStr(k,v); } } } close = function(){ this.hk.close(); } } namespace hotkey{ class logger{ ctor( hotManager ){ this.catchKeys = {}; this.hotManager = hotManager; }; push = function(vkcode){ if(#this.catchKeys==0){ for(k,v in this.$uniqControlKeys ){ if(k==vkcode)continue; if( ::GetKeyState(k) & 0x8000 ){ ..table.push( this.catchKeys,k ); this.hotManager.downKeys[k] = true; } else this.hotManager.downKeys[k] = false; } } ..table.push( this.catchKeys, vkcode ); } clear = function(){ ..table.pop(this.catchKeys,#this.catchKeys) } back = function(pos){ var vk; var len = #this.catchKeys; if(!len || len