Mouse3DInput.cpp 19.5 KB
Newer Older
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

#include "Mouse3DInput.h"

#include <QApplication>

#define LOGITECH_VENDOR_ID 0x46d
#define _CONSTANT_INPUT_PERIOD 0

#ifndef RIDEV_DEVNOTIFY
#define RIDEV_DEVNOTIFY 0x00002000
#endif

#define _TRACE_WM_INPUT_PERIOD 0
#define _TRACE_RI_TYPE 0
#define _TRACE_RIDI_DEVICENAME 0
#define _TRACE_RIDI_DEVICEINFO 0
#define _TRACE_RI_RAWDATA 0
#define _TRACE_3DINPUT_PERIOD 0

#ifdef _WIN64
typedef unsigned __int64 QWORD;
#endif

// object angular velocity per mouse tick 0.008 milliradians per second per count
static const double k3dmouseAngularVelocity = 8.0e-6; // radians per second per count

static const int kTimeToLive = 5;

enum e3dconnexion_pid {
   eSpacePilot = 0xc625,
   eSpaceNavigator = 0xc626,
   eSpaceExplorer = 0xc627,
   eSpaceNavigatorForNotebooks = 0xc628,
   eSpacePilotPRO = 0xc629
};

enum e3dmouse_virtual_key
{
   V3DK_INVALID=0
   , V3DK_MENU=1, V3DK_FIT
   , V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT, V3DK_BOTTOM, V3DK_BACK
   , V3DK_CW, V3DK_CCW
   , V3DK_ISO1, V3DK_ISO2
   , V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6, V3DK_7, V3DK_8, V3DK_9, V3DK_10
   , V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL
   , V3DK_ROTATE, V3DK_PANZOOM, V3DK_DOMINANT
   , V3DK_PLUS, V3DK_MINUS
};

struct tag_VirtualKeys
{
   e3dconnexion_pid pid;
   size_t nKeys;
   e3dmouse_virtual_key *vkeys;
};

static const e3dmouse_virtual_key SpaceExplorerKeys [] =
{
   V3DK_INVALID     // there is no button 0
   , V3DK_1, V3DK_2
   , V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT
   , V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL
   , V3DK_FIT, V3DK_MENU
   , V3DK_PLUS, V3DK_MINUS
   , V3DK_ROTATE
};

static const e3dmouse_virtual_key SpacePilotKeys [] =
{
   V3DK_INVALID
   , V3DK_1, V3DK_2, V3DK_3, V3DK_4, V3DK_5, V3DK_6
   , V3DK_TOP, V3DK_LEFT, V3DK_RIGHT, V3DK_FRONT
   , V3DK_ESC, V3DK_ALT, V3DK_SHIFT, V3DK_CTRL
   , V3DK_FIT, V3DK_MENU
   , V3DK_PLUS, V3DK_MINUS
   , V3DK_DOMINANT, V3DK_ROTATE
};

static const struct tag_VirtualKeys _3dmouseVirtualKeys[]=
{
   eSpacePilot
   , sizeof(SpacePilotKeys)/sizeof(SpacePilotKeys[0])
   , const_cast<e3dmouse_virtual_key *>(SpacePilotKeys),
   eSpaceExplorer
   , sizeof(SpaceExplorerKeys)/sizeof(SpaceExplorerKeys[0])
   , const_cast<e3dmouse_virtual_key *>(SpaceExplorerKeys)
};

/*!
	Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device to the standard 3d mouse virtual key definition.

	\a pid USB Product ID (PID) of 3D mouse device
	\a hidKeyCode  Hid keycode as retrieved from a Raw Input packet

	\return The standard 3d mouse virtual key (button identifier) or zero if an error occurs.

	Converts a hid device keycode (button identifier) of a pre-2009 3Dconnexion USB device
	to the standard 3d mouse virtual key definition.
*/

unsigned short HidToVirtualKey(unsigned long pid, unsigned short hidKeyCode)
{
   unsigned short virtualkey=hidKeyCode;
   for (size_t i=0; i<sizeof(_3dmouseVirtualKeys)/sizeof(_3dmouseVirtualKeys[0]); ++i)
   {
	  if (pid == _3dmouseVirtualKeys[i].pid)
	  {
		 if (hidKeyCode < _3dmouseVirtualKeys[i].nKeys)
			virtualkey = _3dmouseVirtualKeys[i].vkeys[hidKeyCode];
		 else
			virtualkey = V3DK_INVALID;
		 break;
	  }
   }
   // Remaining devices are unchanged
   return virtualkey;
}


