Monthly Archive for November, 2010

Handling multiple Keyboards in MFC

If you want to handle more than one keyboard in your MFC application (e.g. a keyboard and a barcode scanner), you can make use of Win API’s raw input functionality. It allows to determine the associated keyboard of an occurred key press – just to highlight one interesting use case.

The first thing you have to do is the registration of the raw input devices by initializing the RAWINPUTDEVICE structure and calling the RegisterRawInputDevices method. A detailed description of the magic numbers in the listing below can be found here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BOOL CApplication::InitInstance()
{
  // ...
 
  RAWINPUTDEVICE ltDevice;
  ltDevice.usUsagePage = 0x01;
  ltDevice.usUsage = 0x06;
  ltDevice.dwFlags = RIDEV_INPUTSINK;
  ltDevice.hwndTarget = AfxGetMainWnd()->GetSafeHwnd();
 
  if ( !RegisterRawInputDevices(&ltDevice, 1, sizeof(RAWINPUTDEVICE)) )
  {
    return FALSE;
  }
 
  // ...
}

Secondly, you have to implement the OnRawInput method of the related CWnd-based class. And, don’t forget to enable this event handler by inserting ON_WM_INPUT() in the message map. The following example illustrates how to extract the keyboard’s device name of a pressed key.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void CMainFrame::OnRawInput(UINT piInputCode, HRAWINPUT phRawInput)
{
  // only process foreground inputs
  if ( RIM_INPUT != piInputCode )
    return;
 
  // determine the size of the resulting RAWINPUTHEADER structure
  UINT liSize;
  if ( 0 != GetRawInputData(phRawInput, RID_INPUT, NULL, &liSize, sizeof(RAWINPUTHEADER)) )
    return;
 
  // determine the actual RAWINPUTHEADER structure
  LPBYTE lpbBuffer = new BYTE[liSize];
  if ( liSize != GetRawInputData(phRawInput, RID_INPUT, lpbBuffer, &liSize, sizeof(RAWINPUTHEADER)) )
    return;
 
  // determine the size of the resulting device name's string
  if ( 0 != GetRawInputDeviceInfo(((RAWINPUT*)lpbBuffer)->header.hDevice, RIDI_DEVICENAME, NULL, &liSize) )
    return;
 
  // determine the actual string of the device name
  TCHAR *lpszDeviceName = new TCHAR[liSize];
  if ( 0 > GetRawInputDeviceInfo(((RAWINPUT*)lpbBuffer)->header.hDevice, RIDI_DEVICENAME, lpszDeviceName, &liSize) )
    return;
 
  TRACE(_T("%s\n"), lpszDeviceName);
  delete [] lpbBuffer;
  delete [] lpszDeviceName;
}