返回首页

{A}
{S0}
简介
曾经有一段时间,当你是幸运的,如果一台PC有这么多鼠标,但今天,它是常见的有多种游戏控制器到触摸屏人机接口设备(HID)的。特别是,用户可以连接多个键盘到他们的电脑。然而,通常的键盘。NET Framework的编程方法提供没有办​​法来区分不同的键盘输入。处理KeyPress事件的任何应用程序,将接收来自所有连接的键盘输入,好像他们是一个单一的设备。
的Windows XP及以上现在支持"原始输入API,它允许程序处理从任何连接的人机接口设备直接输入。拦截信息和过滤键盘,使应用程序,以确定哪些设备触发的消息。例如,这可以让两个不同的窗口,从不同的键盘输入响应。
本文所附的代码演示了如何处理原始输入,以处理击键,并确定他们来自哪个设备。在附加邮编InputDevice.cs文件中包含的原始输入API的包装,将此文件复制到自己的项目,并按照"使用的代码"的说明,如果你要运行示例应用程序的情况下使用类。{A6}背景
我最近发表的文章对实施跨我的文章{A7}来了,我们讨论了我的代码是否能够适应他的需求。事实上,它横空出世,它不能和原始输入API的解决方案。
不幸的是,有极少数的键盘相关的原始输入样本在线,所以当史蒂夫已经完成了他的代码的工作范例,我愿意写这篇文章,以便将来面对这个问题。NET开发人员就不必看远,以找到解决办法。虽然我对代码所做的轻微调整,主要是史蒂夫的工作,我感谢他分享。注:2007年3月,你也可以下载史蒂夫的WPF示例说明了Windows Vista中使用的的WndProc。然而,本文只介绍Windows XP的源代码。
请注意,这将只能工作在Windows XP或在非终端服务器环境后,附加的示例项目的Visual Studio 2005。{A8}支持不同的设备
附带的代码是一个通用的解决方案,主要是反映MSDN上给出的示例代码。不同的设备会以不同的方式,您可能需要修改代码以满足您使用的键盘。不幸的是,我们不会总是能够帮助设备特定查询,因为我们不会有你有相同的设备。史蒂夫梅塞尔已与不同的键盘测试代码,但是,并相信它将工作与大多数设备提供他们正确安装。{A9}使用代码
所有相关的原始输入处理的代码封装在输入设备类,并使用它,是实施三个简单的步骤问题:
1。实例化一个输入设备对象
输入设备类的构造函数接受一个参数,这是当前窗口的句柄。

InputDevice id = new InputDevice( Handle );


的处理,以确保该窗口将继续侦听事件,即使它不具有焦点。
2。处理keyPressed事件
当按下一个键,输入设备类提出了一个自定义的含有一些KeyControlEventArgs keyPressed事件。这需要的类型DeviceEventHandler,可设置如下方法处理:{C}
处理事件的方法,就可以执行任何行动的基础上的KeyControlEventArgs参数的内容需要。本文所附的示例应用程序简单地使用这些值来填充对话框。
3。重写WndProc方法
在其目前的形式,输入设备类工程拦截消息窗口,以包含原始输入数据的过程中WM_INPUT消息。聆听原始输入的窗口,因此需要重写自己的Windows程序,并通过其所有邮件的实例化的输入设备对象。
protected override void WndProc( ref Message message )

{

  if( id != null )

  {

    id.ProcessMessage( message );

  }

  base.WndProc( ref message );

}


