vbAccelerator - Contents of code file: cRegHotKey.cls

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "cRegHotKey"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

Private Const IDHOT_SNAPWINDOW = -1          '/* SHIFT-PRINTSCRN  */
Private Const IDHOT_SNAPDESKTOP = -2         '/* PRINTSCRN        */
Public Enum EHKModifiers
   MOD_ALT = &H1&
   MOD_CONTROL = &H2&
   MOD_SHIFT = &H4&
   MOD_WIN = &H8&
End Enum
Private Const WM_HOTKEY = &H312&
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 GlobalAddAtom Lib "kernel32" Alias "GlobalAddAtomA"
 (ByVal lpString As String) As Integer
Private Declare Function GlobalDeleteAtom Lib "kernel32" (ByVal nAtom As
 Integer) As Integer
' To Report API errors:
Private Const FORMAT_MESSAGE_ALLOCATE_BUFFER = &H100
Private Const FORMAT_MESSAGE_ARGUMENT_ARRAY = &H2000
Private Const FORMAT_MESSAGE_FROM_HMODULE = &H800
Private Const FORMAT_MESSAGE_FROM_STRING = &H400
Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
Private Const FORMAT_MESSAGE_IGNORE_INSERTS = &H200
Private Const FORMAT_MESSAGE_MAX_WIDTH_MASK = &HFF
Private Declare Function FormatMessage Lib "kernel32" Alias "FormatMessageA"
 (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal
 dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments
 As Long) As Long
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Function SendMessageByLong Lib "user32" Alias "SendMessageA"
 (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As
 Long) As Long
Private Const WM_SYSCOMMAND = &H112
Private Const SC_RESTORE = &HF120
Private Declare Function IsIconic Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As Long) As
 Long
Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long)
 As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal
 nCmdShow As Long) As Long
Private Const SW_SHOW = 5

' Implementation
Private Type tHotKeyInfo
   sName As String
   sAtomName As String
   lID As Long
   eKey As KeyCodeConstants
   eModifiers As EHKModifiers
End Type
Private m_tAtoms() As tHotKeyInfo
Private m_iAtomCount As Long
Private m_hWnd As Long

Public Event HotKeyPress(ByVal sName As String, ByVal eModifiers As
 EHKModifiers, ByVal eKey As KeyCodeConstants)

Implements ISubclass

Public Sub Attach(ByVal hwndA As Long)
   Clear
   If (hwndA <> 0) Then
      m_hWnd = hwndA
      AttachMessage Me, m_hWnd, WM_HOTKEY
   End If
End Sub
Public Sub Clear()
Dim i As Long
   ' Remove all hot keys and atoms:
   For i = m_iAtomCount To 1 Step -1
      UnregisterKey m_tAtoms(i).sName
   Next i
   ' Stop subclassing:
   If (m_hWnd <> 0) Then
      DetachMessage Me, m_hWnd, WM_HOTKEY
      m_hWnd = 0
   End If
End Sub
Public Sub RegisterKey( _
      ByVal sName As String, _
      ByVal eKey As KeyCodeConstants, _
      ByVal eModifiers As EHKModifiers _
   )
Dim lID As Long
Dim lErr As Long
Dim lR As Long
Dim sError As String
Dim sMsg As String
Dim i As Long
Dim sAtomName As String

   ' Check for valid user name:
   If Len(sName) > 32 Then
      Err.Raise vbObjectError + 1048 + 3, App.EXEName & ".cRegHotKey", "Key
       Name too long (max 32 characters)."
      Exit Sub
   Else
      For i = 1 To m_iAtomCount
         If (m_tAtoms(i).sName = sName) Then
            Err.Raise vbObjectError + 1048 + 4, App.EXEName & ".cRegHotKey",
             "The Key Name '" & sName & "' is already registered."
            Exit Sub
         End If
      Next i
   End If

   ' Modify the user supplied name to get a more random system name:
   sAtomName = sName & "_" & App.EXEName & "_" & GetTickCount()
   If (Len(sAtomName) > 254) Then
      sAtomName = Left$(sAtomName, 254)
   End If

   ' Create a new atom:
   lID = GlobalAddAtom(sAtomName)
   If (lID = 0) Then
      lErr = Err.LastDllError
      sError = WinError(lErr)
      sMsg = "Failed to add GlobalAtom"
      If (sError <> "") Then
         sMsg = sMsg & " [" & sError & "]"
      End If
      Err.Raise vbObjectError + 1048 + 2, App.EXEName & ".cRegHotKey", sMsg
   Else
      ' We have added the atom, now try to Register the
      ' key:
      lR = RegisterHotKey(m_hWnd, lID, eModifiers, eKey)
      If (lR = 0) Then
         lErr = Err.LastDllError
         ' Remove the atom:
         GlobalDeleteAtom lID
         ' Raise the error:
         WinError lErr
         sError = WinError(lErr)
         sMsg = "Failed to Register Hot Key"
         If (sError <> "") Then
            sMsg = sMsg & " [" & sError & "]"
         End If
         Err.Raise vbObjectError + 1048 + 3, App.EXEName & ".cRegHotKey", sMsg
      Else
         ' Succeeded in adding the hot key:
         m_iAtomCount = m_iAtomCount + 1
         ReDim Preserve m_tAtoms(1 To m_iAtomCount) As tHotKeyInfo
         With m_tAtoms(m_iAtomCount)
            .sName = sName
            .sAtomName = sAtomName
            .lID = lID
            .eModifiers = eModifiers
            .eKey = eKey
         End With
      End If
         
   End If
