0

I want a TextBox to only accept some specific characters by using the KeyDown event. I've already got it working, except for one character, the single quote. To get the character that will be written I use (char)e.KeyValue which works for all the characters except the quote (it gives Û). I know I could just use e.KeyCode but it's value is Keys.Oem4, which AFAIK might be different across systems.

Is there any way of consistently detecting a single quote key press?

Code snippet:

char c = (char)e.KeyValue;
char[] moves = { 'r', 'u', ..., '\'' };

if (!(moves.Contains(c) || e.KeyCode == Keys.Back || e.KeyCode == Keys.Space))
{
    e.SuppressKeyPress = true;
}
Felipe
  • 336
  • 8
  • 19
  • The `KeyPress` event (which I think [is WM_CHAR](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646276(v=vs.85).aspx)) uses `KeyPressEventArgs`, which has a `KeyChar` property that's what you're looking for. If that event does what you need, you could use that. – 15ee8f99-57ff-4f92-890c-b56153 Jun 16 '17 at 15:00
  • What @EdPlunkett said. `KeyDown` and `KeyEventArgs` only give you virtual key codes, not actual characters (that they often coincide in value so the cast works is just that: coincidental). The virtual key code for the key that produces a single quote differs by layout. The problem is not with `KeyCode`; `KeyValue` isn't universal either. – Jeroen Mostert Jun 16 '17 at 15:01
  • @EdPlunkett That would do it, but I need to suppress the key press, which is only possible in the `KeyDown` event. – Felipe Jun 16 '17 at 15:11
  • @Pipe And KeyDown is raised first, of course. Hm. `e.Handled = true;` in `KeyPress` won't do what you need? – 15ee8f99-57ff-4f92-890c-b56153 Jun 16 '17 at 15:13
  • @EdPlunkett Nope – Felipe Jun 16 '17 at 15:23
  • What do you need to do? Anyway, what about converting keycode to character with [MapViertualKey](https://stackoverflow.com/a/320878/424129)? The KeyConverter suggestion farther down is useless; you can already get "Oem7". – 15ee8f99-57ff-4f92-890c-b56153 Jun 16 '17 at 15:28
  • OK, [this answer works](https://stackoverflow.com/a/38787314/424129). At least, `KeyCodeToUnicode(e.KeyData | e.Modifiers)` is returning `"'\'"` when I give it a single quote. – 15ee8f99-57ff-4f92-890c-b56153 Jun 16 '17 at 15:32
  • @EdPlunkett That works! Thanks a ton! – Felipe Jun 16 '17 at 15:48

2 Answers2

2

I have been using this for a long time. It handles single quotes just fine. e.KeyChar == 39 '\'' and e.Handled = true behaves exactly as you would expect. I tested it with the KeyPress event and works there too.

    protected override void OnKeyPress(KeyPressEventArgs e)
    {
        base.OnKeyPress(e);
        if (e.KeyChar == (char)8) // backspace
            return;
        if (e.KeyChar == (char)3) // ctrl + c
            return;
        if (e.KeyChar == (char)22) // ctrl + v
            return;
        typedkey = true;
        if (_allowedCharacters.Count > 0) // if the string of allowed characters is not empty, skip test if empty
        {
            if (!_allowedCharacters.Contains(e.KeyChar)) // if the new character is not in allowed set,
            {
                e.Handled = true; // ignoring it
                return;
            }
        }
        if (_disallowedCharacters.Count > 0) // if the string of allowed characters is not empty, skip test if empty
        { 
            if (_disallowedCharacters.Contains(e.KeyChar)) // if the new character is in disallowed set,
            {
                e.Handled = true; // ignoring it
                return;
            }
        }
    }
Greg
  • 106
  • 3
0

As @EdPlunkett suggested, this answer works for me:

[DllImport("user32.dll")]
static extern bool GetKeyboardState(byte[] lpKeyState);

[DllImport("user32.dll")]
static extern uint MapVirtualKey(uint uCode, uint uMapType);

[DllImport("user32.dll")]
static extern IntPtr GetKeyboardLayout(uint idThread);

[DllImport("user32.dll")]
static extern int ToUnicodeEx(uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl);


public static string KeyCodeToUnicode(System.Windows.Forms.Keys key)
{
    byte[] keyboardState = new byte[255];
    bool keyboardStateStatus = GetKeyboardState(keyboardState);

    if (!keyboardStateStatus)
    {
        return "";
    }

    uint virtualKeyCode = (uint)key;
    uint scanCode = MapVirtualKey(virtualKeyCode, 0);
    IntPtr inputLocaleIdentifier = GetKeyboardLayout(0);

    StringBuilder result = new StringBuilder();
    ToUnicodeEx(virtualKeyCode, scanCode, keyboardState, result, (int)5, (uint)0, inputLocaleIdentifier);

    return result.ToString();
}
Felipe
  • 336
  • 8
  • 19