Solved Is KeyCode Printable Character? (1 Viewer)

sonic8

AWF VIP
Local time
Today, 02:00
Joined
Oct 27, 2015
Messages
998
Hi!
Is there an easy way to determine whether the KeyCode passed in to a KeyUp event procedure corresponds to a printable character?

When handling the KeyUp event, I want to process the keystrokes for any KeyCode that is actually producing a character in the control, but not any control key such as ESC, TAB, ENTER or cursor/arrow keys.

I'm looking for something as simple as:
Code:
If Not char.IsControl(KeyCode) Then
  '  ProcessKeyCode
End If

Thank you for reading!
Best regards,
Philipp
 

ebs17

Well-known member
Local time
Today, 02:00
Joined
Feb 7, 2020
Messages
1,949

The values of a keyboard key code table could be evaluated like this (without completeness):
Code:
Private Sub Control_KeyUp(KeyCode As Integer, Shift As Integer)
    Select Case KeyCode
        Case 48 To 57, 65 To 90
            Debug.Print "0-9A-Z"
    End Select
End Sub
 

sonic8

AWF VIP
Local time
Today, 02:00
Joined
Oct 27, 2015
Messages
998
The values of a keyboard key code table could be evaluated like this (without completeness):
Thank you. I know the basic principle, but I was looking for completeness.
E.g., your example does neither recognize the numbers on the num pad nor any sign characters like +-*:; etc.
 

ebs17

Well-known member
Local time
Today, 02:00
Joined
Feb 7, 2020
Messages
1,949
the numbers on the num pad

Code:
    96 - 0 in the numeric keypad
    97 - 1 in the numeric keypad
    98 - 2 in the numeric keypad
    99 - 3 in the numeric keypad
    100 - 4 in the numeric keypad
    101 - 5 in the numeric keypad
    102 - 6 in the numeric keypad
    103 - 7 in the numeric keypad
    104 - 8 in the numeric keypad
    105 - 9 in the numeric keypad
    106 - * in the numeric keypad
    107 - + in the numeric keypad
    109 - - in the numeric keypad
    110 - . in the numeric keypad
    111 - / in the numeric keypad
You just have to gather the values a bit.
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Yesterday, 19:00
Joined
Feb 28, 2001
Messages
27,193
Thank you. I know the basic principle, but I was looking for completeness.
E.g., your example does neither recognize the numbers on the num pad nor any sign characters like +-*:; etc.

Your list excludes some things that are traditionally considered printable, such as the TAB key and the ENTER key. Basically, you will need a SELECT CASE with adequate CASE clauses. The solution produced by ebs17 is correct but not complete, but since you using non-standard definitions of what is printable, you will probably have to complete that yourself. The link provided by ebs17 is perfectly adequate for you to go through it to pick out what you want and ignore the stuff you don't want.
 

sonic8

AWF VIP
Local time
Today, 02:00
Joined
Oct 27, 2015
Messages
998
You just have to gather the values a bit.
That's what I wanted to avoid. - I dislike this type of gathering and I dislike code with endless lists of constant values even more.

It appears there is no ready-made solution to this question. Luckily I was able work out an "easy" alternative.

Code:
Private Declare PtrSafe Function GetThreadLocale Lib "Kernel32" () As Long
Private Const MAPVK_VK_TO_CHAR As Long = 2
Private Declare PtrSafe Function MapVirtualKeyA Lib "user32" (ByVal uCode As Long, ByVal uMapType As Long) As Long
Private Declare PtrSafe Function GetStringTypeA Lib "Kernel32" (ByVal LocaleLcId As Long, ByVal dwInfoType As Long, _
                                                                ByVal lpSrcStr As String, ByVal cchSrc As Long, _
                                                                ByVal lpCharType As LongPtr) As Long

Public Function IsPrintableKey(ByVal KeyCode As Integer) As Boolean
    Dim retVal As Boolean
    
    Dim MappedToChar As Long
    MappedToChar = MapVirtualKeyA(KeyCode, MAPVK_VK_TO_CHAR)
    
    If MappedToChar > 0 Then
        Const CT_CTYPE1 As Long = &H1
        Const C1_CNTRL  As Long = &H20
        Dim apiRetVal As Long
        Dim TypeInfo(0) As Integer
    
        apiRetVal = GetStringTypeA(GetThreadLocale(), CT_CTYPE1, Chr(MappedToChar), -1, VarPtr(TypeInfo(0)))
        retVal = Not (TypeInfo(0) And C1_CNTRL) = C1_CNTRL
    End If
    
    IsPrintableKey = retVal
End Function

I didn't really read the documentation beyond the bare minimum required to cobble together this solution. This appears to work for me, but use at your own risk.
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Yesterday, 19:00
Joined
Feb 28, 2001
Messages
27,193
That method uses an API call. It should work, but it seems that you are working very hard to avoid doing the lookup of each character type, a programming step you would only have to do once. But... it is your code and your call.

I will also add that your view of "easy" and my view of "easy" are not the same. But I respect your choice.
 

Users who are viewing this thread

Top Bottom