static Mouse3DInput* gMouseInput = 0;

122
bool Mouse3DInput::nativeEventFilter(const QByteArray &eventType, void* msg, long* result)
123
{
124
    Q_UNUSED(eventType);
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
	if (gMouseInput == 0) return false;

	MSG* message = (MSG*)(msg);

	if (message->message == WM_INPUT) {
		HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(message->lParam);
		gMouseInput->OnRawInput(RIM_INPUT,hRawInput);
		if (result != 0)  {
			result = 0;
		}
		return true;
	}

	return false;
}


Mouse3DInput::Mouse3DInput(QWidget* widget) :
									QObject(widget)
{
	fLast3dmouseInputTime = 0;

147
	InitializeRawInput((HWND)widget->winId());
148 149

	gMouseInput = this;
150
	qApp->installNativeEventFilter(this);
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
}

Mouse3DInput::~Mouse3DInput()
{
	if (gMouseInput == this) {
		gMouseInput = 0;
	}
}

/*!
	Access the mouse parameters structure
*/
I3dMouseParam& Mouse3DInput::MouseParams()
{
	return f3dMouseParams;
}

/*!
	Access the mouse parameters structure
*/
const I3dMouseParam& Mouse3DInput::MouseParams() const
{
	return f3dMouseParams;
}

/*!
	Called with the processed motion data when a 3D mouse event is received

	The default implementation emits a Move3d signal with the motion data
*/
void Mouse3DInput::Move3d(HANDLE device, std::vector<float>& motionData)
{
	Q_UNUSED(device);
	emit Move3d(motionData);
}

/*!
	Called when a 3D mouse key is pressed

	The default implementation emits a On3dmouseKeyDown signal with the key code.
*/
void Mouse3DInput::On3dmouseKeyDown(HANDLE device, int virtualKeyCode)
{
	Q_UNUSED(device);
	emit On3dmouseKeyDown(virtualKeyCode);
}

/*!
	Called when a 3D mouse key is released

	The default implementation emits a On3dmouseKeyUp signal with the key code.
*/
void Mouse3DInput::On3dmouseKeyUp(HANDLE device, int virtualKeyCode)
{
	Q_UNUSED(device);
	emit On3dmouseKeyUp(virtualKeyCode);
}

/*!
	Get an initialized array of PRAWINPUTDEVICE for the 3D devices

	pNumDevices returns the number of devices to register. Currently this is always 1.
 */
static PRAWINPUTDEVICE GetDevicesToRegister(unsigned int* pNumDevices)
{
	// Array of raw input devices to register
	static RAWINPUTDEVICE sRawInputDevices[] = {
		{0x01, 0x08, 0x00, 0x00} // Usage Page = 0x01 Generic Desktop Page, Usage Id= 0x08 Multi-axis Controller
	};

	if (pNumDevices) {
		*pNumDevices = sizeof(sRawInputDevices) / sizeof(sRawInputDevices[0]);
	}

	return sRawInputDevices;
}

/*!
	Detect the 3D mouse
*/
bool Mouse3DInput::Is3dmouseAttached()
{
	unsigned int numDevicesOfInterest = 0;
	PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevicesOfInterest);

	unsigned int nDevices = 0;

	if (::GetRawInputDeviceList(NULL, &nDevices, sizeof(RAWINPUTDEVICELIST)) != 0) {
		return false;
	}

	if (nDevices == 0) return false;

	std::vector<RAWINPUTDEVICELIST> rawInputDeviceList(nDevices);
	if (::GetRawInputDeviceList(&rawInputDeviceList[0], &nDevices, sizeof(RAWINPUTDEVICELIST)) == static_cast<unsigned int>(-1)) {
		return false;
	}

	for (unsigned int i = 0; i < nDevices; ++i) {
		RID_DEVICE_INFO rdi = {sizeof(rdi)};
		unsigned int cbSize = sizeof(rdi);

		if (GetRawInputDeviceInfo(rawInputDeviceList[i].hDevice, RIDI_DEVICEINFO, &rdi, &cbSize) > 0) {
			//skip non HID and non logitec (3DConnexion) devices
			if (rdi.dwType != RIM_TYPEHID || rdi.hid.dwVendorId != LOGITECH_VENDOR_ID) {
				continue;
			}

			//check if devices matches Multi-axis Controller
			for (unsigned int j = 0; j < numDevicesOfInterest; ++j) {
				if (devicesToRegister[j].usUsage == rdi.hid.usUsage
						&& devicesToRegister[j].usUsagePage == rdi.hid.usUsagePage) {
					return true;
				}
			}
		}
	}
	return false;
}



