工作需要写了一个小程序,结合cefsharp利用erp软件的api进行二次开发,实现定制功能。软件会用到扫码枪扫描快递单号发货。会用到蓝牙电子称称重。还会遇到快递拆单快速新建订单并打印订单,也需要用到扫码枪扫描快递单,然后新建指定数量新的快递单。开发中遇到很多问题。比如,扫码枪会认定为keyboard。蓝牙接收器也会认定为keyboard。加上自身的键盘。这么多的输入设备,如果遇到2个或者2个以上输入设备同时输入就会产生干扰。不能同时输入。针对这个问题,查了很多资料发现rawinput原始输入才是解决这个问题的关键。接下来会结合开发代码进行记录。

一、我遇到的第一个问题如何识别是扫码枪输入的快递单号。还是键盘输入的信息。

网上有人的给出的解决方案是利用键盘钩子,记录键盘的按键keypress事件或者keydown事件的时间间隔。一般设置50毫秒。会认为是扫码枪的输入。因为人工输入达不到这么快的速度。虽然我也这样做了,也可以区分是扫描枪还是键盘输入了。但实际使用的时候还是会产生冲突的情况。遇到了rawinput之后这个问题就非常简单了。原始输入得到的信息里包括了输入设备的信息,这样通过识别设备的信息来区分不同的设备。

private const int RIDEV_INPUTSINK = 0x100;
 private const int RIDEV_NoLegacy = 0x30;

private const int WM_INPUT = 0x00FF;
 private const uint RID_INPUT = 0x10000003;
 private const uint RIDI_DEVICENAME = 0x20000007;

private const string HoneywellScanning = @"HID#VID_0C2E&PID_0204";

StringBuilder 创建订单扫码枪 = new StringBuilder();

[StructLayout(LayoutKind.Sequential)]
        internal struct RAWINPUTDEVICE

{

[MarshalAs(UnmanagedType.U2)]

public ushort usUsagePage;

[MarshalAs(UnmanagedType.U2)]

public ushort usUsage;

[MarshalAs(UnmanagedType.U4)]

public int dwFlags;

public IntPtr hwndTarget;

}

[StructLayout(LayoutKind.Sequential)]
        internal struct RAWINPUTHEADER

{

[MarshalAs(UnmanagedType.U4)]

public int dwType;

[MarshalAs(UnmanagedType.U4)]

public int dwSize;

public IntPtr hDevice;

[MarshalAs(UnmanagedType.U4)]

public int wParam;

}

[StructLayout(LayoutKind.Explicit)]
        internal struct RAWINPUT

{

[FieldOffset(0)]

public RAWINPUTHEADER header;

[FieldOffset(16)]

public RAWMOUSE mouse;

[FieldOffset(16)]

public RAWKEYBOARD keyboard;

[FieldOffset(16)]

public RAWHID hid;

}

[StructLayout(LayoutKind.Sequential)]
        internal struct RAWKEYBOARD

{

[MarshalAs(UnmanagedType.U2)]

public ushort MakeCode;

[MarshalAs(UnmanagedType.U2)]

public ushort Flags;

[MarshalAs(UnmanagedType.U2)]

public ushort Reserved;

[MarshalAs(UnmanagedType.U2)]

public ushort VKey;

[MarshalAs(UnmanagedType.U4)]

public uint Message;

[MarshalAs(UnmanagedType.U4)]

public uint ExtraInformation;

}

[StructLayout(LayoutKind.Explicit)]
        internal struct RAWMOUSE
        {
            [MarshalAs(UnmanagedType.U2)]
            [FieldOffset(0)]
            public ushort usFlags;
            [MarshalAs(UnmanagedType.U4)]
            [FieldOffset(4)]
            public uint ulButtons;
            [FieldOffset(4)]
            public BUTTONSSTR buttonsStr;
            [MarshalAs(UnmanagedType.U4)]
            [FieldOffset(8)]
            public uint ulRawButtons;
            [FieldOffset(12)]
            public int lLastX;
            [FieldOffset(16)]
            public int lLastY;
            [MarshalAs(UnmanagedType.U4)]
            [FieldOffset(20)]
            public uint ulExtraInformation;
        }

[StructLayout(LayoutKind.Sequential)]
        internal struct BUTTONSSTR
        {
            [MarshalAs(UnmanagedType.U2)]
            public ushort usButtonFlags;
            [MarshalAs(UnmanagedType.U2)]
            public ushort usButtonData;
        }