写在这篇文章中使用的代码后,史蒂夫决定输入设备类可以真正独立的应用程序使用它从{A10}继承。然而,这篇文章的目的主要是为了说明使用原始输入API,我们决定保持其原来的形式的代码。
本文的其余部分,介绍了如何处理从C#应用程序在示例应用程序的输入设备类所示,"原始输入"。{A11}实现一个Windows API原始输入处理程序
{A12}作为一个接口设备提供的原始数据。在键盘的情况下,这个数据通常是由Windows截获并翻译成。NET框架的关键事件提供的信息。例如,窗口管理器转换成虚拟键的左右按键的设备特定的数据。
然而,正常的Windows经理不提供任何信息,有哪些设备收到的击键,它只是捆绑所有的键盘事件为一类的行为就好像有一个键盘。
这是原始输入API是有用的。它允许应用程序直接从设备接收数据从Windows的最小干预。它提供的信息的一部分,是触发事件的设备的身份。
在Windows XP和Vista的user32.dll中包含用于处理原始输入下列方法:RegisterRawInputDevices允许申请登记要监视的输入设备。GetRawInputData从输入设备获取数据。GetRawInputDeviceList检索连接到系统的输入设备列表。GetRawInputDeviceInfo检索设备的信息。
下面的小节给出了这四种方法如何被用来处理原始数据从键盘的概述。注册原始输入设备
默认情况下,没有应用程序接收原始输入。因此,第一步是注册的输入设备,将提供所需的原始数据,他们将要处理这个数据与窗口关联。
要做到这一点,RegisterRawInputDevices方法是从user32.dll中导入:
[DllImport("User32.dll")]

extern static bool RegisterRawInputDevices(

    RAWINPUTDEVICE[] pRawInputDevice, 

          uint uiNumDevices, uint cbSize);


要确定哪些设备应当予以登记,该方法接受一个RAWINPUTDEVICE结构数组。其他两个参数是数组中的项数,并在RAWINPUTDEVICE结构的字节数。
RAWINPUTDEVICE结构定义在C项目WINDOWS.H,但这个文件是不是在C#中使用结构已重新定义为输入设备类的成员。
[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;

}


每个RAWINPUTDEVICE结构添加到数组中包含利益的应用程序的设备类型的信息。例如,它可以注册键盘和电话设备。该结构采用了以下信息:用法页:顶级的HID"用法"页。对于大多数HIDS,包括键盘,这是0x01。使用编号:一个数字,指示应监测设备的精确类型。对于键盘,这是为0x06。 (使用页和用法ID值的列表可以发现{A14})标志:这些确定的数据应如何处理,是否应该被忽略某些类型。 {A15}如果你不已经有一个)。目标手柄:窗口,这将是从这个特定类型的设备监测数据的处理。
在这种情况下,我们只在键盘感兴趣,所以数组中只有一个成员,并设置如下:
RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[1];





rid[0].usUsagePage  = 0x01;

rid[0].usUsage      = 0x06;

rid[0].dwFlags      = RIDEV_INPUTSINK; 

rid[0].hwndTarget   = hwnd;


在这里,代码只定义RIDEV_INPUTSINK标志,这意味着该窗口将始终接收输入消息​​,即使它不再是重点。这将使两个窗口,以应对不同的键盘事件,至少即使其中一人将不会被激活。
就可以使用与阵列,该方法可以被称为登记窗口的任何设备,确定自己作为键盘的兴趣:
RegisterRawInputDevices(rid, (uint)rid.Length, 

    (uint)Marshal.SizeOf(rid[0]))


一旦已注册的设备类型,这样,应用程序就可以开始使用GetRawInputData在下一节中描述的方法来处理数据。{A16}检索和处理原始输入
注册的设备类型是当,应用程序开始接收原始输入。每当注册设备使用,Windows生成一个WM_INPUT消息,其中包含从设备未处理的数据。
注册设备相关联,在上一节所述的每一个窗口的句柄,因此必须检查接收到的消息,并采取适当的行动时WM_INPUT之一是检测。在示例应用程序,输入设备类保健检查WM_INPUT消息,因此,所有的主窗口是覆盖其基地的WndProc方法获得的消息,并通过任何有效的输入设备对象:
protected override void WndProc( ref Message message ) {

  if( id != null ) {

    id.ProcessMessage( message );

  }

  base.WndProc( ref message );

}


ProcessMessage方法在输入设备过滤器的消息,每当收到一个WM_INPUT调用ProcessInputCommand。任何其他类型的消息将通过调用基地的WndProc下降,因此应用程序会正常响应其他事件。
public void ProcessMessage( Message message ) {

  switch( message.Msg ) {

    case WM_INPUT: {

      ProcessInputCommand( message );

    }

    break;

  }

}


ProcessInputCommand然后使用GetRawInputData方法来检索消息的内容,并转换成有意义的信息。从邮件中检索信息
,为了处理WM_INPUT消息数据,GetRawInputData方法是从user32.dll中导入:
[DllImport("User32.dll")]

