PB热键

来源:互联网 发布:js map用法 编辑:程序博客网 时间:2024/05/21 13:53

在程序中添加一些热键可以让用户更加快速实现某些功能,对于一些熟练的操作人员,他们更容易接受快捷键的操作方式。例如大家熟悉的金山词霸,一般情况下程序处在系统光标区,用户可以通过Ctrl+Alt+F1组合键来切换是否进行屏幕取词。

首先来说一下如何让我们用PowerBuilder编写的程序也能实现这个功能呢?有两种方法:

方法一、本方法在窗口获得焦点的时候,用户按下热键,就可以触发窗口中的事件。

Send ( handle, message#, lowword, long )

参数说明:

handle:长整型,表示一个窗口的系统句柄,可以从handle()函数获得。
message#:就是对应的系统消息,为十进制表示,如:WM_PASTE为0x0302,换算为十进制就是770。
longword:十进制,表示热键的值,具体是由程序员自定义的。

算法是这样的:
??? 高8位字节与低8位字节组成16位字节,然后将它换算成十进制数,即得到所需的热键值。高8位字节值为一些辅助键(Control-0x02、Alt-0x04、Shift-0x01等),低8位字节为使用键的ASCII码,例如F1的ASCII码为112。如果我们定义一个系统热键是Ctrl+Alt+F1,那么该值就是:高八位为辅助键,Ctrl+Alt=0x06,低八位为112,换算成十六进制是0x70,组合得到:0x670,再换算成十进制是1648。同理:Ctrl+Alt+A就是:1601。
long:该数值可以设置为0。
当然,也可以使用外部的API函数,是一样的。该对应的API函数的声明如下:


Function long SendMessageA(long lhWnd,uint uiMsg,long lwMsg,long lwParam) library? "user32.dll"

举例说明:


为窗口上的一个按钮(cb_1)声明一个热键:Ctrl+Alt+F1。查阅winuser.h可以得到:WM_SETHOTKEY为0x0032,换算成十进制就是50。然后为该按钮所在的窗口的open事件写入代码:
long ll_rc
ll_rc=Send(Handle(this), 50, 1648, 0)
if ll_rc<>1 then
? messagebox("Error","Can not register hotkey!")
end if
然后在窗口的Other事件中写入:
IF wparam =61776 THEN //61776为PB中的热键消息,对应windows的SC_HOTKEY
??? cb_1.event clicked()
END IF
此时按下CTRL+Alt+F1就可以触发cb_1的click事件。定义系统热键成功。


又比如:

Send(Handle(dw_whatever), 274, 61472, 0)//最大化dw_whatever,SC_MINIMIZE
Send(Handle(dw_whatever), 274, 61488, 0)//最小化dw_whatever,SC_MAXIMIZE
Send(Handle(dw_whatever), 274, 61728, 0)//恢复原来的状态,SC_RESTORE

方法二、本方法可以实现无论在任何时候,只要用户按下热键,都将触发窗口中的事件。

首先声明如下的外部函数:

FUNCTION Integer GlobalAddAtom(ref string lpString) LIBRARY "kernel32.dll" ALIAS FOR? "GlobalAddAtomA"

参数说明:

lpString是任意的字符串,根据该字符串得到唯一的ID,从而不和其他的应用程序冲突。

FUNCTION ulong RegisterHotKey(ulong hwnd,ulong id,ulong fsModifiers,ulong vk) LIBRARY ??"user32.dll"

参数说明:

hwnd是定义热键的窗口的句柄,由handle()得到。
id是有函数GlobalAddAtom返回的数值(ulong)类型。
fsModifiers是辅助键的编码和。Ctrl为2,Alt为1,Shift为4
vk是虚拟键的ASCII码,如A为65

举例说明:


在窗口中声明一个实例变量ll_mod,保存从GlobalAddAtom获得的唯一ID。
在窗口的Open事件中写入如下的代码:
long ll_rc
string ls_mod

ls_mod="my id"//可以任意定义,是识别这个ID的关键字
ll_mod=GlobalAddAtom(ls_mod)//获得注册成功的唯一ID
ll_rc=RegisterHotKey(Handle(this), ll_mod, 3, 65) //定义热键:Ctrl+Shift+A
if ll_rc=0 then
??? messagebox("Error","Unable to register hotkey!")
end if
在窗口的Other事件中加入如下的代码:
if wparam=ll_mod then
//Do something
end if

如何模拟键盘按键


??? 另外,我们还可以想到,如果我截获用户的按键事件,在该事件中发送特殊意义的按键的代码,就好像替用户按了另外的按键一样,比如,在Excel中按Shift+TAb可以实现和TAB相反方向的移动,我让用户按F12,然后我模拟按Shift+Tab,不也是“热键”吗?嗯,想法不错,我们该如何实现呢?这就要用到一个Api函数,它可以用来模拟按键,是这样声明的:
SUBROUTINE keybd_event(int bvk,int bscan,int dwflags,int dwextrainfo) library? "user32.dll"

参数说明:


bvk:虚拟按键的ASCII码值。
bscan:取值为0即可。
dwflags:取值为0表示按键按下,取值为2表示按键释放。
dwextrainfo:取值为0即可。
举例说明:
keybd_event(44,0,0,0)将当前屏幕上的内容存入到剪贴板中。//44为PrintScreen的ASCII码。
下面几句相当于按下了Ctrl+Alt+F1:
keybd_event(18,0,0,0)//按下了Alt
keybd_event(17,0,0,0)//按下了Ctrl
keybd_event(65,0,0,0)//按下了F1
keybd_event(18,0,2,0)//释放了Alt
keybd_event(17,0,2,0)//释放了Ctrl
keybd_event(65,0,2,0)//释放了F1

现在回过头来看看我们的“热键”的事情。我们已经有了解决的办法,举个例子吧:
在自定义的事件中写入下面的代码(事件的ID为pbm_dwnkey)
Choose Case key
Case KeyF4!
// 模拟按下Shift+Tab键,然后释放
keybd_event(16,0,0,0) // SHIFT Depressed
keybd_event(9,0,0,0) // TAB Depressed
keybd_event(16,0,2,0) // SHIFT Released (CANNOT BE OMITTED)
keybd_event(9,0,2,0) // TAB Released (Can be omitted)

Case KeyF5!
// 模拟按下和释放Tab键
keybd_event(9,0,0,0) // TAB Depressed
keybd_event(9,0,2,0) // TAB Released (Can be omitted)
End Choose

好了,到这里,我们的所有的目标都达到了,现在问题又来了:我现在很难找到某个按键的AScii值,怎么办?这有两个解决办法。
1、使用PowerBuilder提供的asc()函数
2、使用下面的表格查找。