/*!
	Initialize the window to recieve raw-input messages

	This needs to be called initially so that Windows will send the messages from the 3D mouse to the window.
*/
bool Mouse3DInput::InitializeRawInput(HWND hwndTarget)
{
	fWindow = hwndTarget;

	// Simply fail if there is no window
	if (!hwndTarget)  return false;

	unsigned int numDevices = 0;
	PRAWINPUTDEVICE devicesToRegister = GetDevicesToRegister(&numDevices);

	if (numDevices == 0) return false;

	// Get OS version.
	OSVERSIONINFO osvi = {sizeof(OSVERSIONINFO),0};
	::GetVersionEx(&osvi);

	unsigned int cbSize = sizeof (devicesToRegister[0]);
	for (size_t i = 0; i < numDevices; i++) {
		// Set the target window to use
		//devicesToRegister[i].hwndTarget = hwndTarget;

		// If Vista or newer, enable receiving the WM_INPUT_DEVICE_CHANGE message.
		if (osvi.dwMajorVersion >= 6) {
			devicesToRegister[i].dwFlags |= RIDEV_DEVNOTIFY;
		}
	}
	return (::RegisterRawInputDevices(devicesToRegister, numDevices, cbSize) != FALSE);
}


/*!
	Get the raw input data from Windows

	Includes workaround for incorrect alignment of the RAWINPUT structure on x64 os
	when running as Wow64 (copied directly from 3DConnexion code)
*/

UINT Mouse3DInput::GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
{
#ifdef _WIN64
	return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
#else
	BOOL bIsWow64 = FALSE;
	::IsWow64Process(GetCurrentProcess(), &bIsWow64);
	if (!bIsWow64 || pData==NULL) {
		return ::GetRawInputBuffer(pData, pcbSize, cbSizeHeader);
	} else {
		HWND hwndTarget = fWindow; //fParent->winId();

		size_t cbDataSize=0;
		UINT nCount=0;
		PRAWINPUT pri = pData;

		MSG msg;
		while (PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_NOREMOVE)) {
			HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>(msg.lParam);
			size_t cbSize = *pcbSize - cbDataSize;
			if (::GetRawInputData(hRawInput, RID_INPUT, pri, &cbSize, cbSizeHeader) == static_cast<UINT>(-1)) {
				if (nCount==0) {
					return static_cast<UINT>(-1);
				}  else {
					break;
				}
			}
			++nCount;

			// Remove the message for the data just read
			PeekMessage(&msg, hwndTarget, WM_INPUT, WM_INPUT, PM_REMOVE);

			pri = NEXTRAWINPUTBLOCK(pri);
			cbDataSize = reinterpret_cast<ULONG_PTR>(pri) - reinterpret_cast<ULONG_PTR>(pData);
			if (cbDataSize >= *pcbSize) {
				cbDataSize = *pcbSize;
				break;
			}
		}
		return nCount;
	}
#endif
}

/*!
	Process the raw input device data

	On3dmouseInput() does all the preprocessing of the rawinput device data before
	finally calling the Move3d method.
*/

