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