Consulting

Results 1 to 8 of 8

Thread: Solved: How to get Last Key or Key-Combo Pressed (Not Event)

  1. #1

    Solved: How to get Last Key or Key-Combo Pressed (Not Event)

    Hi

    i'd like to get the last key or key-combo pressed.
    Windows API method is fine, or VBA.

    Note: I need to get this several seconds AFTER they key is pressed. I do not care about the current state of the key. I'm not trying to run a macro in response to a keypress. So, getasynckeystate and OnKey are NOT the appropriate solutions for this. The key might be pressed while a macro is running, and i want to allow the macro to finish running without interruption, and only get the last key pressed after the key has already been released, possibly several seconds before.

    I'm not trying to detect any specific key, just want to get last keypress, whatever key it was.

    The method should be able to detect special keys, like home, end, left, right, down, and up.

    It should also recognize key combinations, like control alt and shift.

    Using Excel 2007.

    Thanks!

    also posted here:
    excelforum.com/excel-programming-vba-macros/850033-how-to-get-last-key-or-key-combo-pressed-not-event.html

  2. #2

    Solution

    hi

    not sure how to mark this solved, but I got it. The neat thing about this solution is that if you put a loop around it, you can get all keystrokes in the buffer, not just the most recent. Even better, you can get mousecklicks.

    The answer is the API function, PeekMessage.

    Here's the declaration:
    Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (ByRef lpMsg As MSG, ByVal hWnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    Example call:
    lResult = PeekMessage(msgMessage, hWnd, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE + PM_NOYIELD)
    You also need the TranslateMessage and FindWindow fuctions, constants, message data-structures, and a few other bits.

    Cheers!

  3. #3

  4. #4
    VBAX Sage
    Joined
    Apr 2007
    Location
    United States
    Posts
    8,729
    Location
    Up in thread tools above your first post, there's a Solved button

    Interesting

    Thanks


    Paul
    Last edited by Paul_Hossler; 08-04-2012 at 08:43 AM.

  5. #5
    VBAX Guru Kenneth Hobs's Avatar
    Joined
    Nov 2005
    Location
    Tecumseh, OK
    Posts
    4,956
    Location
    [VBA]hwnd = Application.Hwnd[/VBA]

  6. #6
    VBAX Sage
    Joined
    Apr 2007
    Location
    United States
    Posts
    8,729
    Location
    Ken -- Thanks,

    Paul

  7. #7
    Note, this only gets key and mouse events that were waiting to be processed while your macro was running. Key/mouse events that were processed normally before your macro blocked input will not be returned by this method, as they are long gone.

    You actually do not need the FindWindow API function, since VBA provides a built-in way to get the Excel window handle, provided by Ken above. Thanks Ken!

  8. #8
    VBAX Sage
    Joined
    Apr 2007
    Location
    United States
    Posts
    8,729
    Location
    How can you tell if it's a Shifted-q?

    Now if I run the loop, the pressing the shift key get's 'peeked'


    [VBA]
    Option Explicit
    'Type to hold the coordinates of the mouse pointer
    Private Type POINTAPI
    x As Long
    y As Long
    End Type
    'Type to hold the Windows message information
    Private Type MSG
    hWnd As Long
    'the window handle of the app
    message As Long
    'the type of message (e.g. keydown)
    wParam As Long
    'the key code
    lParam As Long
    'not used
    time As Long
    'time when message posted
    pt As POINTAPI
    'coordinate of mouse pointer
    End Type

    'Look in the message buffer for a message
    Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (ByRef lpMsg As MSG, ByVal hWnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long

    'Translate the message from a key code to a ASCII code
    Private Declare Function TranslateMessage Lib "user32" (ByRef lpMsg As MSG) As Long

    'Windows API constants
    Private Const WM_CHAR As Long = &H102
    Private Const WM_KEYDOWN As Long = &H100
    Private Const PM_REMOVE As Long = &H1
    Private Const PM_NOYIELD As Long = &H2
    'Check for a key press
    Public Function CheckKeyboardBuffer() As String

    'Dimension variables
    Dim msgMessage As MSG
    Dim hWnd As Long
    Dim lResult As Long

    'Get the window handle of this application
    hWnd = Application.hWnd

    'See if there are any "Key down" messages
    lResult = PeekMessage(msgMessage, hWnd, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE + PM_NOYIELD)

    'If so ...
    If lResult <> 0 Then

    '... translate the key-down code to a character code,
    'which gets put back in the message queue as a WM_CHAR message ...
    lResult = TranslateMessage(msgMessage)

    '... and retrieve that WM_CHAR message
    lResult = PeekMessage(msgMessage, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE + PM_NOYIELD)

    'Return the character of the key pressed, ignoring shift and control characters
    CheckKeyboardBuffer = msgMessage.wParam
    End If

    End Function

    Sub test()
    Dim i As Long
    Dim s As String
    s = ""
    i = 1
    Do While Len(s) = 0
    ActiveSheet.Cells(i, 1).Value = i
    i = i + 1
    s = CheckKeyboardBuffer

    Loop

    MsgBox s
    End Sub
    [/VBA]

    Paul

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •