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

By 圣地 at 2021-12-23 • 0人收藏 • 939人看过
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元,等单位有钱了就搞一个。另查到好像是标准证书微软方面只是提权颜色变了,其它的基于声誉的检测也要等下载量多了才好使,还不如过白好用。

登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...