[StructLayout(LayoutKind.Sequential)]
        internal struct RAWHID
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwSizHid;
            [MarshalAs(UnmanagedType.U4)]
            public int dwCount;
        }

[StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_HID
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwVendorId;
            [MarshalAs(UnmanagedType.U4)]
            public int dwProductId;
            [MarshalAs(UnmanagedType.U4)]
            public int dwVersionNumber;
            [MarshalAs(UnmanagedType.U2)]
            public ushort usUsagePage;
            [MarshalAs(UnmanagedType.U2)]
            public ushort usUsage;
        }

[StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_KEYBOARD
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwType;
            [MarshalAs(UnmanagedType.U4)]
            public int dwSubType;
            [MarshalAs(UnmanagedType.U4)]
            public int dwKeyboardMode;
            [MarshalAs(UnmanagedType.U4)]
            public int dwNumberOfFunctionKeys;
            [MarshalAs(UnmanagedType.U4)]
            public int dwNumberOfIndicators;
            [MarshalAs(UnmanagedType.U4)]
            public int dwNumberOfKeysTotal;
        }

[StructLayout(LayoutKind.Explicit)]
        internal struct RID_DEVICE_INFO
        {
            [FieldOffset(0)]
            public int cbSize;
            [FieldOffset(4)]
            public int dwType;
            [FieldOffset(8)]
            public RID_DEVICE_INFO_MOUSE mouse;
            [FieldOffset(8)]
            public RID_DEVICE_INFO_KEYBOARD keyboard;
            [FieldOffset(8)]
            public RID_DEVICE_INFO_HID hid;
        }

[StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_MOUSE
        {
            [MarshalAs(UnmanagedType.U4)]
            public int dwId;
            [MarshalAs(UnmanagedType.U4)]
            public int dwNumberOfButtons;
            [MarshalAs(UnmanagedType.U4)]
            public int dwSampleRate;
            [MarshalAs(UnmanagedType.U4)]
            public int fHasHorizontalWheel;
        }

[DllImport("User32.dll")]
        extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, IntPtr pData, ref uint pcbSize, uint cbSizeHeader);

[DllImport("User32.dll")]
        extern static bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevice, uint uiNumDevices, uint cbSize);

[DllImport("User32.dll")]
        extern static uint GetRawInputDeviceInfo(IntPtr hDevice, uint uiCommand, IntPtr pData, ref uint pcbSize);

private void 订阅WM_INPUT信息()
        {
            RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];

rid[0].usUsagePage = 0x01;

rid[0].usUsage = 0x06;

rid[0].dwFlags = RIDEV_INPUTSINK | RIDEV_NoLegacy;

rid[0].hwndTarget = this.Handle;

RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0]));
        }

我写了一个方法 订阅WM_INPUT信息,用来注册设备。这里RAWINPUTDEVICE是一个结构体。微软官网有详细介绍。usUsagePage=0x01,usUsage = 0x06 这两个选项代表注册的是键盘设备。

dwFlags是一个控制标志,RIDEV_INPUTSINK代表不论程序在焦点状态或者失去焦点状态都会得到WM_INPUT信息。RIDEV_NoLegacy代表你会接收到WM_INPUT信息,但是不会把信息给到winform里。比如你可以接收到按下键盘数字“1”,但是winform里textbox不会有任何变化,相当于屏蔽了键盘的任何输入信息到winform里。两者可以同时写。我根据自身实际情况选择了两者同时写。微软官网还有更多的控制指令。RAWINPUTDEVICE (winuser.h) - Win32 apps | Microsoft Docs这个是介绍文档。很遗憾是英文版。最后是hwndTarget 我设置给了当前winform的handle。

最后一句就是调用winapi注册设备了。注册之后会收到WM_INPUT类型信息。接下来是重写WndProc方法处理WM_INPUT信息。

protected override void WndProc(ref Message message)
        {
            if (message.Msg == WM_INPUT)
                processMessage(message);

base.WndProc(ref message);
        }

如果Msg的类型是WM_INPUT 调用processMessage这个方法来处理message。

private void processMessage(Message message)
        {
            uint dwSize = 0;

GetRawInputData(message.LParam, RID_INPUT, IntPtr.Zero, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));

IntPtr buffer = Marshal.AllocHGlobal((int)dwSize);

