C # .NET - Обнаружение и обработка "расширенных" кодов клавиатуры USB HID - PullRequest
1 голос
/ 18 июня 2019

Я ищу, чтобы обнаружить и обработать коды клавиш с клавиатуры HID USB, которые выходят за пределы «нормального» набора кодов, т.е. коды выше 100 (0x64) в приложении .NET WinForms (.NET Framework 4.5). В частности, в моем случае мне нужно обнаруживать коды от 0x68 до 0x78, но я хотел бы иметь возможность обнаруживать что-либо до 0xA4, что, по-видимому, является верхним пределом кодов клавиатуры HID (кроме таких вещей, как Ctrl, Alt, Win и т. д.)

Этот вопрос Здесь , казалось, был именно тем, что я искал, но мне не удалось получить совет по этому ответу на работу. У меня для параметра KeyPreview установлено значение true для формы, а обработчики событий зарегистрированы для KeyDown, KeyPress и PreviewKeyDown, но ни один из них не срабатывает при получении кода 0x68 (F13). Сейчас я просто хочу напечатать нажатую клавишу в элементе управления richtextbox:

    public mainFrm()
    {
        InitializeComponent();
        this.KeyPreview = true;
        this.KeyDown += new KeyEventHandler(KeyDownHandler);
        this.KeyPress += new KeyPressEventHandler(KeyPressHandler);
        this.PreviewKeyDown += new PreviewKeyDownEventHandler(PreviewKeyHandler);
    }

    private void KeyPressHandler(object sender, KeyPressEventArgs e)
    {
        rtb_hidLog.AppendText("Press: " + e.KeyChar.ToString() + "\r\n");
    }

    private void KeyDownHandler(object sender, KeyEventArgs e)
    {
        rtb_hidLog.AppendText("KeyDown: "+ e.KeyCode.ToString() + "\r\n");
    }

    private void PreviewKeyHandler(object sender, PreviewKeyDownEventArgs e)
    {
        rtb_hidLog.AppendText("Preview: " + e.KeyCode.ToString() + "\r\n");
    }

Я даже попытался переопределить ProcessCmdKey (согласно этому вопросу), и он также не срабатывает при 0x68:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        rtb_hidLog.AppendText("CmdKey: " + keyData.ToString() + "\r\n");
        return base.ProcessCmdKey(ref msg, keyData);
    }

У меня подключено USB-устройство HID Keyboard (микроконтроллер PSoC в качестве HID-клавиатуры), которое отправляет код клавиши 0x68 (F13) при нажатии кнопки, но не запускает PreviewKeyHander. Стандартный код «A» (0x04) с устройства PSoC запускает события KeyDownHandler и KeyPressHandler без проблем. Через USB Analyzer я подтвердил, что код 0x68 отправляется правильно, но я просто не могу заставить .NET его распознать и запустить событие. Есть ли что-то, чего мне не хватает, или какой-то трюк, который мне нужно сделать, чтобы мое приложение вызвало событие для этих кодов?

[EDIT] Теперь я также пытался использовать Interop для использования win32 API (User32.dll), чтобы подключиться к вводу с клавиатуры, и это также не работает. Те же результаты, подключенное событие будет срабатывать для всех клавиш на моей клавиатуре, но все, что не находится в этом диапазоне, не вызывает событие нажатия клавиши.

[РЕДАКТИРОВАТЬ 2] Меня поразило, что я, вероятно, также должен опубликовать свой USB HID Descriptor для устройства клавиатуры, если там есть какая-то проблема:

enter image description here

Заранее спасибо за любую помощь!

1 Ответ

0 голосов
/ 04 июля 2019

Вы можете использовать клавиатуру-перехватчик «в отдельном dll-проекте, на который ссылается ваше приложение», который используется такой формой

public delegate IntPtr KeyBoardHook( int nCode, IntPtr wParam, IntPtr lParam);
public class InterceptKeys : IDisposable
{
    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;
    private KeyBoardHook _proc;
    public  event KeyBoardHook  OnKeyBoardKeyClicked;
    private static IntPtr _hookID = IntPtr.Zero;

    public InterceptKeys()
    {
        _proc = HookCallback;
        _hookID = SetHook(_proc);
        if(_hookID == IntPtr.Zero)
        {
            throw new Exception($"Error Happened [{Marshal.GetLastWin32Error()}]");
        }

    }
    public void Dispose()
    {
        UnhookWindowsHookEx(_hookID);
    }

    private IntPtr SetHook(KeyBoardHook proc)
    {
        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
            return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
               GetModuleHandle(curModule.ModuleName), 0);
        }
    }

    private IntPtr HookCallback(
        int nCode, IntPtr wParam, IntPtr lParam)
    {
        OnKeyBoardKeyClicked?.Invoke(nCode, wParam, lParam);
        //if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
        //{
        //    int vkCode = Marshal.ReadInt32(lParam);
        //    Console.WriteLine((char)vkCode);
        //}
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }


    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetWindowsHookEx(int idHook,
        KeyBoardHook lpfn, IntPtr hMod, uint dwThreadId);


    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);


    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
        IntPtr wParam, IntPtr lParam);


    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);


}


    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);


}
...