mirror of
https://github.com/libretro/pcsx2.git
synced 2025-02-22 02:21:51 +00:00

It's been available since XP and it's not special like XInput (where we might have SCP in the middle) so let's have the linker resolve the functions at link time.
306 lines
9.1 KiB
C++
306 lines
9.1 KiB
C++
/* 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/>.
|
|
*/
|
|
|
|
#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;
|
|
return RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
|
}
|
|
|
|
void ReleaseRawKeyboards() {
|
|
RAWINPUTDEVICE Rid;
|
|
Rid.hwndTarget = 0;
|
|
|
|
Rid.dwFlags = RIDEV_REMOVE;
|
|
Rid.usUsagePage = 0x01;
|
|
Rid.usUsage = 0x06;
|
|
RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
|
}
|
|
|
|
int GetRawMice(HWND hWnd) {
|
|
RAWINPUTDEVICE Rid;
|
|
Rid.hwndTarget = hWnd;
|
|
|
|
Rid.dwFlags = RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE;
|
|
Rid.usUsagePage = 0x01;
|
|
Rid.usUsage = 0x02;
|
|
return RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
|
}
|
|
|
|
void ReleaseRawMice() {
|
|
RAWINPUTDEVICE Rid;
|
|
Rid.hwndTarget = 0;
|
|
|
|
Rid.dwFlags = RIDEV_REMOVE;
|
|
Rid.usUsagePage = 0x01;
|
|
Rid.usUsage = 0x02;
|
|
RegisterRawInputDevices(&Rid, 1, sizeof(Rid));
|
|
}
|
|
|
|
// 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;
|
|
|
|
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);
|
|
|
|
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) {
|
|
if (GET_RAWINPUT_CODE_WPARAM (wParam) == RIM_INPUT) {
|
|
RAWINPUT in;
|
|
unsigned int size = sizeof(RAWINPUT);
|
|
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &in, &size, sizeof(RAWINPUTHEADER)) > 0) {
|
|
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;
|
|
if (GetRawInputDeviceList(0, (unsigned int*)&count, sizeof(RAWINPUTDEVICELIST)) != (UINT)-1 && count > 0) {
|
|
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;
|
|
count = GetRawInputDeviceList(list, (unsigned int*)&count, sizeof(RAWINPUTDEVICELIST));
|
|
|
|
// 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;
|
|
int nameLen = GetRawInputDeviceInfo(list[i].hDevice, RIDI_DEVICENAME, instanceID, &bufferLen);
|
|
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"));
|
|
}
|
|
}
|