extern static uint GetRawInputData(IntPtr hRawInput, uint uiCommand, 

        IntPtr pData, ref uint pcbSize, uint cbSizeHeader);


该方法采用下列参数:hRawInput
RAWINPUT结构包含数据,在WM_INPUT消息的lParam提供的处理。uiCommand
一个标志设置是否要撷取的输入数据或从RAWINPUT结构的头信息。可能的值有RID_INPUT(0x10000003)或RID_HEADER(0x10000005)。PDATA:
根据期望的结果,这可能是两件事情之一:如果PDATA设置IntrPtr.Zero,需要包含的数据的缓冲区的大小是在pcbSize变量返回。否则,PDATA必须是一个分配的内存,可容纳RAWINPUT结构WM_INPUT消息的指针。在方法调用返回时,分配的内存的内容将是消息的标题信息或输入数据,根据uiCommand价值。pcbSize
返回或指定的数据大小的一个变量,指出由PDATA。cbSizeHeader
一个RAWINPUTHEADER结构的大小。
为了确保有足够的内存分配给存储所需要的信息,GetRawInputData方法首先应该被称为PDATA设置到IntPtr.Zero。
uint dwSize = 0;



GetRawInputData( message.LParam, RID_INPUT, 

                 IntPtr.Zero, ref dwSize, 

                 (uint)Marshal.SizeOf( typeof( RAWINPUTHEADER )));


此调用的dwSize值将对应需要存储的原始输入数据(如使用的RID_INPUT标志表示)的字节数。
然后分配正确的内存量,在这种情况下,指针是存储在一个变量的缓冲区。
IntPtr buffer = Marshal.AllocHGlobal( (int)dwSize );


缓冲点,以一个合适的位置,GetRawInputData可以再次调用RAWINPUT结构从目前的消息来填充分配的内存。如果成功,该方法返回的数据检索的大小,所以这是值得的检查,这相匹配的结果,然后再继续先前呼叫。
if( GetRawInputData( message.LParam, RID_INPUT, 

     buffer, ref dwSize, (uint)Marshal.SizeOf( typeof( RAWINPUTHEADER )))

         == dwSize )

//do something with the data


一旦这项工作已经完成,内容指出,由缓冲区可以封送处理成RAWINPUT结构,可以轻松访问各种数据的成员,如以下部分所示。 处理数据
如上所述,WM_INPUT消息包含在RAWINPUT结构封装的原始数据。由于在上一节中所述的RAWINPUTDEVICE结构,这种结构在输入设备类重新定义如下。
[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;

}


之后的第二次调用GetRawInputData(见上一节),原料结构将包含以下信息:
所谓的头一个RAWINPUTHEADER结构,其中包含的消息,并触发它的设备的信息。
一个类型RAWKEYBOARD第二结构称为键盘。这也可能是一个RAWMOUSE或RAWHID结构被称为鼠标或HID,取决于设备类型。
RAWINPUTHEADER结构布局如下:
[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;

}


其成员将返回以下信息:dwType
的消息表示原始输入的类型。的值可以RIM_TYPEHID(2),RIM_TYPEKEYBOARD(1),或RIM_TYPEMOUSE(0)。的dwSize
消息中的所有信息(包括头和输入数据)的大小。hDevice
处理设备,由此引发的消息。wParam参数
从WM_INPUT消息的wParam数据。
第二个结构将是一个RAWMOUSE,RAWKEYBOARD,或RAWHID类型。为了完整起见,输入设备类不包含RAWMOUSE和RAWHID的定义,虽然它只是设计过程中键盘信息。
键盘信息提供一个RAWKEYBOARD结构如下规定。
[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;

}


由于只关心键盘输入的输入设备类,ProcessInputCommand方法首先检查头,以确保这是一个键盘消息,然后再继续:
if( raw.header.dwType == RIM_TYPEKEYBOARD )


下一步是过滤消息,看它是否是一个down事件的关键。这可以很容易地检查了事件的关键;这里的要点是使同一按键键并了事件的关键不处理的消息过滤器。
private const int WM_KEYDOWN     = 0x0100;

private const int WM_SYSKEYDOWN  = 0x0104;

...

if (raw.keyboard.Message == WM_KEYDOWN || 

    raw.keyboard.Message == WM_SYSKEYDOWN)

