可自定义键盘快捷键的输入无法按预期工作

时间:2018-01-15 19:52:28

标签: c# winforms

尝试为自定义键盘快捷键输入:

private void textBoxShortcut_KeyDown(object sender, KeyEventArgs e)
{
    e.Handled = true;
    e.SuppressKeyPress = true;
    textBoxShortcut.Text = "";

    if (e.KeyCode != Keys.Back)
    {
        var converter = new KeysConverter();
        textBoxShortcut.Text = converter.ConvertToString(e.KeyData);
    }
}

但是当我按 Shift 输出为Shift+ShiftKey时,我只需要Shift作为输出(仅Modifier,而不是KeyCode)。 此外,当我按时,输出为OemSemicolon,但不是,。 如何改进我的代码?
我试图补充一下:

if (e.KeyCode != Keys.Back && e.Modifiers = 0)
{
    //do logic
}

但是不可能输入任何组合,例如 Shift + A Shift A

编辑#1:在下面添加了我自己的答案。

4 个答案:

答案 0 :(得分:0)

试试这个

      e.Handled = true;
       // e.SuppressKeyPress = true;
        textBox1.Text = "";

        if (e.Modifiers==Keys.Shift && e.KeyCode!=Keys.Back)
      {
            var converter = new KeysConverter();
            textBox1.Text = 
            converter.ConvertToString(e.Modifiers+e.KeyValue);
        }

答案 1 :(得分:0)

您可以尝试使用switch语句过滤掉键:

private void textBoxShortcut_KeyDown(object sender, KeyEventArgs e)
{
        e.Handled = true;
        e.SuppressKeyPress = true;
        textBoxShortcut.Text = "";

        if (e.KeyCode != Keys.Back)
        {
            var converter = new KeysConverter();
            string keyStr = string.Empty;
            switch (e.KeyCode)
            {
                case Keys.Oemcomma:
                    keyStr = "Comma";
                    break;
                case Keys.OemPeriod:
                    keyStr = "Period";
                    break;
                case Keys.ShiftKey:
                    keyStr = "Shift";
                    break;
                case Keys.ControlKey:
                    keyStr = "Ctrl";
                    break;
                case Keys.Menu:
                    keyStr = "Alt";
                    break;
                default:
                    keyStr = converter.ConvertToString(e.KeyData);
                    break;
            }

            textBoxShortcut.Text = keyStr;
        }
}

我也发现了这个问题,其中一个答案实现了使用win32 API调用的方法:Convert keycode to char/string

要为您的特定示例实现此解决方案,请在项目中添加一个新的静态类:

public static class User32Wrapper
{
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern int ToUnicode(
        uint virtualKeyCode,
        uint scanCode,
        byte[] keyboardState,
        StringBuilder receivingBuffer,
        int bufferSize,
        uint flags);
}

然后在表单中,您可以执行以下操作:

if (e.KeyCode != Keys.Back)
{
    var converter = new KeysConverter();
    string keyStr = string.Empty;
    switch (e.KeyCode)
    {
        case Keys.ShiftKey:
            keyStr = "Shift";
            break;
        case Keys.ControlKey:
            keyStr = "Ctrl";
            break;
        case Keys.Menu:
            keyStr = "Alt";
            break;
        default:
            keyStr = textBox1.Text = GetCharsFromKeys(e.KeyData, (ModifierKeys & Keys.Shift)==Keys.Shift);
            break;
    }

    textBox1.Text = keyStr;
}

private static string GetCharsFromKeys(Keys keys, bool shift)
{
    var buf = new StringBuilder(256);
    var keyboardState = new byte[256];
    if (shift)
    {
        keyboardState[(int)Keys.ShiftKey] = 0xff;
    }
    User32Wrapper.ToUnicode((uint)keys, 0, keyboardState, buf, 256, 0);
    return buf.ToString();
}

答案 2 :(得分:0)

几天后,我决定让用户只设置这些类型的组合:

  • (Ctrl || Shift || Alt) + (letter || number)
  • (Ctrl + Shift || Ctrl + Alt || Alt + Shift) + (letter || number)

我去了这段代码:

private void textScreenshotHotkey_KeyDown(object sender, KeyEventArgs e)
    {
        e.Handled = true;
        e.SuppressKeyPress = true;
        textScreenshotHotkey.Text = "";

        bool shiftMod = ((e.Modifiers & Keys.Shift) != 0);
        bool altMod = ((e.Modifiers & Keys.Alt) != 0);
        bool ctrlMod = ((e.Modifiers & Keys.Control) != 0);

        bool modifiers = false;
        bool letterNumber = false;

        if ((shiftMod & altMod) || (shiftMod & ctrlMod) || (altMod & ctrlMod) || shiftMod || altMod || ctrlMod)
        {
            modifiers = true;
        }

        if ((e.KeyCode >= Keys.A & e.KeyCode <= Keys.Z) || (e.KeyCode >= Keys.D0 & e.KeyCode <= Keys.D9))
        {
            letterNumber = true;
        }

        if (e.KeyCode != Keys.Back && modifiers == true && letterNumber == true)
        {
            textScreenshotHotkey.Text = (new KeysConverter()).ConvertToString(e.KeyData);
        }
    }

我仍在寻找简化我的代码和sollution,它们也可以处理这些符号“,”,“。”,“;”,“'”,“\”,“ - ”,“`”,“= ”

答案 3 :(得分:0)

试试这个。实际上,应该接受任何不需要“翻译”的内容(如取消,插入...)。

我添加了F1-F24键。

我认为让用户控制一个好主意。
您可以覆盖ProcessCmdKey(),如果您需要添加更多选项,并且可以直接处理原始WindowProc消息,那么所有这些都可能更容易管理。

我正在使用MapVirtualKey。可能是处理不同键盘布局的最直接的工具。

/*
UINT WINAPI MapVirtualKey(
  _In_ UINT uCode,
  _In_ UINT uMapType
); */

const uint MAPVK_VK_TO_CHAR = 0x02;

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

  private void TextBox1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
  {
      if (e.KeyCode != Keys.Back)
      {
          string _Char;
          e.SuppressKeyPress = true;
          string KeyModifiers = string.Join("+", e.Modifiers
                                      .ToString().Split(',')
                                      .Where(s => s != "None"))
                                      .ToUpper();

          if (e.KeyCode >= Keys.F1 & e.KeyCode <= Keys.F24)
          {
              _Char = e.KeyCode.ToString();
          } else {
              _Char = ((char)(MapVirtualKey((uint)e.KeyCode, MAPVK_VK_TO_CHAR))).ToString();
          }

          TextBox1.Text = KeyModifiers + ((KeyModifiers.Length > 0 && _Char != "\0" ? "+ " : "") + _Char);
      } else {
          TextBox1.Text = "";
      }
  }