void Mouse3DInput::On3dmouseInput()
{
	// Don't do any data processing in background
	bool bIsForeground = (::GetActiveWindow() != NULL);
	if (!bIsForeground) {
		// set all cached data to zero so that a zero event is seen and the cached data deleted
		for (std::map<HANDLE, TInputData>::iterator it = fDevice2Data.begin(); it != fDevice2Data.end(); it++) {
			it->second.fAxes.assign(6, .0);
			it->second.fIsDirty = true;
		}
	}

	DWORD dwNow = ::GetTickCount();           // Current time;
	DWORD dwElapsedTime;                      // Elapsed time since we were last here

	if (0 == fLast3dmouseInputTime) {
		dwElapsedTime = 10;                    // System timer resolution
	} else {
		dwElapsedTime = dwNow - fLast3dmouseInputTime;
		if (fLast3dmouseInputTime > dwNow) {
			dwElapsedTime = ~dwElapsedTime+1;
		}
		if (dwElapsedTime<1) {
			dwElapsedTime=1;
		} else if (dwElapsedTime > 500) {
			// Check for wild numbers because the device was removed while sending data
			dwElapsedTime = 10;
		}
	}

#if _TRACE_3DINPUT_PERIOD
	qDebug("On3DmouseInput() period is %dms\n", dwElapsedTime);
#endif

	float mouseData2Rotation = k3dmouseAngularVelocity;
	// v = w * r,  we don't know r yet so lets assume r=1.)
	float mouseData2PanZoom = k3dmouseAngularVelocity;

	// Grab the I3dmouseParam interface
	 I3dMouseParam& i3dmouseParam = f3dMouseParams;
	 // Take a look at the users preferred speed setting and adjust the sensitivity accordingly
	 I3dMouseSensor::ESpeed speedSetting = i3dmouseParam.GetSpeed();
	 // See "Programming for the 3D Mouse", Section 5.1.3
	float speed = (speedSetting == I3dMouseSensor::kLowSpeed ? 0.25f : speedSetting == I3dMouseSensor::kHighSpeed ?  4.f : 1.f);

	 // Multiplying by the following will convert the 3d mouse data to real world units
	mouseData2PanZoom *= speed;
	mouseData2Rotation *= speed;

	std::map<HANDLE, TInputData>::iterator iterator=fDevice2Data.begin();
	while (iterator != fDevice2Data.end()) {

		// If we have not received data for a while send a zero event
		if ((--(iterator->second.fTimeToLive)) == 0) {
			iterator->second.fAxes.assign(6, .0);
		} else if (/*!t_bPoll3dmouse &&*/ !iterator->second.fIsDirty) {
		  // If we are not polling then only handle the data that was actually received
			++iterator;
			continue;
		}
		iterator->second.fIsDirty=false;

		// get a copy of the device
		HANDLE hdevice = iterator->first;

		// get a copy of the motion vectors and apply the user filters
		std::vector<float> motionData = iterator->second.fAxes;

		// apply the user filters

		// Pan Zoom filter
		// See "Programming for the 3D Mouse", Section 5.1.2
		if (!i3dmouseParam.IsPanZoom()) {
			// Pan zoom is switched off so set the translation vector values to zero
			motionData[0] =  motionData[1] =  motionData[2] = 0.;
		}

		// Rotate filter
		// See "Programming for the 3D Mouse", Section 5.1.1
		if (!i3dmouseParam.IsRotate()) {
			// Rotate is switched off so set the rotation vector values to zero
			motionData[3] =  motionData[4] =  motionData[5] = 0.;
		}

		// convert the translation vector into physical data
		for (int axis = 0; axis < 3; axis++) {
			 motionData[axis] *= mouseData2PanZoom;
		 }
		// convert the directed Rotate vector into physical data
		// See "Programming for the 3D Mouse", Section 7.2.2
		for (int axis = 3; axis < 6; axis++) {
			motionData[axis] *= mouseData2Rotation;
		}

		// Now that the data has had the filters and sensitivty settings applied
		// calculate the displacements since the last view update
		for (int axis = 0; axis < 6; axis++) {
			motionData[axis] *= dwElapsedTime;
		}


		// Now a bit of book keeping before passing on the data
		if (iterator->second.IsZero()) {
			iterator = fDevice2Data.erase(iterator);
		} else {
			++iterator;
		}

		// Work out which will be the next device
		HANDLE hNextDevice = 0;
		if (iterator != fDevice2Data.end()) {
			hNextDevice = iterator->first;
		}

		 // Pass the 3dmouse input to the view controller
		 Move3d(hdevice, motionData);

		// Because we don't know what happened in the previous call, the cache might have
		// changed so reload the iterator
		iterator = fDevice2Data.find(hNextDevice);
   }

	if (!fDevice2Data.empty()) {
		fLast3dmouseInputTime = dwNow;
	} else {
		fLast3dmouseInputTime = 0;
	}
}