GetRawInputData(message.LParam, RID_INPUT, buffer, ref dwSize, (uint)Marshal.SizeOf(typeof(RAWINPUTHEADER)));

RAWINPUT raw = (RAWINPUT)Marshal.PtrToStructure(buffer, typeof(RAWINPUT));

uint size = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));

GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICENAME, IntPtr.Zero, ref size);
            IntPtr pData = Marshal.AllocHGlobal((int)size);
            GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICENAME, pData, ref size);

string deviceName = (string)Marshal.PtrToStringAnsi(pData);

//判断deviceName来自哪个设备。做对应的处理

//doSomething..

//下面两句是释放了缓存
            Marshal.FreeHGlobal(buffer);
            Marshal.FreeHGlobal(pData);

}

两次 调用GetRawInputData 这个winapi。第一次调用为了得到dwSize这个长度,然后定义了dwsize长度的缓存buffer来保存返回的数据。数据是RAWINPUT类型的。然后通过raw.keyboard.Message得到按键值。翻译工作这里不做介绍了。每一个按键会得到2次信息。对应的就是keydown,keyup完成一次按键敲击。有精力的朋友可以继续深入研究。我有这个信息就足够了没在研究下去了。

已经知道了按键的数据。现在还需要知道是哪个设备发送过来的。就到了下面的GetRawInputDeviceInfo这个winapi,同样是2次。第一次得到size,第二次得到数据。我这里需要的是设备名字。所以用的RIDI_DEVICENAME这个控制指令。官网有其他指令的介绍。

现在就可以通过设备名称来识别是哪个设备来的信息。分别保存到各自的StringBuilder中。

//doSomething..

举例。。

if (deviceName.Contains(HoneywellScanning))

{

switch (raw.keyboard.Message)
                {
                    case (uint)21:
                        创建订单扫码枪.Append('Y');
                        break;
                    case (uint)20:
                        创建订单扫码枪.Append('T');
                        break;
                    case (uint)11:
                        创建订单扫码枪.Append('0');
                        break;
                    case (uint)10:
                        创建订单扫码枪.Append('9');
                        break;
                    case (uint)9:
                        创建订单扫码枪.Append('8');
                        break;
                    case (uint)8:
                        创建订单扫码枪.Append('7');
                        break;
                    case (uint)7:
                        创建订单扫码枪.Append('6');
                        break;
                    case (uint)6:
                        创建订单扫码枪.Append('5');
                        break;
                    case (uint)5:
                        创建订单扫码枪.Append('4');
                        break;
                    case (uint)4:
                        创建订单扫码枪.Append('3');
                        break;
                    case (uint)3:
                        创建订单扫码枪.Append('2');
                        break;
                    case (uint)2:
                        创建订单扫码枪.Append('1');
                        break;

//(uint)28 是回车
                    case (uint)28:
                        try
                        {
                            string 快递单号 = 创建订单扫码枪.ToString();
                            创建订单扫码枪.Clear();
                            //创建订单(快递单号);
                        }
                        catch (Exception ex) { MessageBox.Show(ex.ToString()); }
                        break;
                }

}

这样我有2个扫描枪。1个蓝牙称。他们可以互不干扰的输入着各自的数据。也不会因为同时输入而收到干扰。也不会因为winform的textbox得到了焦点被莫名扫码枪输入一串数字。也不会被扫码枪的自带回车键给提交了表单避免了错误操作。

结束语:这个是我写的第一个文章。方便自己今后阅读,也希望能够帮助到需要帮助的人.本人文化水平有限。代码纯属个人爱好。高手勿喷。直接绕路。qq281781648需要源码可以联系本人

