• 按下某組鍵(HotKey)便執行某程式

在Dos的年代,我們常會以攔截中斷向量的方式,做到按下某個hotkey而自動執行某個程式,在Window呢,也可以,不過它是用RegisterHotkey API來完成。

使用RegisterHotkey的概念是,它會定義一組按鍵的組合,當使用者不管在哪個程式之中,按下Window有註冊的HotKey時,OS會傳送WM_HOTKEY 的訊息給待接收該訊息的Window,而該Window收到WM_HOTKEY時,便可知道有本身Thread所定義的HotKey被按下,於是可以從wParam, lParam來得知是哪一組HotKey被按下。

 RegisterHotKey(
    ByVal hwnd As Long ,        //接收Hotkey的Window
    ByVal idHotKey as Long,     // identifier of hot key,range 0x0000 through 0xBFFF
    ByVal Modifiers As Long,    // 定義alt shift control等的組合
    ByVal uVirtKey As Long      // virtual-key code
   )

 WM_HOTKEY 參數的定義
 idHotKey =  wParam;                 // identifier of hot key
 Modifiers = (UINT) LOWORD(lParam);  // key-modifier flags
 uVirtKey = (UINT) HIWORD(lParam);   // virtual-key code

所以了,除了設定RegisterHotkey外,另要使用SubClassing的技巧才會得知HotKey被按下;最後,程式結束前要使用UnRegisterHotkey將HotKey的定義取消掉。

以下程式功能是:不管在哪個程式中,只要按下CTRL+1或CTRL+2 便執行NotePad


'以下在.Bas
Option Explicit

'用以告訴系統當這個視窗的msg事件發生時 執行lpPrevWndFunc
Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal _
lpPrevWndFunc As Long, _
ByVal hwnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
'lpPrevWndFunc執行函數的位址
'hwnd 就是視窗的hwnd屬性
'Msg就是訊息 例如按下滑鼠右鍵 最大化....
'wParam,lParam會因Msg不同而有不同的用途

'取得可用的id
Declare Function GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA" (ByVal lpString As String) As Integer
'lpString 傳入任意字串 傳回值為可用的id

'用以設定視窗的程序
Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" ( _
ByVal hwnd As Long, _
ByVal nIndex As Long, _
ByVal dwNewLong As Long) As Long
'hwnd 就是所要設定視窗的hwnd屬性
'nIndex 是要設定的程序
'dwNewLong  所指定的程序(nIndex)所要執行的動作

'用以向系統註冊熱鍵 當熱鍵按下時 系統會將WM_HOTKEY這個訊息傳過來
Declare Function RegisterHotKey Lib "user32" (ByVal hwnd As Long, _
ByVal id As Long, _
ByVal fsModifiers As Long, _
ByVal vk As Long) As Long
'hwnd 就是視窗的hwnd屬性
'id可以隨便填,只要不重複的話...保險起見是使用GlobalAddAtom取得未使用的id
'fsModifiers 指定按下ALT CTRL 或SHIFT鍵
Public Const MOD_ALT = &H1
Public Const MOD_CONTROL = &H2
Public Const MOD_SHIFT = &H4
'vk是按鍵的VK碼

'取消熱鍵
Declare Function UnregisterHotKey Lib "user32" (ByVal hwnd As Long, ByVal id As Long) As Long

Public Const GWL_WNDPROC = (-4)
Public Const WM_HOTKEY = &H312


Public AppId As Long
Public AppId1 As Long

Public PrevWndProc As Long

Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Dim lResult As Long
If uMsg = WM_HOTKEY Then '當熱鍵按下時
    Form1.WindowState = 0
    Form1.Show
    If wParam = AppId1 Then '當wParam=第二組id時 是按下第二組熱鍵
        Form1.Caption = "你按Control+3"
        Shell "notepad", vbNormalFocus
    ElseIf wParam = AppId Then '當wParam=第一組id時 是按下第一組熱鍵
        Form1.Caption = "你按Control+2"
        Shell "notepad", vbNormalFocus
    End If
Else
    WndProc = CallWindowProc(PrevWndProc, hwnd, uMsg, wParam, lParam)
    '其他訊息用原來的回呼函數處理
End If
End Function
 
'以下在 Form
Option Explicit
Private Sub Form_Load()
Dim lResult As Long
AppId = GlobalAddAtom("Honey") '向系統取得第一組可用id
AppId1 = GlobalAddAtom("Honey1") '向系統取得第二組可用id

lResult = RegisterHotKey(Form1.hwnd, AppId, MOD_CONTROL, vbKey2)
lResult = RegisterHotKey(Form1.hwnd, AppId1, MOD_CONTROL, vbKey3)
'設定兩組熱鍵 分別是Ctrl+2和Ctrl+3
'當按下這兩組按鍵時 系統會傳WM_HOTKEY訊息
'給所熱鍵所註冊的視窗 此時是Form1

PrevWndProc = SetWindowLong(Me.hwnd, GWL_WNDPROC, AddressOf WndProc)
'設定新的回呼函式 以攔截訊息
'note: 傳回值PrevWndProc是原來視窗的回呼函數
'WndProc函數放在模組 因為AddressOf只能取得模組下函數的位址
End Sub

Private Sub Form_Unload(Cancel As Integer)
Dim lResult As Long
lResult = SetWindowLong(Me.hwnd, GWL_WNDPROC, PrevWndProc)
'結束時歸還原來的回呼函數 不然會當機

lResult = UnregisterHotKey(Me.hwnd, AppId)
lResult = UnregisterHotKey(Me.hwnd, AppId1)
'取消熱鍵
End Sub

  • 相關資訊

  GlobalAddAtom

  UnregisterHotKey

  RegisterHotKey

  Keyboard Input Overview

  Keyboard Input Functions

  SetWindowLong

  CallWindowProc

  GetWindowLong

  • 文件出處

  cww,Honey修改

VB心得筆記歡迎各位的指教,如果您有任何文章或資料願意提供給我們的,請來信到VBNote

如果對本站有任何建議,歡迎來信給Honey,我們會盡快給您答覆