天天看点

PB热键

在程序中添加一些热键可以让用户更加快速实现某些功能,对于一些熟练的操作人员,他们更容易接受快捷键的操作方式。例如大家熟悉的金山词霸,一般情况下程序处在系统光标区,用户可以通过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、使用下面的表格查找。

继续阅读