2014-04-12 10:44:38 +00:00
|
|
|
/* LilyPad - Pad plugin for PS2 Emulator
|
|
|
|
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
|
|
|
|
*
|
|
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the
|
|
|
|
* terms of the GNU Lesser General Public License as published by the Free
|
|
|
|
* Software Found- ation, either version 3 of the License, or (at your option)
|
|
|
|
* any later version.
|
|
|
|
*
|
|
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
|
* details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with PCSX2. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2010-04-24 21:37:39 +00:00
|
|
|
#include "Global.h"
|
|
|
|
#include "InputManager.h"
|
|
|
|
#include "WindowsMessaging.h"
|
|
|
|
#include "VKey.h"
|
|
|
|
#include "DeviceEnumerator.h"
|
|
|
|
#include "WndProcEater.h"
|
|
|
|
#include "WindowsKeyboard.h"
|
|
|
|
#include "WindowsMouse.h"
|
|
|
|
|
|
|
|
ExtraWndProcResult RawInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output);
|
|
|
|
|
|
|
|
int GetRawKeyboards(HWND hWnd) {
|
|
|
|
RAWINPUTDEVICE Rid;
|
|
|
|
Rid.hwndTarget = hWnd;
|
|
|
|
|
|
|
|
Rid.dwFlags = 0;
|
|
|
|
Rid.usUsagePage = 0x01;
|
|
|
|
Rid.usUsage = 0x06;
|
2016-02-25 22:24:02 +00:00
|
|
|
return RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
2010-04-24 21:37:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReleaseRawKeyboards() {
|
|
|
|
RAWINPUTDEVICE Rid;
|
|
|
|
Rid.hwndTarget = 0;
|
|
|
|
|
|
|
|
Rid.dwFlags = RIDEV_REMOVE;
|
|
|
|
Rid.usUsagePage = 0x01;
|
|
|
|
Rid.usUsage = 0x06;
|
2016-02-25 22:24:02 +00:00
|
|
|
RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
2010-04-24 21:37:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int GetRawMice(HWND hWnd) {
|
|
|
|
RAWINPUTDEVICE Rid;
|
|
|
|
Rid.hwndTarget = hWnd;
|
|
|
|
|
|
|
|
Rid.dwFlags = RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE;
|
|
|
|
Rid.usUsagePage = 0x01;
|
|
|
|
Rid.usUsage = 0x02;
|
2016-02-25 22:24:02 +00:00
|
|
|
return RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
2010-04-24 21:37:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ReleaseRawMice() {
|
|
|
|
RAWINPUTDEVICE Rid;
|
|
|
|
Rid.hwndTarget = 0;
|
|
|
|
|
|
|
|
Rid.dwFlags = RIDEV_REMOVE;
|
|
|
|
Rid.usUsagePage = 0x01;
|
|
|
|
Rid.usUsage = 0x02;
|
2016-02-25 22:24:02 +00:00
|
|
|
RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
2010-04-24 21:37:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Count of active raw keyboard devices.
|
|
|
|
// when it gets to 0, release them all.
|
|
|
|
static int rawKeyboardActivatedCount = 0;
|
|
|
|
// Same for mice.
|
|
|
|
static int rawMouseActivatedCount = 0;
|
|
|
|
|
|
|
|
class RawInputKeyboard : public WindowsKeyboard {
|
|
|
|
public:
|
|
|
|
HANDLE hDevice;
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2010-04-24 21:37:39 +00:00
|
|
|
RawInputKeyboard(HANDLE hDevice, wchar_t *name, wchar_t *instanceID=0) : WindowsKeyboard(RAW, name, instanceID) {
|
|
|
|
this->hDevice = hDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Activate(InitInfo *initInfo) {
|
|
|
|
Deactivate();
|
|
|
|
|
|
|
|
hWndProc = initInfo->hWndProc;
|
|
|
|
|
|
|
|
active = 1;
|
|
|
|
if (!rawKeyboardActivatedCount++) {
|
|
|
|
if (!rawMouseActivatedCount)
|
|
|
|
hWndProc->Eat(RawInputWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES);
|
|
|
|
|
|
|
|
if (!GetRawKeyboards(hWndProc->hWndEaten)) {
|
|
|
|
Deactivate();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
InitState();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Deactivate() {
|
|
|
|
FreeState();
|
|
|
|
if (active) {
|
|
|
|
active = 0;
|
|
|
|
rawKeyboardActivatedCount --;
|
|
|
|
if (!rawKeyboardActivatedCount) {
|
|
|
|
ReleaseRawKeyboards();
|
|
|
|
if (!rawMouseActivatedCount)
|
|
|
|
hWndProc->ReleaseExtraProc(RawInputWndProc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class RawInputMouse : public WindowsMouse {
|
|
|
|
public:
|
|
|
|
HANDLE hDevice;
|
|
|
|
|
|
|
|
RawInputMouse(HANDLE hDevice, wchar_t *name, wchar_t *instanceID=0, wchar_t *productID=0) : WindowsMouse(RAW, 0, name, instanceID, productID) {
|
|
|
|
this->hDevice = hDevice;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Activate(InitInfo *initInfo) {
|
|
|
|
Deactivate();
|
|
|
|
|
|
|
|
hWndProc = initInfo->hWndProc;
|
|
|
|
|
|
|
|
active = 1;
|
|
|
|
|
|
|
|
// Have to be careful with order. At worst, one unmatched call to ReleaseRawMice on
|
|
|
|
// EatWndProc fail. In all other cases, no unmatched initialization/cleanup
|
|
|
|
// lines.
|
|
|
|
if (!rawMouseActivatedCount++) {
|
|
|
|
GetMouseCapture(hWndProc->hWndEaten);
|
|
|
|
if (!rawKeyboardActivatedCount)
|
|
|
|
hWndProc->Eat(RawInputWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES);
|
2010-04-25 00:31:27 +00:00
|
|
|
|
2010-04-24 21:37:39 +00:00
|
|
|
if (!GetRawMice(hWndProc->hWndEaten)) {
|
|
|
|
Deactivate();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AllocState();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Deactivate() {
|
|
|
|
FreeState();
|
|
|
|
if (active) {
|
|
|
|
active = 0;
|
|
|
|
rawMouseActivatedCount --;
|
|
|
|
if (!rawMouseActivatedCount) {
|
|
|
|
ReleaseRawMice();
|
|
|
|
ReleaseMouseCapture();
|
|
|
|
if (!rawKeyboardActivatedCount) {
|
|
|
|
hWndProc->ReleaseExtraProc(RawInputWndProc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ExtraWndProcResult RawInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output) {
|
|
|
|
if (uMsg == WM_INPUT) {
|
2016-02-25 22:24:02 +00:00
|
|
|
if (GET_RAWINPUT_CODE_WPARAM (wParam) == RIM_INPUT) {
|
2010-04-24 21:37:39 +00:00
|
|
|
RAWINPUT in;
|
|
|
|
unsigned int size = sizeof(RAWINPUT);
|
2016-02-25 22:24:02 +00:00
|
|
|
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &in, &size, sizeof(RAWINPUTHEADER)) > 0) {
|
2010-04-24 21:37:39 +00:00
|
|
|
for (int i=0; i<dm->numDevices; i++) {
|
|
|
|
Device *dev = dm->devices[i];
|
|
|
|
if (dev->api != RAW || !dev->active) continue;
|
|
|
|
if (in.header.dwType == RIM_TYPEKEYBOARD && dev->type == KEYBOARD) {
|
|
|
|
RawInputKeyboard* rik = (RawInputKeyboard*)dev;
|
|
|
|
if (rik->hDevice != in.header.hDevice) continue;
|
|
|
|
|
|
|
|
u32 uMsg = in.data.keyboard.Message;
|
|
|
|
if (!(in.data.keyboard.VKey>>8))
|
|
|
|
rik->UpdateKey((u8) in.data.keyboard.VKey, (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN));
|
|
|
|
}
|
|
|
|
else if (in.header.dwType == RIM_TYPEMOUSE && dev->type == MOUSE) {
|
|
|
|
RawInputMouse* rim = (RawInputMouse*)dev;
|
|
|
|
if (rim->hDevice != in.header.hDevice) continue;
|
|
|
|
if (in.data.mouse.usFlags) {
|
|
|
|
// Never been set for me, and specs on what most of them
|
|
|
|
// actually mean is sorely lacking. Also, specs erroneously
|
|
|
|
// indicate MOUSE_MOVE_RELATIVE is a flag, when it's really
|
|
|
|
// 0...
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned short buttons = in.data.mouse.usButtonFlags & 0x3FF;
|
|
|
|
int button = 0;
|
|
|
|
while (buttons) {
|
|
|
|
if (buttons & 3) {
|
|
|
|
// 2 is up, 1 is down. Up takes precedence over down.
|
|
|
|
rim->UpdateButton(button, !(buttons & 2));
|
|
|
|
}
|
|
|
|
button++;
|
|
|
|
buttons >>= 2;
|
|
|
|
}
|
|
|
|
if (in.data.mouse.usButtonFlags & RI_MOUSE_WHEEL) {
|
|
|
|
rim->UpdateAxis(2, ((short)in.data.mouse.usButtonData)/WHEEL_DELTA);
|
|
|
|
}
|
|
|
|
if (in.data.mouse.lLastX || in.data.mouse.lLastY) {
|
|
|
|
rim->UpdateAxis(0, in.data.mouse.lLastX);
|
|
|
|
rim->UpdateAxis(1, in.data.mouse.lLastY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (uMsg == WM_ACTIVATE) {
|
|
|
|
for (int i=0; i<dm->numDevices; i++) {
|
|
|
|
Device *dev = dm->devices[i];
|
|
|
|
if (dev->api != RAW || dev->physicalControlState == 0) continue;
|
|
|
|
memset(dev->physicalControlState, 0, sizeof(int) * dev->numPhysicalControls);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (uMsg == WM_SIZE && rawMouseActivatedCount) {
|
|
|
|
// Doesn't really matter for raw mice, as I disable legacy stuff, but shouldn't hurt.
|
|
|
|
WindowsMouse::WindowResized(hWnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return CONTINUE_BLISSFULLY;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EnumRawInputDevices() {
|
|
|
|
int count = 0;
|
2016-02-25 22:24:02 +00:00
|
|
|
if (GetRawInputDeviceList(0, (unsigned int*)&count, sizeof(RAWINPUTDEVICELIST)) != (UINT)-1 && count > 0) {
|
2010-04-24 21:37:39 +00:00
|
|
|
wchar_t *instanceID = (wchar_t *) malloc(41000*sizeof(wchar_t));
|
|
|
|
wchar_t *keyName = instanceID + 11000;
|
|
|
|
wchar_t *displayName = keyName + 10000;
|
|
|
|
wchar_t *productID = displayName + 10000;
|
|
|
|
|
|
|
|
RAWINPUTDEVICELIST *list = (RAWINPUTDEVICELIST*) malloc(sizeof(RAWINPUTDEVICELIST) * count);
|
|
|
|
int keyboardCount = 1;
|
|
|
|
int mouseCount = 1;
|
2016-02-25 22:24:02 +00:00
|
|
|
count = GetRawInputDeviceList(list, (unsigned int*)&count, sizeof(RAWINPUTDEVICELIST));
|
2010-04-24 21:37:39 +00:00
|
|
|
|
|
|
|
// Not necessary, but reminder that count is -1 on failure.
|
|
|
|
if (count > 0) {
|
|
|
|
for (int i=0; i<count; i++) {
|
|
|
|
if (list[i].dwType != RIM_TYPEKEYBOARD && list[i].dwType != RIM_TYPEMOUSE) continue;
|
|
|
|
|
|
|
|
UINT bufferLen = 10000;
|
2016-02-25 22:24:02 +00:00
|
|
|
int nameLen = GetRawInputDeviceInfo(list[i].hDevice, RIDI_DEVICENAME, instanceID, &bufferLen);
|
2010-04-24 21:37:39 +00:00
|
|
|
if (nameLen >= 4) {
|
|
|
|
// nameLen includes terminating null.
|
|
|
|
nameLen--;
|
|
|
|
|
|
|
|
// Strip out GUID parts of instanceID to make it a generic product id,
|
|
|
|
// and reformat it to point to registry entry containing device description.
|
|
|
|
wcscpy(productID, instanceID);
|
|
|
|
wchar_t *temp = 0;
|
|
|
|
for (int j=0; j<3; j++) {
|
|
|
|
wchar_t *s = wcschr(productID, '#');
|
|
|
|
if (!s) break;
|
|
|
|
*s = '\\';
|
|
|
|
if (j==2) {
|
|
|
|
*s = 0;
|
|
|
|
}
|
|
|
|
if (j==1) temp = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
wsprintfW(keyName, L"SYSTEM\\CurrentControlSet\\Enum%s", productID+3);
|
|
|
|
if (temp) *temp = 0;
|
|
|
|
int haveDescription = 0;
|
|
|
|
HKEY hKey;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &hKey)) {
|
|
|
|
DWORD type;
|
|
|
|
DWORD len = 10000 * sizeof(wchar_t);
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueExW(hKey, L"DeviceDesc", 0, &type, (BYTE*)displayName, &len) &&
|
|
|
|
len && type == REG_SZ) {
|
|
|
|
wchar_t *temp2 = wcsrchr(displayName, ';');
|
|
|
|
if (!temp2) temp2 = displayName;
|
|
|
|
else temp2++;
|
|
|
|
// Could do without this, but more effort than it's worth.
|
|
|
|
wcscpy(keyName, temp2);
|
|
|
|
haveDescription = 1;
|
|
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
}
|
|
|
|
if (list[i].dwType == RIM_TYPEKEYBOARD) {
|
|
|
|
if (!haveDescription) wsprintfW(displayName, L"Raw Keyboard %i", keyboardCount++);
|
|
|
|
else wsprintfW(displayName, L"Raw KB: %s", keyName);
|
|
|
|
dm->AddDevice(new RawInputKeyboard(list[i].hDevice, displayName, instanceID));
|
|
|
|
}
|
|
|
|
else if (list[i].dwType == RIM_TYPEMOUSE) {
|
|
|
|
if (!haveDescription) wsprintfW(displayName, L"Raw Mouse %i", mouseCount++);
|
|
|
|
else wsprintfW(displayName, L"Raw MS: %s", keyName);
|
|
|
|
dm->AddDevice(new RawInputMouse(list[i].hDevice, displayName, instanceID, productID));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(list);
|
|
|
|
free(instanceID);
|
|
|
|
dm->AddDevice(new RawInputKeyboard(0, L"Simulated Keyboard"));
|
|
|
|
dm->AddDevice(new RawInputMouse(0, L"Simulated Mouse"));
|
|
|
|
}
|
|
|
|
}
|