按下某組鍵(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 LongPublic Const GWL_WNDPROC = (-4)
Public Const WM_HOTKEY = &H312
Public AppId As Long
Public AppId1 As LongPublic PrevWndProc As LongFunction 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") '向系統取得第二組可用idlResult = RegisterHotKey(Form1.hwnd, AppId, MOD_CONTROL, vbKey2)
lResult = RegisterHotKey(Form1.hwnd, AppId1, MOD_CONTROL, vbKey3)
'設定兩組熱鍵 分別是Ctrl+2和Ctrl+3
'當按下這兩組按鍵時 系統會傳WM_HOTKEY訊息
'給所熱鍵所註冊的視窗 此時是Form1PrevWndProc = SetWindowLong(Me.hwnd, GWL_WNDPROC, AddressOf WndProc)
'設定新的回呼函式 以攔截訊息
'note: 傳回值PrevWndProc是原來視窗的回呼函數
'WndProc函數放在模組 因為AddressOf只能取得模組下函數的位址
End SubPrivate 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  

解决方案 »

  1.   

    另一个:按下HotKey以叫起視窗 
     
      
      
            
     如何做到在任何一個程式之下,按下某個HotKey組合鍵,便將我們的視窗Activate起來,這便得使用 WM_SETHOTKEY 來達成WM_SETHOTKEY所需的參數如下:
    wParam = (WPARAM) MAKEWORD(vkey, modifiers)   
    lParam = 0 vkey 指的是virtual-key code,它是在低位元組,modifier是以下四種鍵的組合,它是
    在高位元組。HOTKEYF_ALT     ALT key
    HOTKEYF_CONTROL CTRL key
    HOTKEYF_EXT     Extended key
    HOTKEYF_SHIFT   SHIFT          SendMessage()的傳回值有以下的意義:
    -1  hotkey 設定不對
     0  hWnd的指定有誤
     1  成功,而且沒有其他window的HotKey與之相同
     2  成功,但有其他window的HotKey與之相同
    --------------------------------------------------------------------------------
    Option Explicit
    Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
    Const WM_SETHOTKEY = &H32
    Const HOTKEYF_SHIFT = &H1 
    Const HOTKEYF_CONTROL = &H2
    Const HOTKEYF_ALT = &H4
    Const HOTKEYF_EXT = &H8Private Type tInteger
      aint As Integer
    End Type
    Private Type t2Byte
      lByte As Byte
      hByte As Byte
    End Type
    Private ii As tInteger
    Private bb As t2BytePrivate Sub Command1_Click()
    Dim wParam As Long, I As Long'設定ctl-shift-T 為該window的hotkey
    bb.hByte = HOTKEYF_CONTROL Or HOTKEYF_SHIFT
    bb.lByte = vbKeyT
    LSet ii = bbwParam = CLng(ii.aint)
    I = SendMessage(Me.hwnd, WM_SETHOTKEY, wParam, 0)
    If I = 1 Then
       Debug.Print "Ctl-Shift-T 為hotkey"
    Else
       If I = 2 Then
         Debug.Print "有其他Window也用Ctl-Shift-T當Hotkey"
       Else
         Debug.Print "指定失敗"
       End If
    End If
    End Sub  
      

  2.   

    或者用keyb_event API:Const VK_H = 72
    Const VK_E = 69
    Const VK_L = 76
    Const VK_O = 79
    Const KEYEVENTF_EXTENDEDKEY = &H1
    Const KEYEVENTF_KEYUP = &H2
    Private Declare Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
    Private Sub Form_KeyPress(KeyAscii As Integer)
        'Print the key on the form
        Me.Print Chr$(KeyAscii);
    End Sub
    Private Sub Form_Paint()
         'Clear the form
        Me.Cls
        keybd_event VK_H, 0, 0, 0   ' press H
        keybd_event VK_H, 0, KEYEVENTF_KEYUP, 0   ' release H
        keybd_event VK_E, 0, 0, 0  ' press E
        keybd_event VK_E, 0, KEYEVENTF_KEYUP, 0  ' release E
        keybd_event VK_L, 0, 0, 0  ' press L
        keybd_event VK_L, 0, KEYEVENTF_KEYUP, 0  ' release L
        keybd_event VK_L, 0, 0, 0  ' press L
        keybd_event VK_L, 0, KEYEVENTF_KEYUP, 0  ' release L
        keybd_event VK_O, 0, 0, 0  ' press O
        keybd_event VK_O, 0, KEYEVENTF_KEYUP, 0  ' release O
    End Sub