End Sub
Public Sub UnregisterKey( _
      ByVal sName As String _
   )
Dim lIndex As Long
Dim i As Long
   lIndex = AtomIndex(sName)
   If (lIndex > 0) Then
      ' Unregister the key:
      UnregisterHotKey m_hWnd, m_tAtoms(lIndex).lID
      ' Unregister the atom:
      GlobalDeleteAtom m_tAtoms(lIndex).lID
      ' Remove from internal array:
      If (m_iAtomCount > 1) Then
         For i = lIndex To m_iAtomCount - 1
            LSet m_tAtoms(lIndex) = m_tAtoms(lIndex + 1)
         Next i
         m_iAtomCount = m_iAtomCount - 1
         ReDim Preserve m_tAtoms(1 To m_iAtomCount) As tHotKeyInfo
      Else
         m_iAtomCount = 0
         Erase m_tAtoms
      End If
   End If
End Sub
Private Property Get AtomIndex(ByVal sName As String) As Long
Dim i As Long
   For i = 1 To m_iAtomCount
      If (m_tAtoms(i).sName = sName) Then
         AtomIndex = i
         Exit Property
      End If
   Next i
   Err.Raise vbObjectError + 1048 + 1, App.EXEName & ".cRegHotKey", "No hot key
    registered under the name '" & sName & "'"
End Property

Private Function WinError(ByVal lLastDLLError As Long) As String
Dim sBuff As String
Dim lCount As Long
    
   ' Return the error message associated with LastDLLError:
   sBuff = String$(256, 0)
   lCount = FormatMessage( _
     FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, _
     0, lLastDLLError, 0&, sBuff, Len(sBuff), ByVal 0)
   If lCount Then
      WinError = Left$(sBuff, lCount)
   End If
    
End Function

Public Sub RestoreAndActivate(ByVal hwnd As Long)
   If (IsWindowVisible(hwnd) = 0) Then
      ShowWindow hwnd, SW_SHOW
   End If
   If (IsIconic(hwnd) <> 0) Then
      SendMessageByLong hwnd, WM_SYSCOMMAND, SC_RESTORE, 0
   End If
   SetForegroundWindow hwnd
End Sub

Private Sub Class_Terminate()
   Clear
End Sub

Private Property Let ISubclass_MsgResponse(ByVal RHS As SSubTimer.EMsgResponse)
   ' ...
End Property

Private Property Get ISubclass_MsgResponse() As SSubTimer.EMsgResponse
   ISubclass_MsgResponse = emrPreprocess
End Property

Private Function ISubclass_WindowProc(ByVal hwnd As Long, ByVal iMsg As Long,
 ByVal wParam As Long, ByVal lParam As Long) As Long
Dim i As Long
Dim lIndex As Long

   If (iMsg = WM_HOTKEY) Then
      ' Interpret the hotkey.  wParam is the id, the
      ' loword of lParam is the key modifier and the
      ' hiword of lParam is the key code:
      Select Case wParam
      Case IDHOT_SNAPWINDOW
         RaiseEvent HotKeyPress("Window Snapshot", MOD_SHIFT, vbKeySnapshot)
      Case IDHOT_SNAPDESKTOP
         RaiseEvent HotKeyPress("Desktop Snapshot", 0, vbKeySnapshot)
      Case Else
         ' Try to find id:
         For i = 1 To m_iAtomCount
            If (m_tAtoms(i).lID = wParam) Then
               lIndex = i
               Exit For
            End If
         Next i
         If (lIndex <> 0) Then
            RaiseEvent HotKeyPress(m_tAtoms(lIndex).sName,
             m_tAtoms(lIndex).eModifiers, m_tAtoms(lIndex).eKey)
         Else
            ' What has happened?
            RaiseEvent HotKeyPress("Unknown HotKey", (lParam And &HFFFF&),
             (lParam \ &H10000))
         End If
      End Select
   End If
End Function