C# 多输入设备识别 扫码枪键盘区分RAWINPUT原始输入简易开发笔记相关推荐

  1. 重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop...

    重新想象 Windows 8 Store Apps (49) - 输入: 获取输入设备信息, 虚拟键盘, Tab 导航, Pointer, Tap, Drag, Drop 原文:重新想象 Window ...

  2. 计算机键盘在线识别,usb键盘,教您电脑usb键盘无法识别解决方法

    在现在,电脑已成了我们生活中必不可少的实用工具.不管在生活中的聊天.娱乐,还是在学习上的查阅都可以应用的到,我么你知道,当我们在使用电脑,都是要用到usb键盘的,但是如果遇到无法识别时,该怎么办呢?为 ...

  3. 计算机键盘在线识别,usb键盘,详细教您电脑usb键盘无法识别解决方法

    键盘是最常用也是最主要的输入设备,通过键盘,可以将英文字母.数字.标点符号等输入到计算机中,从而向计算机发出命令.输入数据等.不过有用户在使用usb键盘的时候,就遇到了usb键盘无法识别的情况,下面, ...

  4. 电脑无法识别扫码枪怎么办?看4点解决方法就知道

    近来有很多朋友问远景达(RAKINDA)的技术同事,为什么电脑不能识别扫码枪呢?随着自动识别技术的设备应用于我们生活的多种领域上,同时也给我们带来便捷.但是扫码枪作为由光学.电子.机械.软件应用技术紧 ...

  5. QT 版本号识别 不同系统区分

    QT 版本号识别 不同系统区分 版本号的识别 获取使用QT的版本号 qt版本号的比较 qt 版本小版本的区别 不同系统使用区分 版本号的识别 获取使用QT的版本号 1.$$[QT_VERSION] 在 ...

  6. 电脑不识别扫码枪怎么解决?

    近来有很多朋友问远景达的技术同事,为什么电脑不能识别扫码枪呢?随着自动识别技术的设备应用于我们生活的多种领域上,同时也给我们带来便捷.但是扫码枪作为由光学.电子.机械.软件应用技术紧密结合的电子设备, ...

  7. Win7系统不识别usb键盘

    Win7系统不识别usb键盘 打开win7设备管理器,找到usb键盘并直接打开,发现如下usb键盘中的驱动中是有带感叹号的. 第1步:在桌面找到计算机图标,并在此图标上右键选择管理,打开计算机管理程序 ...

  8. 计算机识别不成USB键盘,如果无法识别计算机键盘该怎么办?提示无法识别的USB设备...

    1. 如果无法识别PS / 2接口键盘该怎么办? 对于台式计算机上最常见的PS / 2接口键盘,如果无法识别,则可能是由于键盘故障或计算机主板上的PS / 2接口引起的. 通常,主板上的PS / 2接 ...

  9. 痞子衡嵌入式:超级下载算法(RT-UFL)开发笔记(2) - 识别当前i.MXRT型号

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是超级下载算法开发笔记(2)之识别当前i.MXRT型号. 文接上篇 <超级下载算法(RT-UFL)开发笔记(1) - 执行在不同CM ...

最新文章

  1. [16] 螺旋面(Spire)图形的生成算法
  2. 如何用OKR搞垮一个团队?
  3. mongodb高可用性架构---Replica Set
  4. 第七周项目三-用多文件组织多个类的程序
  5. Wasserstein距离在生成模型中的应用
  6. 什么是真正的APM?
  7. java连接摄像头_Java实现 海康摄像头抓拍图像(示例代码)
  8. aws cognito_AWS Cognito的用户管理—(2/3)核心功能
  9. H264中I、B、P帧编码原理及pts和dts分析
  10. Go Web编程--使用bcrpyt哈希用户密码
  11. Gibbs 采样定理的若干证明
  12. Altium Designer(六):Make Library
  13. [蛋蛋涂鸦]蜡笔蛋&某蛋真面目(表被吓着)
  14. RNN神经网络- 吴恩达Andrew Ng 循环神经网络 NLP Transformers Week4 知识总结
  15. Xcode证书错误 Provisioning profile does not support the Associated Domains capability
  16. 低版本 android 软件下载,纳米盒旧版本下载-纳米盒旧版下载4.1安卓版-西西软件下载...
  17. 《数字图像处理 第三版》(冈萨雷斯)——第五章 图像复原与重建
  18. 1的阶乘加到100的阶乘
  19. Macbook Tools
  20. 【java】英语单词对战小游戏

热门文章

  1. Java鼠标自动点击及文件内容读取复制
  2. 有限公司跟有限责任公司是什么
  3. 编码器—解码器和注意力机制
  4. 周五IT程序员科技段子
  5. 英语话题 Health
  6. 人际交往中的谈话技巧
  7. 计算机说话技巧,随机应变的说话技巧
  8. android+播放器+螺旋效果,螺旋丸特效相机(抖音螺旋丸特效)V2.3.0.3 安卓版
  9. 大数据:千万个“路人甲”的价值逻辑
  10. 许奔创新社-第26问:专家们创新时为何需要外行来指手画脚?