MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Как получить доступ к порту сканера QR-кода?"
Answer 912546
Для сканеров, работающих в режиме эмуляции клавиатуры, единственный способ выделить ввод конкретного устройства - использование Raw Input.
Пример:
using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Runtime.InteropServices; using System.Windows.Interop; namespace WpfApp1 { public partial class MainWindow : Window { //обработчик сообщений для окна private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == Keyboard.WM_INPUT) { RAWINPUT data; int size = Marshal.SizeOf(typeof(RAWINPUT)); Keyboard.GetRawInputData(lParam, Keyboard.RID_INPUT, out data, ref size, Marshal.SizeOf(typeof(RAWINPUTHEADER))); if (data.Header.Type == Keyboard.RawInputType_Keyboard) { //выведем нажатую клавишу textbox.Text += "["+Keyboard.VKCodeToUnicode((uint)data.Keyboard.VirtualKey)+"]"; //выведем тип события switch (data.Keyboard.Message) { case Keyboard.WM_KEYDOWN: textbox.Text += " pressed"; break; case Keyboard.WM_KEYUP: textbox.Text += " released"; break; } textbox.Text += Environment.NewLine; //выведем устройство-источник StringBuilder sb = new StringBuilder(500); uint strsize = (uint)sb.Capacity * 2; uint result = Keyboard.GetRawInputDeviceInfo(data.Header.Device, Keyboard.RIDI_DEVICENAME, sb, ref strsize); textbox.Text += "Source device: "+sb.ToString(); textbox.Text += Environment.NewLine; textbox.Text += Environment.NewLine; } } return IntPtr.Zero; } public MainWindow() { InitializeComponent(); } private void ButtonRegister_Click(object sender, RoutedEventArgs e) { //регистрируем обработчик сообщений WindowInteropHelper h = new WindowInteropHelper(this); HwndSource source = HwndSource.FromHwnd(h.Handle); source.AddHook(new HwndSourceHook(WndProc)); //регистрируем окно в Raw Input RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1]; rid[0].UsagePage = Keyboard.HidPage_Generic; rid[0].Usage = Keyboard.HidUsage_Keyboard; rid[0].WindowHandle = h.Handle; bool res = Keyboard.RegisterRawInputDevices(rid, 1, Marshal.SizeOf(typeof(RAWINPUTDEVICE))); if (res == false) MessageBox.Show("RegisterRawInputDevices failed"); } } // Вспомогательный класс для работы с клавиатурой public class Keyboard { public const uint VK_CAPITAL = 0x14; public const uint WM_INPUT = 0x00FF; public const uint WM_KEYDOWN = 0x0100; public const uint WM_KEYUP = 0x0101; public const uint RID_INPUT = 0x10000003; public const uint RIDI_DEVICENAME = 0x20000007; public const uint RawInputType_Keyboard = 1; public const ushort HidPage_Generic = 0x01; public const ushort HidUsage_Keyboard = 0x06; [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern uint GetRawInputDeviceList ( [In, Out] RAWINPUTDEVICELIST[] RawInputDeviceList, ref uint NumDevices, uint Size ); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern uint GetRawInputDeviceInfo( IntPtr hDevice, uint uiCommand, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pData, ref uint pcbSize); [DllImport("user32.dll")] public static extern int GetRawInputData(IntPtr hRawInput, uint uiCommand, out RAWINPUT pData, ref int pcbSize, int cbSizeHeader); [DllImport("user32.dll")] public static extern bool RegisterRawInputDevices([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] RAWINPUTDEVICE[] pRawInputDevices, int uiNumDevices, int cbSize); [DllImport("USER32.dll")] public static extern short GetKeyState(int vKey); [DllImport("user32.dll")] public static extern short GetAsyncKeyState(int vKey); [DllImport("user32.dll")] public static extern int ToUnicodeEx( uint wVirtKey, uint wScanCode, byte[] lpKeyState, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwszBuff, int cchBuff, uint wFlags, IntPtr dwhkl); [DllImport("user32.dll")] public static extern bool GetKeyboardState(byte[] lpKeyState); [DllImport("user32.dll")] public static extern uint MapVirtualKey( uint uCode, uint uMapType); [DllImport("user32.dll")] public static extern IntPtr GetKeyboardLayout(uint idThread); [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); //преобразование кода клавиши в символы public static string VKCodeToUnicode(uint vkCode) { StringBuilder buf = new StringBuilder(); byte[] keyboardState = new byte[255]; short x; byte y; for (int i = 0; i < 255; i++) { if (i == VK_CAPITAL) { x = GetKeyState(i); } else { x = GetAsyncKeyState(i); } y = 0; if ((x & 0x8000) != 0) y = (byte)(y | 0x80); if ((x & 0x0001) != 0) y = (byte)(y | 0x01); keyboardState[i] = y; } ToUnicodeEx(vkCode, MapVirtualKey(vkCode, 0), keyboardState, buf, 5, 0, GetKeyboardLayout(GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero))); return buf.ToString(); } } // Структуры [StructLayout(LayoutKind.Sequential)] public struct RAWINPUTDEVICELIST { public IntPtr hDevice; public uint Type; } [StructLayout(LayoutKind.Sequential)] public struct RAWINPUTDEVICE { /// <summary>Top level collection Usage page for the raw input device.</summary> public ushort UsagePage; /// <summary>Top level collection Usage for the raw input device. </summary> public ushort Usage; /// <summary>Mode flag that specifies how to interpret the information provided by UsagePage and Usage.</summary> public uint Flags; /// <summary>Handle to the target device. If NULL, it follows the keyboard focus.</summary> public IntPtr WindowHandle; } [StructLayout(LayoutKind.Sequential)] public struct RAWINPUTHEADER { /// <summary>Type of device the input is coming from.</summary> public uint Type; /// <summary>Size of the packet of data.</summary> public int Size; /// <summary>Handle to the device sending the data.</summary> public IntPtr Device; /// <summary>wParam from the window message.</summary> public IntPtr wParam; } [StructLayout(LayoutKind.Sequential)] public struct RAWINPUTKEYBOARD { /// <summary>Scan code for key depression.</summary> public short MakeCode; /// <summary>Scan code information.</summary> public ushort Flags; /// <summary>Reserved.</summary> public short Reserved; /// <summary>Virtual key code.</summary> public ushort VirtualKey; /// <summary>Corresponding window message.</summary> public uint Message; /// <summary>Extra information.</summary> public int ExtraInformation; } [StructLayout(LayoutKind.Explicit)] public struct RAWINPUT { /// <summary>Header for the data.</summary> [FieldOffset(0)] public RAWINPUTHEADER Header; [FieldOffset(16)] public RAWINPUTKEYBOARD Keyboard; } }
Внимание: код заточен под 32-разрядные приложения.
Имя устройства в данном случае будет иметь вид
\\?\ACPI#PNP0303#0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}
. Вас интересует часть между\\?\
и{...}
, которая представляет собой слегка измененный Device Instance ID (PnpDeviceID в WMI).
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.