{

  //Do something like...

  int vkey = raw.keyboard.vkey;

  MessageBox.Show(vkey.ToString());

}


在这一点上,输入设备类检索有关消息,并触发它的设备的进一步信息,并提出了其自定义的keyPressed事件。以下各节描述如何在设备上的信息。{A17}检索输入设备清单
虽然这一步是不需要处理原始输入,输入设备清单可以是有用的。示例应用程序检索的设备清单,过滤器键盘,然后返回键盘。这是KeyControlEventArgs返回的信息输入设备类的keyPressed事件的一部分。
第一步是从user32.dll中导入必要的方法:
[DllImport("User32.dll")]

extern static uint GetRawInputDeviceList(IntPtr pRawInputDeviceList, 

    ref uint uiNumDevices, uint cbSize);


方法的参数如下:pRawInputDeviceList:根据期望的结果,这可以是一两件事情:如果目的IntPtr.Zero是只检索设备的数量。RAWINPUTDEVICELIST结构的阵列,如果方法调用的目的是为了获取设备的完整列表的指针。uiNumDevices:一个无符号整数,存储设备的数量的参考。如果pRawInputDeviceList说法是IntPtr.Zero,那么这个变量将返回设备的数量。如果pRawInputDeviceList参数是一个指向数组的指针,那么这个变量必须包含数组的大小。这允许适当的方法来分配内存。如果uiNumDevices小于在这种情况下数组的大小,该方法将返回数组的大小,但一个"缓冲区不足"的错误会发生,该方法将失败。cbSize:一个RAWINPUTDEVICELIST结构的大小。
为了确保第一和第二个参数是正确配置需要的设备清单时,该方法应设立三个阶段。
首先,它应该被称为pRawInputDeviceList设置到IntPtr.Zero。这将确保在第二个参数(deviceCount在这里)的变量是正确的设备填补。应检查此调用的结果,因为一个错误代码可以进行没有进一步。
uint deviceCount = 0;

int dwSize = (Marshal.SizeOf( typeof( RAWINPUTDEVICELIST )));



if( GetRawInputDeviceList( IntPtr.Zero, ref deviceCount, (uint)dwSize ) 

    == 0 )

{

  //continue retrieving the information (see below)

}

else

{

  //handle the error or throw an exception

}


一旦deviceCount变量包含正确的价值,正确的存储器可以分配和指针关联:
IntPtr pRawInputDeviceList = 

              Marshal.AllocHGlobal((int)(dwSize * deviceCount ));


和方法,可以再次调用,此时填充RAWINPUTDEVICELIST结构数组分配内存:
GetRawInputDeviceList( pRawInputDeviceList, ref deviceCount, (uint)dwSize );


pRawInputDeviceList数据就可以被转换成单个的RAWINPUTDEVICELIST结构。在下面的例子中,for循环被用于遍历的设备,所以我代表数组中的当前设备的位置。
for( int i = 0; i < deviceCount; i++ )

{

  RAWINPUTDEVICELIST rid = (RAWINPUTDEVICELIST)Marshal.PtrToStructure(

         new IntPtr(( pRawInputDeviceList.ToInt32() + ( dwSize * i ))), 

         typeof( RAWINPUTDEVICELIST ));

//do something with the information (see section on GetRawInputDeviceInfo)

}


当任何后续处理完成后,内存被释放。
Marshal.FreeHGlobal( pRawInputDeviceList );

{A18}在特定设备上获取信息
一旦GetRawInputDeviceList已用于检索RAWINPUTDEVICELIST结构的阵列,以及阵列中的项目数量,它是可以使用GetRawInputDeviceInfo的检索每个设备的具体信息。
首先,该方法是从user32.dll中导入:
[DllImport("User32.dll")]

extern static uint GetRawInputDeviceInfo(IntPtr hDevice, 

    uint uiCommand, IntPtr pData, ref uint pcbSize);


