Search code examples
vb.netvisual-studio-2010keypresskeydownkeyup

How to make `KeyDown` and `KeyUp` ignore modifier keys and how to print the key to a string in Visual Basic


In VB, I usually put my code for when keys are pressed in the KeyDown and KeyUp subs. However, I would prefer it if this code could be put in the Timer_Tick.

So I implemented the method shown below in the code where the program creates a List (Of Keys) upon starting, and then the KeyDown and KeyUp subs adds or removes the Keys from the List.

To debug, the program draws a string of all of the Keys in the Paint sub which is refreshed every frame.

This method of handling key presses works fine mostly, except for the following problems I've encountered:

  1. keysPressed(i).ToString doesn't draw , or any non-letter characters as I would expect it to. Instead, it draws Oemcomma. Is there a way to fix this? (I know it's not important for now as it's just a debugging feature, but I would still like to know how to get around this for the future)

  2. The modifier keys are a nuisance for me. After being pressed, the KeyUp sub isn't called once released (I suspect this is because they modify themselves) and some keys aren't detected at all (like fn).

    In addition, if I were to press and hold A, then press Shift and then release A, then KeyUp for A isn't called (as it has been modified) which means that Keys.A is not removed from my list. I would like KeyUp for A to be called whether or not A has been modified.

    Is there a way to tell VB to ignore all modifier keys in the KeyDown and KeyUp subs? (here I mean ignore as in ignore all modifications, despite still being able to detect the modifier key being pressed)

  3. When I press a load of buttons (over 10), then it seems that they are not all detected at once (only 6 or so appear in the list). Is there a way to avoid this bug, or is this a limitation of using VB?

    In fact, occasionally, when I press a few more buttons whilst holding another one, the one I was holding seems to be 'cancelled out' by being removed from the list until I release. (There are quite a few bugs which appear when I press a lot of keys).

  4. When I press multiple keys down at the same time, what exactly happens? Is KeyDown called multiple times for each key, or is it actually possible for a KeyDown to represent multiple keys? In which case, what exactly would happen in my program?

Public Class Form1
    Dim keysPressed As New List(Of Keys)

    Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown

        If Not keysPressed.Contains(e.KeyData) Then keysPressed.Add(e.KeyData)

        If e.KeyData = Keys.Escape Then End
    End Sub

    Private Sub Form1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp

        keysPressed.Remove(e.KeyData)
    End Sub

    Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles screenTimer.Tick
        Refresh()
    End Sub

    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

        For i = 0 To keysPressed.Count - 1
            e.Graphics.DrawString(keysPressed(i).ToString, New System.Drawing.Font("Arial", 10), Brushes.Black, 10 * i, 540)
        Next
    End Sub
End Class

Solution

    1. No, code it yourself. It's great the way it is for your purposes functionality-wise, and debugging wise, I prefer it that way, so maybe you should take my advice and not fight it. Consider looking at a trace of all the keystrokes and seeing , mixed in with a bunch of otherwise sensible seeming key names. Imagine Ctrl+, and etc. (when making this code you really need to debug or console trace every event)

    2. So rip apart the keydata by taking out the modifiers. There isn't a way to change the way the keydatas come to you. It's inconvenient for some purposes, but useful for some others.

    3. It's your keyboard's fault. In general you can't press many keys at once. It has nothing to do with VB or .net

    4. Precisely what you expect happens; one keydown can only represent one key. If you can even find a way to store information about more than one key inside the KeyEventArgs, then you're a magician

    Despite not using winforms events, the code here does what you're attempting: https://github.com/TASVideos/BizHawk/tree/master/BizHawk.Client.EmuHawk/Input ; It receives key events in bunches, but processing them is more or less the same as if they came from winforms. But believe it or not, we actually have to go to effort to reconstruct the way winforms delivers them with the modifiers combined with the keystrokes (see point #2)--not because of compatibility with old winforms code, but because that's the way we prefer it.