/*!
	Called when new raw input data is available
*/
void Mouse3DInput::OnRawInput(UINT nInputCode, HRAWINPUT hRawInput)
{
	const size_t cbSizeOfBuffer=1024;
	BYTE pBuffer[cbSizeOfBuffer];

	PRAWINPUT pRawInput = reinterpret_cast<PRAWINPUT>(pBuffer);
	UINT cbSize = cbSizeOfBuffer;

	if (::GetRawInputData(hRawInput, RID_INPUT, pRawInput, &cbSize, sizeof(RAWINPUTHEADER)) == static_cast<UINT>(-1)) {
		return;
	}

	bool b3dmouseInput = TranslateRawInputData(nInputCode, pRawInput);
	::DefRawInputProc(&pRawInput, 1, sizeof(RAWINPUTHEADER));

	// Check for any buffered messages
	cbSize = cbSizeOfBuffer;
	UINT nCount = this->GetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER));
	if (nCount == (UINT)-1) {
		 qDebug ("GetRawInputBuffer returned error %d\n", GetLastError());
	}

	while (nCount>0 && nCount !=  static_cast<UINT>(-1)) {
		PRAWINPUT pri = pRawInput;
		UINT nInput;
		for (nInput=0; nInput<nCount; ++nInput) {
			b3dmouseInput |= TranslateRawInputData(nInputCode, pri);
			// clean the buffer
			::DefRawInputProc(&pri, 1, sizeof(RAWINPUTHEADER));

			pri = NEXTRAWINPUTBLOCK(pri);
		}
		cbSize = cbSizeOfBuffer;
		nCount = this->GetRawInputBuffer(pRawInput, &cbSize, sizeof(RAWINPUTHEADER));
	}

	// If we have mouse input data for the app then tell tha app about it
	if (b3dmouseInput) {
		On3dmouseInput();
	}
}



bool Mouse3DInput::TranslateRawInputData(UINT nInputCode, PRAWINPUT pRawInput)
{
	bool bIsForeground = (nInputCode == RIM_INPUT);

#if _TRACE_RI_TYPE
	qDebug("Rawinput.header.dwType=0x%x\n", pRawInput->header.dwType);
#endif
	// We are not interested in keyboard or mouse data received via raw input
	if (pRawInput->header.dwType != RIM_TYPEHID) return false;

#if _TRACE_RIDI_DEVICENAME
	UINT dwSize=0;
	if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, NULL, &dwSize) == 0)  {
		std::vector<wchar_t> szDeviceName(dwSize+1);
		if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICENAME, &szDeviceName[0],	&dwSize) >0) {
			qDebug("Device Name = %s\nDevice handle = 0x%x\n", &szDeviceName[0], pRawInput->header.hDevice);
		}
   }