它的参数如下:hDevice
设备句柄返回相应的RAWINPUTDEVICELIST结构。uiCommandA标志设置将在PDATA返回什么类型的数据。可能的值有RIDI_PREPARSEDDATA(0x20000005 - 返回以前分析过的数据),RIDI_DEVICENAME(0x20000007 - 一个字符串,其中包含的设备名称),或RIDI_DEVICEINFO(0x2000000b - RIDI_DEVICE_INFO结构)PDATA:根据期望的结果,这可以是一两件事情:如果PDATA设置IntrPtr.Zero,需要包含的数据的缓冲区的大小是在pcbSize变量返回。否则,PDATA必须分配的内存,可容纳uiCommand指定的数据类型的指针。
(注:如果uiCommand设置到RIDI_DEVICEINFO,然后RIDI_DEVICE_INFO结构的cbSize成员必须设置结构的大小)pcbSize
返回或指定的数据大小的一个变量,指出由PDATA。如果uiCommand是RIDI_DEVICENAME,pcbSize会显示字符串中的字符数。否则,它表示数据的字节数量。
示例代码使用一个for循环迭代通过提供设备deviceCount变量表示。在每个循环的开始,一个RAWINPUTDEVICELIST结构称为RID是与当前设备上的信息填写(见以上GetRawInputDeviceList节)。
为了确保有足够的内存分配给存储所需要的信息,GetRawInputDeviceInfo方法首先应该被称为PDATA设置到IntPtr.Zero。在hDevice参数的处理是由RID包含回路中的电流设备信息结构。
uint pcbSize = 0;



GetRawInputDeviceInfo( rid.hDevice, RIDI_DEVICENAME, IntPtr.Zero, 

            ref pcbSize );


在这个例子中,目的是要找出设备的名称,将用于查找设备上的注册表中的信息。
此调用,pcbSize价值将对应所需的存储设备名称的字符数。一旦代码检查,pcbSize大于0,适量的内存可以分配。
IntPtr pData = Marshal.AllocHGlobal( (int)pcbSize );


和方法,可以再次调用,此时填补分配的内存的设备名称。的数据可以被转换成一个C#字符串的易用性。
string deviceName; 



GetRawInputDeviceInfo( rid.hDevice, RIDI_DEVICENAME, pData, ref pcbSize );

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


该列表还包括"根"的键盘和鼠标设备,终端服务或远程桌面连接使用。由于这些不感兴趣,我们在这里,下面的代码将跳过这些,当他们在遇到循环。
if (deviceName.ToUpper().Contains("ROOT"))

{

  continue;  //Drop into next iteration of the loop

}


下一个阶段是,以确定是否枚举设备是键盘。
if( deviceType.Equals( "KEYBOARD" ) || deviceType.Equals( "HID" ))

{

  //It's a keyboard 锟?or a USB device that could be a keyboard<

/span>

  //Do something

}


代码的其余部分,然后检索设备的有关信息,并检查注册表,看设备是否是一个真正的键盘。{A19}从注册表中读取设备信息
上面的代码,DEVICENAME的值都将类似于以下内容:
\\??\\ACPI#PNP0303#3&13c0b0c5&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}

这个字符串反映设备的注册表项解析,因此它使我们能够找到相关的注册表项,其中包含设备的进一步信息。因此,第一步是要打破字符串的相关部分:
// remove the \??\

item = item.Substring( 4 ); 



string[] split = item.Split( '#' );



string id_01 = split[0];    // ACPI (Class code)

string id_02 = split[1];    // PNP0303 (SubClass code)

string id_03 = split[2];    // 3&13c0b0c5&0 (Protocol code)

// The final part is the class GUID and is not needed here




类代码,子类的代码和"议定书"的检索,这种方式相对应的设备的路径HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet下,使下一阶段的开放,关键:
RegistryKey OurKey = Registry.LocalMachine;



string findme = string.Format( 

    @"System\CurrentControlSet\Enum\{0}\{1}\{2}", 



    id_01, id_02, id_03 );


我们感兴趣的是信息设备的友好描述,和它的类,因为后者会告诉我们,如果这是一个键盘:
string deviceDesc  = (string)OurKey.GetValue( "DeviceDesc" );

string deviceClass = (string)OurKey.GetValue( "Class" );

if( deviceClass.ToUpper().Equals( "KEYBOARD" )){

  isKeyboard = true;

}

else{

  isKeyboard = false;

}


