Search code examples
vbapowerpoint

Use MapVirtualKeyA with Shift and Ctrl Alt


I have found this page for a function that converts a given keycode in to the corresponding charcater, depending on the system language and keyboard layout. I tested it (in PowerPoint using VBA) and it works, except I don't know how to tell the function that Shift or Ctrl + Alt are being pressed and therefore the function should then return a different result. Say for instance: The keycode 51 corresponds to the number 3, when I pass it to the function, it returns 3. But what if the user is pressing the Shift key? It should return # (or a different character, depending on the keyboard layout, etc.)

So, I know how to check if Shift or Ctrl + Alt are being pressed, but what I don't know is how to tell the function that the keys are being pressed.

I put the following code in a module:

Public Declare PtrSafe Function MapVirtualKeyA Lib "user32" (ByVal uCode As Long, ByVal uMapType As Long) As Integer

And then in the slide's code I put:

Sub test()

    MsgBox Chr(MapVirtualKeyA(vbKey3, 2)) ' always returns 3, even when pressing shift or ctrl + alt

End Sub

I want to know what I have to change in my code so that function knows that Shift or Ctrl + Alt are being pressed.

Thanks in advance.


Solution

  • You could use ToAscii API.

    Option Explicit
    
    Private Declare PtrSafe Function ToAscii Lib "user32" (ByVal uVirtKey As Long, ByVal uScanCode As Long, lpbKeyState As Byte, lpChar As LongPtr, ByVal uFlags As Long) As Long
    Private Declare PtrSafe Function MapVirtualKeyA Lib "user32" (ByVal uCode As Long, ByVal uMapType As Long) As Long
    
    Sub Test()
        Debug.Print GetCharacterFromVK(uVirtKey:=vbKey3, shiftDown:=True)
    End Sub
    
    Function GetCharacterFromVK(uVirtKey As Long _
        , Optional shiftDown As Boolean = False _
        , Optional ctrlDown As Boolean = False _
        , Optional altDown As Boolean = False _
    ) As String
        'https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
        Const VK_SHIFT = &H10   'SHIFT key
        Const VK_CONTROL = &H11 'CTRL key
        Const VK_MENU = &H12    'ALT key
        '
        Dim keyState(0 To 255) As Byte
        Dim buffer As String: buffer = Space$(2)
        '
        'Set Key States by setting the high-order bit of the byte
        If shiftDown Then keyState(VK_SHIFT) = &H80
        If ctrlDown Then keyState(VK_CONTROL) = &H80
        If altDown Then keyState(VK_MENU) = &H80
        '
        'Populate buffer
        Select Case ToAscii(uVirtKey, MapVirtualKeyA(uVirtKey, 0), keyState(0), ByVal StrPtr(buffer), 0)
        Case 0
            'The specified virtual key has no translation for the current state of the keyboard
            GetCharacterFromVK = vbNullString
        Case 1
            'One character was copied to the buffer
            GetCharacterFromVK = Left$(buffer, 1)
        Case 2
            'Two characters were copied to the buffer
            GetCharacterFromVK = buffer
        End Select
    End Function