VB.NET - How do I make a textbox only valid one character per key press?
My project is supposed to mimic an Enigma machine and I need help with the visual interface.
In my program, I need to have a textbox where the user can enter an unlimited number of letters. However, the program also updates other components based on the entered text and displays a visual representation to the user.
For example, when I press the letter "A", the program encodes it to say the letter "S" and displays an image in the interface. However, this encoding is unique for each letter encoding.
As you know, when you keep a letter pressed on the keyboard for a longer time, it continues to write that letter. For example, if I hold down the "A" key, I get "AAAAAAAAAAAAAAAAAAAAA" in my textbox, and it spams the image as it encodes each "A".
My question is, how can I restrict a textbox to accept only one letter per key press, but still allow a double or triple letter? Therefore, I can have a substring of the same characters if I enter them by pressing several times on the keyboard.
I need this to get the encoded leater to light up as long as the input letter is pressed.
If you are using SuppressKeyPress on KeyEventArgs, you can control when the key press is complete. In my example, I am using a textbox to input the control. But this will work with other controls too ...
Dim keyIsDown As Boolean 'marked to give status of keyboard key
Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyDown
If keyIsDown Then 'if key is already down abort
e.SuppressKeyPress = True
Exit Sub
End If
keyIsDown = True 'if key was not already down mark it as down now
End Sub
Private Sub TextBox1_KeyUp(sender As Object, e As KeyEventArgs) Handles TextBox1.KeyUp
keyIsDown = False 'key has traveled up clear the marker
End Sub
Whether or not it is a duplicate key is not something you can learn from key events. But it is available in the basic WM_KEYDOWN message , bit # 30 of the lparam argument will be set to 1. The easiest way to take a look at this message is by overriding the ProcessCmdKey () method. Paste this code into your form class:
Private repeatedKey As Boolean
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
repeatedKey = (msg.LParam.ToInt32 And (1 << 30)) <> 0
Return MyBase.ProcessCmdKey(msg, keyData)
End Function
You can now check this variable in the KeyPressed event handler. I would guess that you want to do something like this:
Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
If repeatedKey Then e.Handled = True
If e.KeyChar = ChrW(22) Then e.Handled = True '' Disable paste
If e.KeyChar = ChrW(8) Then e.Handled = False '' Allow repeating backspace
End Sub
The first line prevents duplicate keys from being visible. The second line disables copy / paste, which is unlikely to be useful in your application. The third line still allows the backspace key to be repeated so that the user can easily correct the error. Keep in mind that I'm just guessing what you want to do here, this is just an example and you probably want to change it.
You can use a boolean flag to determine if the first event has fired keypress
and then cancel any next one keypress
until the event occurs KeyUp
.
Private isKeyHandled As Boolean = False
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) _
Handles TextBox1.KeyPress
e.Handled = Me.isKeyHandled
Me.isKeyHandled = True
End Sub
Private Sub TextBox1_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs) _
Handles TextBox1.KeyUp
Me.isKeyHandled = False
End Sub
Also, for placement, you could add logic to the subclassed TextBox:
Public Class TextBoxEx : Inherits TextBox
Public Property DisableKeyRepetition As Boolean = False
Private isKeyHandled As Boolean = False
Protected Overrides Sub OnKeyPress(ByVal e As KeyPressEventArgs)
MyBase.OnKeyPress(e)
If Me.DisableKeyRepetition Then
e.Handled = Me.isKeyHandled
Me.isKeyHandled = True
End If
End Sub
Protected Overrides Sub OnKeyUp(ByVal e As KeyEventArgs)
MyBase.OnKeyUp(e)
Me.isKeyHandled = False
End Sub
End Class
Then:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.TextBoxEx1.DisableKeyRepetition = True
End Sub