,然后是左是释放任何分配的内存,并与已检索到的数据的东西。{A20}结论
虽然。NET Framework中提供的最常见的用途的方法,原始输入API提供了一个更灵活的方式,设备的数据。包含的代码,在这篇文章中解释,将有望证明一个有用的出发点,在XP或Vista的应用程序来处理多个键盘的人。{A21}来源
本文给出了一个需要实现的原始输入API的不同步骤的概述。进一步处理原始输入信息:{A22}。如果你是在监测其他HIDS感兴趣,{A23}解释有关使用页。历史2007年3月 - 增加了WPF的样本响应用户的请求2007年1月 - 原始版本

回答

评论会员:亚历克斯Miricho 时间:2011/12/07
在谈到上述问题,这是以前发布的另一名成员(唐Denuyl)将任何机会,你有他没有解决问题的完整变化。我假设的基础上他的信息,他可能会向您发送的决议。请寄给我,如果你能是一个问题,我一直有,并不能找出一个解决方案。


评论会员:会员4314808 时间:2011/12/07
我一直在试图使鼠标与样品的工作,但我似乎无法找到如何
有人能帮助我
评论会员:会员4314808 时间:2011/12/07
我想我发现我的问题
我能得到的左边和右边的按键,但是当我按下鼠标中或Xbutton1,我得到一个错误。
当我检查设备的句柄为0。

我觉得我的鼠标可能会使用多个处理。
任何人是否知道如何解决这个问题
评论会员:?grheard 时间:2011/12/07
我有同样的问题与我的微软媒体中心的USB遥控媒体键。当我按下媒体键,它是作为从设备0的报道。

你找到一个解决方案
评论会员:会员4314808 时间:2011/12/07
我没有找到一个解决方案
。在ProcessInputCommand方法,找到:

if (deviceList.Contains(raw.header.hDevice))

{

...

}


添加此代码之后:


else if (raw.header.hDevice == IntPtr.Zero)

{

    dInfo = new DeviceInfo();

    dInfo.deviceType = DeviceType.Key.ToString();

    dInfo.vKey = myKey.ToString();

    dInfo.key = key;

}


我不是100%肯定,使用raw.header.hDevice == IntPtr.Zero是正确的方法来处理它,但至少它的工作原理
评论会员:。likaxx 时间:2011/12/07
!!我一直在寻找这样的事情完全BR}我的工作与C网,所以我封闭RawInput DLL中的类,并用我的WinForm应用程序!工程100%。

非常感谢
利卡
评论会员:cbonifacio 时间:2011/12/07
我发现这奇怪的。使用源,但转换到VS2008的解决方案,它建立RawInput.exe和RawInput.vshost.exe。
奇数部分是表单中的文本框会收到我在键盘上键入的所有的字符,但会错过的前几个字符,如果不存在RawInput.vshost.exe。 在我的应用程序,你的榜样,完美的工作,当vshost文件存在,否则将完全失败,甚至没有赶上我在键盘上键入的任何。
你有没有看到这种行为?感谢你的答复之前
评论会员:smesser 时间:2011/12/07
,我目前使用VS2010的和Windows 7 64位,我还没有遇到这个问题
评论会员:Samy1981 时间:2011/12/07
您好,

我附3键盘,第一个正常的键盘,其他两个键盘热键操作使用。热键键盘是完全的相同的参数及。

我想要做的是这样的:

例如,如果按下"A"是关键:

键盘上的1:输出"A"
键盘上的2:做一些动作X
键盘上的3:做一些行动Ÿ

所以,我需要知道的键盘的键被按下键盘是我的第1,2和3 ...

DeviceHandle似乎是唯一的,但每次开机后的变化,所以每次重新启动,我要告诉我的应用程序的键盘是键盘1,2和3。不是很好。

DEVICENAME和DeviceDescription是完全相同的两个热键键盘相同,因为它们是相同的参数及

