自定义注册热键类, 保证稳定同时可覆盖注册已注册过的热键

By 圣地 at 2021-12-23 • 0人收藏 • 460人看过
import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio form";right=759;bottom=469)
winform.add(
button={cls="button";text="Button";left=282;top=183;right=609;bottom=289;z=1}
)
/*}}*/

import console;
import key.hotkey;

class reghotkey{
	ctor( winform ){
		var superHK = ..key.hotkey(winform)
		var modArr = {Alt=1,Ctrl=2,Shift=4,Win=8}
		var regHkId = {};	
	};	
	reg = function(func, hotkeyStr){
		var mod = 0;
		var vk;	
		if(..string.find(hotkeyStr,"@+")){
			var retArr = ..string.split(hotkeyStr,'+')			
			var lastKey = retArr[#retArr]
			vk = ..key.getCode(lastKey)
			for(i=1;#retArr-1;1){
				mod += modArr[retArr[i]]	
			}			
		}else {
			vk = ..key.getCode(hotkeyStr)
		}				
		var ret = winform.reghotkey( func , mod, vk)		
		if(ret){
			//这时可以用超极热键来注册
			..console.log("------- reg 方式 --------------",hotkeyStr)			
		}else {
			..console.log("------- hook 方式 --------------",hotkeyStr)
			superHK.regStr(hotkeyStr,func )
		}		
	};	
	unreg = function(){
		superHK.clear()
		for(k,v in winform._hotkeys){
			..console.log(k,v)
			winform.unreghotkey(k)		
		}		
	}	
}
var hk = reghotkey(winform)
hk.reg(function(){ console.log(3333) },"F2")
hk.reg(function(){ console.log(5555) },"Win+A")
hk.reg(function(){ console.log(6666) },"Ctrl+A")
winform.button.oncommand = function(id,event){
	hk.unreg()
}

winform.show();
win.loopMessage();

钩子热键有时会不稳定(如远程桌面连接后有时会失效),RegisterHotKey 方式个别键又无法注册

用上面方法优先用 RegisterHotKey 来注册,如果不成功再用钩子方式。


Update 2021-12-24 10:40  增加卸载热键功能,这样会将所有热键全部卸载掉,如果说要修改某个本程序内已注册的热键只需要 unreg() 然后根据热键字符串重新注册就可以了,

如果要单独修改某个热键,对 RegisterHotKey 还可以根据热键ID卸载后重新注册一个,但超极热键无法单独修改,这样操作代码写起来简洁省事,速度也很快。

6 个回复 | 最后更新于 2021-12-24
2021-12-24   #1

以前用的纯钩子方法,受到限制不只远程桌面 还有360什么的,然后如果加上//RUNAS//误报也会增加( 待进一步验证 ),尽可能用系统标准注册热键方式,保证软件基本可用,不至于出问题热键完全不能用。

我在看了AHK的实现方法也是这么干的,算是相对比较稳定的方法了,能尽可能的保证不会出错

2021-12-24   #2

回复#2 @圣地 :

感谢分享,研究的深入。

2021-12-24   #3

已注册过得一般不都是提示热键已占用么,直接覆盖不太好吧

2021-12-24   #4

以RegisterHotKey 注册为主,这时如果其它程序注册过是无法覆盖的

这时就用钩子来覆盖

2021-12-24   #5

A用远程桌面连接B后,B上的低级键盘钩子程序有时会失效,这个也不好重现出来,只是有时会,当时查的资料是说一定时间内执行不完相关动作,Win7以上系统会没有任何提示情况下释放钩子。解决方法可以改个注册表加大一个时间的方法。

//贴一下当时查的资料

https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/f6032ca1-31b8-4ad5-be39-f78dd29952da/hooking-problem-in-windows-7?forum=windowscompatibility 	
https://stackoverflow.com/questions/48695720/setwindowshookex-hook-stops-working 	
https://stackoverflow.com/questions/14596117/setwindowshookex-wm-keyboard-ll-not-coming-through-with-full-screen-rdc   远程桌面导致挂钩不工作	
https://kb.vmware.com/s/article/1009409 用vmware虚拟机时出现钩子不能用,可以手动注册表创建超时项目建议改为5000	
VC底层钩子程序在Win7/Vista下无效
Source: https://www.cnblogs.com/braver/articles/2557961.html 	
HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout  
//Win10中默认没有这个项,可以手动创建: 新建>DWORD32值,类型改为10进制写入5000
该值以毫秒为单位。如果挂接过程超时,系统会将消息传递到下一个挂接。但是,在 Windows 7 及更高版本上,钩子会静默地删除,而不会被调用。应用程序无法知道钩子是否已移除。
注意调试挂钩无法跟踪这种类型的低级键盘挂钩。如果应用程序必须使用低级挂钩,则应在专用线程上运行挂钩,该线程将工作传递给工作线程,然后立即返回。在大多数情况下,应用程序需要使用低级挂钩,它应该改为监视原始输入。这是因为原始输入可以异步监视针对其他线程的鼠标和键盘消息,这些消息比低级钩子更有效。有关原始输入的详细信息,请参 阅原始输入。
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v=vs.85) 

以上信息说明了,会有超时的情况导致 钩子失效:
对Win7以下,系统会将消息传递到下一个挂接。
对Win7以上,系统会悄悄的静默删除挂钩并不给出任何提示。

解决办法( 这是我当时瞎总结的,也没有实际测试不一定对 ):
改注册表将超时时间改大一点如 5000ms
用专用线程运行挂钩
改为原始钩子,既扩展库 win.win.rawInput; 底层输入设备钩子



360这个有时会弹出键盘被监控,这个情况所有键盘钩子类程序都这样,AHK 也这样。

我是想怎么能减少这类情况所以用 RegisterHotKey  替代,这样也可以在出现钩子1/100失效情况和360拦截情况下不至于不工作,所以用了上述方法,




AHK不是高手、aardio更不是,这个问题不懂。

2021-12-24   #6

现在的方法运行一段时间看看,不行就试试定时器定时注册钩子


按起始页的方法 360、微软、麦咖啡这三个都用过,360回复也挺及时在10多个小时就回复

现在电脑基本就是 360、微软 这两个,这个方法有效。


证书一年要2800元,等单位有钱了就搞一个。另查到好像是标准证书微软方面只是提权颜色变了,其它的基于声誉的检测也要等下载量多了才好使,还不如过白好用。

登录后方可回帖

登 录
信息栏
公 告:

专注分享

谢绝纯提问

谢谢合作!
本站域名:HtmLayout.Cn
aardio可以快速开发上位机,本站主要记录了学习过程中遇到的问题和解决办法及aardio代码分享

这里主要专注于aardio学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.

Aardio 官方站:Aardio官方
Aardio最新功能:Aardio官方更新日志
本 站 主 站:Stm32cube中文网
Sciter中文在线文档Sciter在线学习文档
空间赞助:才仁机械
打赏本站
Loading...