#endif

	RID_DEVICE_INFO sRidDeviceInfo;
	sRidDeviceInfo.cbSize = sizeof(RID_DEVICE_INFO);
	UINT cbSize = sizeof(RID_DEVICE_INFO);

	if (::GetRawInputDeviceInfo(pRawInput->header.hDevice, RIDI_DEVICEINFO, &sRidDeviceInfo, &cbSize) == cbSize) {
#if _TRACE_RIDI_DEVICEINFO
		switch (sRidDeviceInfo.dwType)  {
			case RIM_TYPEMOUSE:
				qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEMOUSE\n");
				break;
			case RIM_TYPEKEYBOARD:
				qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEKEYBOARD\n");
				break;
			case RIM_TYPEHID:
				qDebug("\tsRidDeviceInfo.dwType=RIM_TYPEHID\n");
				qDebug("\tVendor=0x%x\n\tProduct=0x%x\n\tUsagePage=0x%x\n\tUsage=0x%x\n",
						sRidDeviceInfo.hid.dwVendorId,
						sRidDeviceInfo.hid.dwProductId,
						sRidDeviceInfo.hid.usUsagePage,
						sRidDeviceInfo.hid.usUsage);
				break;
		}
#endif

		if (sRidDeviceInfo.hid.dwVendorId == LOGITECH_VENDOR_ID) {
			if (pRawInput->data.hid.bRawData[0] == 0x01) { // Translation vector

				TInputData& deviceData = fDevice2Data[pRawInput->header.hDevice];
				deviceData.fTimeToLive = kTimeToLive;
				if (bIsForeground) {
					short* pnRawData = reinterpret_cast<short*>(&pRawInput->data.hid.bRawData[1]);
					// Cache the pan zoom data
					deviceData.fAxes[0] = static_cast<float>(pnRawData[0]);
					deviceData.fAxes[1] = static_cast<float>(pnRawData[1]);
					deviceData.fAxes[2] = static_cast<float>(pnRawData[2]);

#if _TRACE_RI_RAWDATA
					qDebug("Pan/Zoom RI Data =\t0x%x,\t0x%x,\t0x%x\n",
									pnRawData[0],  pnRawData[1],  pnRawData[2]);
#endif
					if (pRawInput->data.hid.dwSizeHid >= 13) {// Highspeed package
						// Cache the rotation data
						deviceData.fAxes[3] = static_cast<float>(pnRawData[3]);
						deviceData.fAxes[4] = static_cast<float>(pnRawData[4]);
						deviceData.fAxes[5] = static_cast<float>(pnRawData[5]);
						deviceData.fIsDirty = true;
#if _TRACE_RI_RAWDATA
						qDebug("Rotation RI Data =\t0x%x,\t0x%x,\t0x%x\n",
							 pnRawData[3], pnRawData[4], pnRawData[5]);
#endif
						return true;
					}
				} else { // Zero out the data if the app is not in forground
					deviceData.fAxes.assign(6, 0.f);
				}
			} else if (pRawInput->data.hid.bRawData[0] == 0x02) { // Rotation vector
				// If we are not in foreground do nothing
				// The rotation vector was zeroed out with the translation vector in the previous message
				if (bIsForeground) {
					TInputData& deviceData = fDevice2Data[pRawInput->header.hDevice];
					deviceData.fTimeToLive = kTimeToLive;

					short* pnRawData = reinterpret_cast<short*>(&pRawInput->data.hid.bRawData[1]);
					// Cache the rotation data
					deviceData.fAxes[3] = static_cast<float>(pnRawData[0]);
					deviceData.fAxes[4] = static_cast<float>(pnRawData[1]);
					deviceData.fAxes[5] = static_cast<float>(pnRawData[2]);
					deviceData.fIsDirty = true;

#if _TRACE_RI_RAWDATA
					qDebug("Rotation RI Data =\t0x%x,\t0x%x,\t0x%x\n",
						pnRawData[0],  pnRawData[1], pnRawData[2]);
#endif
					return true;
				}
			} else if (pRawInput->data.hid.bRawData[0] == 0x03)  { // Keystate change
				// this is a package that contains 3d mouse keystate information
				// bit0=key1, bit=key2 etc.


				unsigned long dwKeystate = *reinterpret_cast<unsigned long*>(&pRawInput->data.hid.bRawData[1]);
#if _TRACE_RI_RAWDATA
				qDebug("ButtonData =0x%x\n", dwKeystate);
#endif
				// Log the keystate changes
				unsigned long dwOldKeystate = fDevice2Keystate[pRawInput->header.hDevice];
				if (dwKeystate != 0) {
					fDevice2Keystate[pRawInput->header.hDevice] = dwKeystate;
				} else {
					fDevice2Keystate.erase(pRawInput->header.hDevice);
				}

				//  Only call the keystate change handlers if the app is in foreground
				if (bIsForeground) {
					unsigned long dwChange = dwKeystate ^ dwOldKeystate;


					for (int nKeycode=1; nKeycode<33; nKeycode++) {
						if (dwChange & 0x01) {
							int nVirtualKeyCode = HidToVirtualKey(sRidDeviceInfo.hid.dwProductId, nKeycode);
							if (nVirtualKeyCode) {
								if (dwKeystate&0x01) {
									On3dmouseKeyDown(pRawInput->header.hDevice, nVirtualKeyCode);
								} else {
									On3dmouseKeyUp(pRawInput->header.hDevice, nVirtualKeyCode);
								}
							}
						}
						dwChange >>=1;
						dwKeystate >>=1;
					}
				}
			}
		}
   }
   return false;
}