任何其他的想法
评论会员:?motific 时间:2011/12/07
我不是已经设置了相同的键盘的发挥,但WMI应该允许你创建/找到一个设备的物理地址,如果没有的话少以及在Windows DDK中的Win32 SetupAPI的记录一定会
评论会员:。rouen_sk 时间:2011/12/07
第一:伟大的教程和样本,绝对时间保护程序
我有一个问题:我怎样才能实现,从某些关键信息设备将被"俘虏"和"封杀"我的应用程序,使其他应用程序不会接受他们吗?我的遥控器被认定为HID设备,但是当我打开记事本,然后按一些键就可以了,它像一个正常的键盘写字母... ...我希望避免这种情况 - 某种自定义应用程序"压倒一切的"这个遥控器的默认键码..和任何其他应用程序应该接收它的事件。这是可能的吗?我试图设置"处理"中的WndProc(HWND的IntPtr,INT味精,IntPtr的wParam参数lParam的IntPtr的文献BOOL处理)为true,但没有效果 - !还在写记事本
Thanx很多
R.
评论会员:JeffreyOwens 时间:2011/12/07
这个问题不断得到解决?我也想知道如何"处理"的消息,所以,它并没有沿着链。非常感谢
评论会员:!josemaaa 时间:2011/12/07
您好!我也有兴趣在这个主题。我必须做同样的事情,但我没有找到解决方案。
感谢
评论会员:!itgrunt2002 时间:2011/12/07
有没有人能够得到这些样品在Windows 7(64位),工作在Visual Studio 2010中



ItGrunt
评论会员:smesser 时间:2011/12/07
对不起,我没有的配置,甚至尝试
评论会员:。itgrunt2002 时间:2011/12/07
无后顾之忧... ...
爬下来的源代码,发现预处理变量,这是导致64位的结构,没有得到正确创建。
我正在盘算着如何动态确定操作系统类型,所以我没有做两个不同的版本。

感谢

乔恩
评论会员:jumacabo 时间:2011/12/07

能否请您共享的变量,

究竟您没有改变,使其工作在64位?

感谢在前进!
评论会员:itgrunt2002 时间:2011/12/07
如果你在第一线inputdevice.cs来看,你会看到一条线"#定义VISTA_64"。

该行取消注释
评论会员:布伦特Lamborn 时间:2011/12/07
!效果很好,感谢
{A24}

评论会员:游客 时间:2011/12/07
|motific:有一个错误的代码,这意味着它在x64环境中返回错误的结构。看到这个答案的评论:-http://www.codeproject.com/Messages/3309574/Re-Not-suported-under-Windows-Vista.aspx希望帮助
!mapasoal
评论会员:本文全部成为明确 时间:2011/12/07
motific
评论会员:游客 时间:2011/12/07
分享他们的代码的作者。救了我相当多的时间很多。我使用的代码,修改为未知的成员由64位系统上使用,它的工作非常出色。但我需要规则的东西,并没有测试现在的32位框。无论我尝试从媒体键(VolumeUp,VolumeDown等)的消息,返回一个零处理设备(raw.header.hDevice)。但问题是,不具有普遍性和似乎是有限的2个USBKB的(由苹果公司和IBM),但不是PS/2。我已经测试过的"正常"键似乎做工精细(如Mac上的F13-F15)。如果任何人有USB键盘与媒体键,可以花一点时间,复制的测试和发布您的结果,或如果任何人都可以阐明什么可能会引起一些轻,这将大大赞赏
smesser
评论会员:游客 时间:2011/12/07
我有一个32位的操作系统,微软自然多媒体键盘和所有的媒体键返回正确的值。如果我没有记错的话,每个键盘设备厂商以不同的方式实现其特殊键。我相信你已经安装的软件驱动程序的返回值,否则默认的键盘驱动程序的特殊键的键盘,不知道如何处理市场上有许多不同的键盘特殊键。我相当肯定我测试一次卸载我的微软键盘软件和不再起作用的键。也就是说,如果我没有记错正确的。希望帮助
motific
评论会员:游客 时间:2011/12/07
感谢您的输入,有趣的是,这里的工作之一KB是微软多媒体(但我猜司机是建于)。为什么我获得这个项目的一部分的感觉这将是比我原先预期的头痛...我想也许我会离开这个人-有没有采取进一步此功能一般的商业案例,是我的潜在客户群,约1%是要使用他们,我会感到惊讶,如果其中任何使用比USB数字键盘的任何其他
!smesser
评论会员:游客 时间:2011/12/07
。微软的硬件恰好滑稽如何更好地运行其他硬件(硬件!=MICROSOFT){睡眠(1000);IgnoreSpecialKeys()}我开玩笑,但我的鼠标和键盘都是从微软