How to extract values ​​of characters used with Shift key using MapVirtualKeyEx API?

jacky Perpète 106 Reputation points
2025-03-02T19:08:04.1533333+00:00

I use the MapVirtualKeyEx api to extract characters from the virtual keys on the keyboard.

Here is the code in VB.

Const MAPVK_VK_TO_CHAR = 2

Dim keyblayoutID As Integer = GetKeyboardLayout(0)

For nb As Integer = 0 To 255
    Dim ScanCode As UInteger = MapVirtualKeyEx(nb, MAPVK_VK_TO_CHAR, keyblayoutID)
    If ScanCode <> 0 Then
        ScanCode = ScanCode And &HFF
        Debug.Print(ChrW(ScanCode) & " - " & Hex(nb))
    End If
Next

Here is a part of the result display

enter image description here

The result displayed is correct.

For OEM virtual keys, I would like to retrieve the character when the shift key is pressed.

Example: Virtual key: 0xBB, currently gives me the character '=', I would like to retrieve the character '+' when the shift key is pressed.

Is it possible to use the API with the value of the virtual code and the meaning of the shift key pressed?

VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,793 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 87,706 Reputation points
    2025-03-03T08:18:57.8466667+00:00

    You can use ToUnicodeEx

    A test in a Button click :

    Imports System.Runtime.InteropServices
    Imports System.Text
    
    Public Class Form1
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function ToUnicodeEx(wVirtKey As UInteger, wScanCode As UInteger, lpKeyState As Byte(),
                                     <Out, MarshalAs(UnmanagedType.LPWStr)> pwszBuff As StringBuilder,
                                     cchBuff As Integer, wFlags As UInteger, dwhkl As IntPtr) As Integer
        End Function
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function GetKeyboardState(lpKeyState As Byte()) As Boolean
        End Function
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function GetKeyboardLayout(idThread As UInteger) As IntPtr
        End Function
    
        <DllImport("User32.dll", SetLastError:=True, CharSet:=CharSet.Unicode)>
        Public Shared Function MapVirtualKeyEx(uCode As UInteger, uMapType As UInteger, dwhkl As IntPtr) As UInteger
        End Function
    
        Private Function GetCharFromVirtualKey(virtualKey As UInteger, shiftPressed As Boolean) As Char
            Dim keyState(255) As Byte
            GetKeyboardState(keyState)
    
            If shiftPressed Then
                keyState(&H10) += &H80 ' Simulate Shift key press
            End If
    
            Dim nScanCode As UInteger = MapVirtualKeyEx(virtualKey, 0, GetKeyboardLayout(0))
            If (nScanCode <> 0) Then
                Dim sb As New StringBuilder(2)
                Dim nResult As Integer = ToUnicodeEx(virtualKey, nScanCode, keyState, sb, sb.Capacity, 0, GetKeyboardLayout(0))
                If nResult > 0 Then
                    Return If(String.IsNullOrEmpty(sb(0)), " ", sb(0))
                Else
                    Return ChrW(0)
                End If
            End If
            Return ChrW(0)
        End Function
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            For nVK As Integer = 0 To 255
                Dim sUnshifted As Char = GetCharFromVirtualKey(CUInt(nVK), False)
                Dim sShifted As Char = GetCharFromVirtualKey(CUInt(nVK), True)
                If sUnshifted <> ChrW(0) And sShifted <> ChrW(0) Then
                    Debug.WriteLine($"VK: {nVK:X2} - Unshifted: '{sUnshifted}' Shifted: '{sShifted}'")
                End If
            Next
        End Sub
    End Class
    
    

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.