You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
678 lines
20 KiB
678 lines
20 KiB
|
|
#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; |
|
|
|
bool Mouse3DInput::nativeEventFilter(const QByteArray &eventType, void* msg, long* result) |
|
{ |
|
Q_UNUSED(eventType); |
|
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; |
|
|
|
InitializeRawInput((HWND)widget->winId()); |
|
|
|
gMouseInput = this; |
|
qApp->installNativeEventFilter(this); |
|
} |
|
|
|
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; |
|
}
|
|
|