在VBA中,有一种很好的方式来接收WM_HOTKEY消息或任何其他方式来模拟Excel的Application.OnKey

时间:2019-11-18 21:24:37

标签: vba winapi powerpoint

发表了很长的文章,所以先tl;博士: 是否有适当的方法可以在VBA中接收WM_HOTKEY消息,或者有其他适当的方法来操作单个键盘快捷键来调用您自己的子例程?

我目前正在为Powerpoint *编写一个外接程序,它具有自己的功能区,但我也希望能够通过键盘快捷键来调用子例程。在Excel加载项中,我使用的是 Application.OnKey ,可惜在Powerpoint中不可用。 (*在工作中个人使用以提高生产力;可能想与我的团队分享,但没有专业/商业发展)

在对Windows API,键盘挂钩等进行了大量研究之后,我尝试的每种方法都遇到了很多问题。

1。键盘挂钩 我首先尝试了一个键盘钩子,该钩子分析了键盘输入,并且如果按下了特定的按钮组合(例如CTRL + L之类的东西),就会执行某事。不幸的是,我遇到了Windows keyboard hook API in VBA causes infinite loop in PowerPoint这里描述的相同问题。

基本上,问题在于,如果在Powerpoint的对话框窗口中输入文本,则使用WH_KEYBOARD挂钩会导致Powerpoint崩溃(例如,当您尝试按链接文章中的描述命名自己的新设计时)。也许存在引用问题(窗口实例,挂钩回调等)? 当我尝试WH_CBT挂钩时,不会发生此问题,但这会导致不同的问题。例如,当挂钩运行时,我无法切换正在运行的应用程序(即,单击任务栏中的图标无效)。

由于这是我第一次接触Windows API的SetWindowsHookExA及其附带的所有内容,因此我陷入了僵局。

2。注册热键 第一种方法还表明,正确注册要用作快捷键的组合键已经是一项艰巨的任务。这就是让我研究易于设置的RegisterHotKey的原因。在对Windows的消息队列进行了大量研究之后,我了解到我必须实现一种机制来侦听消息队列并注册WM_HOTKEY消息。 我想出了一些基本可行的方法(请参见下面的代码),但不幸的是,Powerpoint的速度降低了很多,这似乎是由DoEvents和我用于PeekMessage的永无止境的循环引起的。

Option Explicit

Private Const MOD_ALT = &H1
Private Const MOD_CONTROL = &H2
Private Const MOD_SHIFT = &H4
Private Const PM_REMOVE = &H1
Private Const WM_HOTKEY = &H312
Private Const KC = 104
Private Const KC_ALT = 105
Private Const KC_CTRL = 106
Private Const VK_SNAPSHOT = &H2C

' Needed for MSG Structure
Private Type POINTAPI
    x As Long
    y As Long
End Type

Private Type Msg
    hwnd As Long
    message As Long
    wParam As Long
    lParam As Long
    time As Long
    pt As POINTAPI
End Type

Private Declare Function RegisterHotKey Lib "user32" ( _
                                ByVal hwnd As Long, _
                                ByVal id As Long, _
                                ByVal fsModifiers As Long, _
                                ByVal vk As Long) As Long

Private Declare Function UnregisterHotKey Lib "user32" (ByVal hwnd As Long, ByVal id As Long) As Long

Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" ( _
                                lpMsg As Msg, _
                                ByVal hwnd As Long, _
                                ByVal wMsgFilterMin As Long, _
                                ByVal wMsgFilterMax As Long, _
                                ByVal wRemoveMsg As Long) As Long

Private Declare Function WaitMessage Lib "user32" () As Long

Private bCancel As Boolean

Private Sub SetHotKey()
    Call RegisterHotKey(0, KC_ALT, MOD_ALT, VK_SNAPSHOT)
End Sub
Private Sub UnSetHotKey()
    Call UnregisterHotKey(0, KC_ALT)
End Sub

Private Sub ProcessMessages()
    Dim message As Msg

    Dim ModHwnd As Long
    ModHwnd = GetModuleHandle(vbNullString)

    'loop until bCancel is set to True
    Do While Not bCancel
        'wait for a message
        WaitMessage
        'check if it's a HOTKEY-message
        If PeekMessage(message, 0, WM_HOTKEY, WM_HOTKEY, PM_REMOVE) Then
            'here I would check which hotkey was triggered and execute a macro depending on which
            Call TestSub
            Debug.Print time(), "called"
        End If
        'let the operating system process other events
        DoEvents
    Loop
End Sub

是否有适当的方法可以在VBA中接收WM_HOTKEY消息,或者有其他适当的方法来操作单个键盘快捷键来调用自己的子例程? 我知道有一个名为Shortcut Manager for PowerPoint的程序,该程序也有一个SDK可以将其实现到您自己的加载项中,所以这可能是我最终要使用的,但是可以更灵活地拥有自己的代码,而不必依赖第三方软件(也更难卖给IT部门)。

任何帮助将不胜感激。如果需要更多信息或代码示例(用于键盘挂钩方法或其他方法),请告诉我。

最诚挚的问候

菲利普

0 个答案:

没有答案