mirror of
https://github.com/micsthepick/dsi2key.git
synced 2025-06-18 16:55:33 -04:00
437 lines
9.5 KiB
C++
437 lines
9.5 KiB
C++
// Virtual input, includes Keyboard, Mouse, and Joystick support
|
|
|
|
#ifdef _WIN32
|
|
#ifdef __GNUC__
|
|
#define _WIN32_WINNT 0x0500
|
|
#endif
|
|
#include <windows.h>
|
|
#include <winuser.h>
|
|
#include "vjoy.h"
|
|
#endif
|
|
|
|
#include "common/key.h"
|
|
#include "common/easylogging++Wrapper.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "common/misc.h"
|
|
|
|
namespace D2K {namespace Input {
|
|
|
|
#ifdef __linux__
|
|
Display* g_display;
|
|
#endif
|
|
|
|
void Init()
|
|
{
|
|
#ifdef __linux__
|
|
g_display = XOpenDisplay(nullptr);
|
|
#endif
|
|
}
|
|
|
|
void DeInit()
|
|
{
|
|
#ifdef _WIN32
|
|
for(uint8_t i = 1; i < Joystick::MAX_JOYSTICKS; i++)
|
|
if(Joystick::IsActive(i))
|
|
Joystick::DeInit(i);
|
|
#endif
|
|
}
|
|
|
|
// TODO: check and verify for every extended key
|
|
// Checks if (key) is an "extended" key
|
|
// param: key Platform specific value
|
|
// return: true if (key) is an "extended" key
|
|
bool IsExtended(uint16_t key)
|
|
{
|
|
switch(key)
|
|
{
|
|
#ifdef _WIN32
|
|
case VK_INSERT:
|
|
case VK_DELETE:
|
|
case VK_HOME:
|
|
case VK_END:
|
|
case VK_PRIOR:
|
|
case VK_NEXT:
|
|
case VK_NUMLOCK:
|
|
case VK_PRINT:
|
|
case VK_SCROLL:
|
|
case VK_PAUSE:
|
|
case VK_DIVIDE:
|
|
case VK_LMENU:
|
|
case VK_RMENU:
|
|
case VK_LWIN:
|
|
case VK_RWIN:
|
|
case VK_LCONTROL:
|
|
case VK_RCONTROL:
|
|
case VK_UP:
|
|
case VK_DOWN:
|
|
case VK_LEFT:
|
|
case VK_RIGHT:
|
|
case VK_MEDIA_NEXT_TRACK:
|
|
case VK_MEDIA_PLAY_PAUSE:
|
|
case VK_MEDIA_PREV_TRACK:
|
|
case VK_MEDIA_STOP:
|
|
// next are untested
|
|
case VK_EXECUTE:
|
|
case VK_SNAPSHOT:
|
|
case VK_APPS:
|
|
return true;
|
|
#endif
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
enum KeyState
|
|
{
|
|
pressed = false,
|
|
released = true,
|
|
};
|
|
enum MouseMovement
|
|
{
|
|
relative = 0,
|
|
absolute = 1,
|
|
joystick = 2,
|
|
};
|
|
|
|
static uint16_t s_press_counter[65535]{}; // this allows 1 or more profile to press the same key, instead of going crazy
|
|
static uint16_t s_turbo_status [65535]{};
|
|
|
|
// Presses or releases (key) depending on (state)
|
|
// param: key Platform specific value
|
|
// param: state true = released, false = pressed
|
|
void Keyboard(uint16_t key, KeyState state)
|
|
{
|
|
#ifdef _WIN32
|
|
INPUT input{};
|
|
switch(key)
|
|
{
|
|
case VK_LBUTTON:
|
|
{
|
|
input.type = INPUT_MOUSE;
|
|
input.mi.dwFlags = MOUSEEVENTF_MOVE;
|
|
|
|
if(state == KeyState::released)
|
|
input.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
|
|
else
|
|
input.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
|
|
break;
|
|
}
|
|
case VK_RBUTTON:
|
|
{
|
|
input.type = INPUT_MOUSE;
|
|
input.mi.dwFlags = MOUSEEVENTF_MOVE;
|
|
|
|
if(state == KeyState::released)
|
|
input.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
|
|
else
|
|
input.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
|
|
break;
|
|
}
|
|
case VK_MBUTTON:
|
|
{
|
|
input.type = INPUT_MOUSE;
|
|
input.mi.dwFlags = MOUSEEVENTF_MOVE;
|
|
if(state == KeyState::released)
|
|
input.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
|
|
else
|
|
input.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
input.type = INPUT_KEYBOARD;
|
|
input.ki.wVk = key;
|
|
input.ki.dwFlags = KEYEVENTF_SCANCODE;
|
|
|
|
if(IsExtended(key))
|
|
input.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
|
|
|
|
if(state == KeyState::released)
|
|
input.ki.dwFlags |= KEYEVENTF_KEYUP;
|
|
|
|
input.ki.wScan = (WORD)MapVirtualKey(key, MAPVK_VK_TO_VSC);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SendInput(1, (LPINPUT)&input, sizeof(INPUT));
|
|
#elif defined(__linux__)
|
|
unsigned long int code;
|
|
if (key >= 0x8001 && key <= 0x8003) {
|
|
code = (key & 0x3);
|
|
//LOG(TRACE) << "XTestFakeButtonEvent:: code: " << code << ", state: " << state;
|
|
XTestFakeButtonEvent(g_display, code, !state, 0);
|
|
XFlush(g_display);
|
|
return;
|
|
}
|
|
|
|
code = XKeysymToKeycode(g_display, key);
|
|
if (code == 0) {
|
|
LOG(ERROR) << "XKeysymToKeycode returned 0 (NULL)" << std::endl;
|
|
return;
|
|
}
|
|
XTestFakeKeyEvent(g_display, code, !state, 0);
|
|
XFlush(g_display);
|
|
#endif
|
|
}
|
|
|
|
// Moves cursor position
|
|
// param: type true = absolute, false = relative
|
|
void Mouse(MouseMovement type, signed long int x, signed long int y)
|
|
{
|
|
#ifdef _WIN32
|
|
INPUT input{};
|
|
|
|
input.type = INPUT_MOUSE;
|
|
input.mi.dx = x;
|
|
input.mi.dy = y;
|
|
input.mi.dwFlags = (type ? MOUSEEVENTF_ABSOLUTE : 0) | MOUSEEVENTF_MOVE;
|
|
input.mi.dwExtraInfo = 0;
|
|
input.mi.mouseData = 0;
|
|
input.mi.time = 0;
|
|
|
|
SendInput(1, (LPINPUT)&input, sizeof(INPUT));
|
|
#elif defined(__linux__)
|
|
Window dummyWin;
|
|
int dummySignedInt;
|
|
unsigned int width, height, dummyInt;
|
|
|
|
int screen = DefaultScreen(g_display);
|
|
Window rootwindow = RootWindow(g_display, screen);
|
|
|
|
if(XGetGeometry(g_display, rootwindow, &dummyWin, &dummySignedInt, &dummySignedInt, &width, &height, &dummyInt, &dummyInt))
|
|
{
|
|
//LOG(DEBUG) << x << ", " << y << std::endl;
|
|
//return;
|
|
if(type)
|
|
XTestFakeMotionEvent(g_display, screen, x, y, 0);
|
|
else
|
|
XTestFakeRelativeMotionEvent(g_display, x, y, 0);
|
|
XFlush(g_display);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void MouseJoystick(uint8_t x, uint8_t y)
|
|
{
|
|
#ifdef _WIN32
|
|
Joystick::SetAxisPercent(1, HID_USAGE_X, x);
|
|
Joystick::SetAxisPercent(1, HID_USAGE_Y, y);
|
|
Joystick::Update(1);
|
|
#endif
|
|
}
|
|
|
|
void Tap(uint16_t key, uint8_t joy)
|
|
{
|
|
if(s_press_counter[key] == 0)
|
|
{
|
|
if(!s_turbo_status[key])
|
|
Press(key, joy);
|
|
else
|
|
Release(key, joy);
|
|
}
|
|
else
|
|
{
|
|
if(!s_turbo_status[key])
|
|
Release(key, joy);
|
|
else
|
|
Press(key, joy);
|
|
}
|
|
}
|
|
|
|
void Press(uint16_t key, uint8_t joy)
|
|
{
|
|
if(s_press_counter[key] == 0)
|
|
{
|
|
// GamePad Buttons
|
|
if(key >= Key::JOY && key <= Key::JOY_MAX) // virtual gamepad buttons
|
|
{
|
|
#ifdef _WIN32
|
|
Joystick::SetButton(joy, (uint8_t)(key - Key::JOY), true);
|
|
Joystick::Update(joy);
|
|
#endif
|
|
}
|
|
// GamePad DPad
|
|
else if(key >= Key::JOY_HAT && key <= Key::JOY_HAT_MAX) // virtual gamepad buttons
|
|
{
|
|
#ifdef _WIN32
|
|
Joystick::SetHat(joy, (uint8_t)(key - Key::JOY_HAT), true);
|
|
Joystick::Update(joy);
|
|
#endif
|
|
}
|
|
// Analog Axis
|
|
else if(key >= Key::JOY_AXIS1 && key <= Key::JOY_AXIS5_MAX) // virtual analog axis
|
|
{
|
|
#ifdef _WIN32
|
|
switch(key)
|
|
{
|
|
case Key::JOY_AXIS_X_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_X, 0);
|
|
break;
|
|
case Key::JOY_AXIS_X_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_X, 100);
|
|
break;
|
|
case Key::JOY_AXIS_Y_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_Y, 0);
|
|
break;
|
|
case Key::JOY_AXIS_Y_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_Y, 100);
|
|
break;
|
|
case Key::JOY_AXIS_Z_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_Z, 0);
|
|
break;
|
|
case Key::JOY_AXIS_Z_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_Z, 100);
|
|
break;
|
|
case Key::JOY_AXIS_RX_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RX, 0);
|
|
break;
|
|
case Key::JOY_AXIS_RX_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RX, 100);
|
|
break;
|
|
case Key::JOY_AXIS_RY_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RY, 0);
|
|
break;
|
|
case Key::JOY_AXIS_RY_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RY, 100);
|
|
break;
|
|
case Key::JOY_AXIS_RZ_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RZ, 0);
|
|
break;
|
|
case Key::JOY_AXIS_RZ_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RZ, 100);
|
|
break;
|
|
case Key::JOY_AXIS_SL0_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_SL0, 0);
|
|
break;
|
|
case Key::JOY_AXIS_SL0_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_SL0, 100);
|
|
break;
|
|
case Key::JOY_AXIS_SL1_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_SL1, 0);
|
|
break;
|
|
case Key::JOY_AXIS_SL1_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_SL1, 100);
|
|
break;
|
|
case Key::JOY_AXIS_WHL_MINUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_WHL, 0);
|
|
break;
|
|
case Key::JOY_AXIS_WHL_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_WHL, 100);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
Joystick::Update(joy);
|
|
#endif
|
|
}
|
|
// Keyboard
|
|
else
|
|
{
|
|
Keyboard(key, KeyState::pressed);
|
|
LOG(TRACE) << "Key Pressed:" << key;
|
|
}
|
|
}
|
|
|
|
if(s_press_counter[key] < 65535)
|
|
s_press_counter[key]++;
|
|
}
|
|
|
|
void Release(uint16_t key, uint8_t joy)
|
|
{
|
|
if(s_press_counter[key] == 1)
|
|
{
|
|
// GamePad Buttons
|
|
if(key >= Key::JOY && key <= Key::JOY_MAX)
|
|
{
|
|
#ifdef _WIN32
|
|
Joystick::SetButton(joy, (uint8_t)(key - Key::JOY), false);
|
|
Joystick::Update(joy);
|
|
#endif
|
|
}
|
|
// GamePad DPad
|
|
else if(key >= Key::JOY_HAT && key <= Key::JOY_HAT_MAX)
|
|
{
|
|
#ifdef _WIN32
|
|
Joystick::SetHat(joy, (uint8_t)( key - Key::JOY_HAT), false);
|
|
Joystick::Update(joy);
|
|
#endif
|
|
}
|
|
// Analog Axis
|
|
else if(key >= Key::JOY_AXIS1 && key <= Key::JOY_AXIS5_MAX)
|
|
{
|
|
#ifdef _WIN32
|
|
switch(key)
|
|
{
|
|
case Key::JOY_AXIS_X_MINUS:
|
|
case Key::JOY_AXIS_X_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_X, 50);
|
|
break;
|
|
case Key::JOY_AXIS_Y_MINUS:
|
|
case Key::JOY_AXIS_Y_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_Y, 50);
|
|
break;
|
|
case Key::JOY_AXIS_Z_MINUS:
|
|
case Key::JOY_AXIS_Z_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_Z, 50);
|
|
break;
|
|
case Key::JOY_AXIS_RX_MINUS:
|
|
case Key::JOY_AXIS_RX_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RX, 50);
|
|
break;
|
|
case Key::JOY_AXIS_RY_MINUS:
|
|
case Key::JOY_AXIS_RY_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RY, 50);
|
|
break;
|
|
case Key::JOY_AXIS_RZ_MINUS:
|
|
case Key::JOY_AXIS_RZ_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_RZ, 50);
|
|
break;
|
|
case Key::JOY_AXIS_SL0_MINUS:
|
|
case Key::JOY_AXIS_SL0_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_SL0, 50);
|
|
break;
|
|
case Key::JOY_AXIS_SL1_MINUS:
|
|
case Key::JOY_AXIS_SL1_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_SL1, 50);
|
|
break;
|
|
case Key::JOY_AXIS_WHL_MINUS:
|
|
case Key::JOY_AXIS_WHL_PLUS:
|
|
Joystick::SetAxisPercent(joy, HID_USAGE_WHL, 50);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
Joystick::Update(joy);
|
|
#endif
|
|
}
|
|
// Keyboard
|
|
else
|
|
{
|
|
Keyboard(key, KeyState::released);
|
|
}
|
|
}
|
|
|
|
if(s_press_counter[key] > 0)
|
|
s_press_counter[key]--;
|
|
}
|
|
|
|
void Move(signed long int x, signed long int y)
|
|
{
|
|
Mouse(MouseMovement::relative, x, y);
|
|
}
|
|
|
|
void MoveAbsolute(signed long int x, signed long int y)
|
|
{
|
|
Mouse(MouseMovement::absolute, x, y);
|
|
}
|
|
|
|
void MoveJoystick(uint8_t x, uint8_t y)
|
|
{
|
|
MouseJoystick(x, y);
|
|
}
|
|
|
|
}} // namespace D2K::Input
|