summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_rawinput.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/input/input_rawinput.cpp')
-rw-r--r--src/osd/modules/input/input_rawinput.cpp186
1 files changed, 139 insertions, 47 deletions
diff --git a/src/osd/modules/input/input_rawinput.cpp b/src/osd/modules/input/input_rawinput.cpp
index 3ee8e2d8f7e..5b6813dcd59 100644
--- a/src/osd/modules/input/input_rawinput.cpp
+++ b/src/osd/modules/input/input_rawinput.cpp
@@ -25,9 +25,11 @@
#include <algorithm>
#include <cassert>
+#include <chrono>
#include <functional>
#include <mutex>
#include <new>
+#include <utility>
// standard windows headers
#include <windows.h>
@@ -307,23 +309,75 @@ class rawinput_keyboard_device : public rawinput_device
public:
rawinput_keyboard_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
rawinput_device(std::move(name), std::move(id), module, handle),
+ m_pause_pressed(std::chrono::steady_clock::time_point::min()),
+ m_e1(0xffff),
m_keyboard({ { 0 } })
{
}
virtual void reset() override
{
+ rawinput_device::reset();
+ m_pause_pressed = std::chrono::steady_clock::time_point::min();
memset(&m_keyboard, 0, sizeof(m_keyboard));
+ m_e1 = 0xffff;
+ }
+
+ virtual void poll(bool relative_reset) override
+ {
+ rawinput_device::poll(relative_reset);
+ if (m_keyboard.state[0x80 | 0x45] && (std::chrono::steady_clock::now() > (m_pause_pressed + std::chrono::milliseconds(30))))
+ m_keyboard.state[0x80 | 0x45] = 0x00;
}
virtual void process_event(RAWINPUT const &rawinput) override
{
// determine the full DIK-compatible scancode
- uint8_t scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00);
+ uint8_t scancode;
- // scancode 0xaa is a special shift code we need to ignore
- if (scancode == 0xaa)
+ // the only thing that uses this is Pause
+ if (rawinput.data.keyboard.Flags & RI_KEY_E1)
+ {
+ m_e1 = rawinput.data.keyboard.MakeCode;
return;
+ }
+ else if (0xffff != m_e1)
+ {
+ auto const e1 = std::exchange(m_e1, 0xffff);
+ if (!(rawinput.data.keyboard.Flags & RI_KEY_E0))
+ {
+ if (((e1 & ~USHORT(0x80)) == 0x1d) && ((rawinput.data.keyboard.MakeCode & ~USHORT(0x80)) == 0x45))
+ {
+ if (rawinput.data.keyboard.Flags & RI_KEY_BREAK)
+ return; // RawInput generates a fake break immediately after the make - ignore it
+
+ m_pause_pressed = std::chrono::steady_clock::now();
+ scancode = 0x80 | 0x45;
+ }
+ else
+ {
+ return; // no idea
+ }
+ }
+ else
+ {
+ return; // shouldn't happen, ignore it
+ }
+ }
+ else
+ {
+ // strip bit 7 of the make code to work around dodgy drivers that set it for key up events
+ if (rawinput.data.keyboard.MakeCode & ~USHORT(0xff))
+ {
+ // won't fit in a byte along with the E0 flag
+ return;
+ }
+ scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00);
+
+ // fake shift generated with cursor control and Ins/Del for compatibility with very old DOS software
+ if (scancode == 0xaa)
+ return;
+ }
// set or clear the key
m_keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80;
@@ -333,13 +387,20 @@ public:
{
keyboard_trans_table const &table = keyboard_trans_table::instance();
- for (int keynum = 0; keynum < MAX_KEYS; keynum++)
+ // FIXME: GetKeyNameTextW is for scan codes from WM_KEYDOWN, which aren't quite the same as DIK_* keycodes
+ // in particular, NumLock and Pause are reversed for US-style keyboard systems
+ for (unsigned keynum = 0; keynum < MAX_KEYS; keynum++)
{
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
WCHAR keyname[100];
// generate the name
- if (GetKeyNameTextW(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, std::size(keyname)) == 0)
+ // FIXME: GetKeyNameText gives bogus names for media keys and various other things
+ // in many cases it ignores the "extended" bit and returns the key name corresponding to the scan code alone
+ LONG lparam = ((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17);
+ if ((keynum & 0x7f) == 0x45)
+ lparam ^= 0x0100'0000; // horrid hack
+ if (GetKeyNameTextW(lparam, keyname, std::size(keyname)) == 0)
_snwprintf(keyname, std::size(keyname), L"Scan%03d", keynum);
std::string name = text::from_wstring(keyname);
@@ -354,6 +415,8 @@ public:
}
private:
+ std::chrono::steady_clock::time_point m_pause_pressed;
+ uint16_t m_e1;
keyboard_state m_keyboard;
};
@@ -370,7 +433,8 @@ public:
m_mouse({0}),
m_x(0),
m_y(0),
- m_z(0)
+ m_v(0),
+ m_h(0)
{
}
@@ -381,28 +445,45 @@ public:
{
m_mouse.lX = std::exchange(m_x, 0);
m_mouse.lY = std::exchange(m_y, 0);
- m_mouse.lZ = std::exchange(m_z, 0);
+ m_mouse.lV = std::exchange(m_v, 0);
+ m_mouse.lH = std::exchange(m_h, 0);
}
}
virtual void reset() override
{
+ rawinput_device::reset();
memset(&m_mouse, 0, sizeof(m_mouse));
- m_x = m_y = m_z = 0;
+ m_x = m_y = m_v = m_h = 0;
}
virtual void configure(input_device &device) override
{
// populate the axes
- for (int axisnum = 0; axisnum < 3; axisnum++)
- {
- device.add_item(
- default_axis_name[axisnum],
- std::string_view(),
- input_item_id(ITEM_ID_XAXIS + axisnum),
- generic_axis_get_state<LONG>,
- &m_mouse.lX + axisnum);
- }
+ device.add_item(
+ "X",
+ std::string_view(),
+ ITEM_ID_XAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lX);
+ device.add_item(
+ "Y",
+ std::string_view(),
+ ITEM_ID_YAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lY);
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ZAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_RZAXIS,
+ generic_axis_get_state<LONG>,
+ &m_mouse.lH);
// populate the buttons
for (int butnum = 0; butnum < 5; butnum++)
@@ -418,17 +499,17 @@ public:
virtual void process_event(RAWINPUT const &rawinput) override
{
-
// If this data was intended for a rawinput mouse
if (rawinput.data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
{
-
m_x += rawinput.data.mouse.lLastX * input_device::RELATIVE_PER_PIXEL;
m_y += rawinput.data.mouse.lLastY * input_device::RELATIVE_PER_PIXEL;
- // update Z axis (vertical scroll)
+ // update Z/Rz axes (vertical/horizontal scroll)
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
- m_z += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
+ m_v += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL)
+ m_h += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
// update the button states; always update the corresponding mouse buttons
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) m_mouse.rgbButtons[0] = 0x80;
@@ -446,7 +527,7 @@ public:
private:
mouse_state m_mouse;
- LONG m_x, m_y, m_z;
+ LONG m_x, m_y, m_v, m_h;
};
@@ -460,7 +541,8 @@ public:
rawinput_lightgun_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
rawinput_device(std::move(name), std::move(id), module, handle),
m_lightgun({0}),
- m_z(0)
+ m_v(0),
+ m_h(0)
{
}
@@ -468,13 +550,18 @@ public:
{
rawinput_device::poll(relative_reset);
if (relative_reset)
- m_lightgun.lZ = std::exchange(m_z, 0);
+ {
+ m_lightgun.lV = std::exchange(m_v, 0);
+ m_lightgun.lH = std::exchange(m_h, 0);
+ }
}
virtual void reset() override
{
+ rawinput_device::reset();
memset(&m_lightgun, 0, sizeof(m_lightgun));
- m_z = 0;
+ m_v = 0;
+ m_h = 0;
}
virtual void configure(input_device &device) override
@@ -490,13 +577,19 @@ public:
&m_lightgun.lX + axisnum);
}
- // scroll wheel is always relative if present
+ // scroll wheels are always relative if present
device.add_item(
- default_axis_name[2],
+ "Scroll V",
std::string_view(),
ITEM_ID_ADD_RELATIVE1,
generic_axis_get_state<LONG>,
- &m_lightgun.lZ);
+ &m_lightgun.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE2,
+ generic_axis_get_state<LONG>,
+ &m_lightgun.lH);
// populate the buttons
for (int butnum = 0; butnum < 5; butnum++)
@@ -515,14 +608,15 @@ public:
// If this data was intended for a rawinput lightgun
if (rawinput.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
{
-
// update the X/Y positions
m_lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, input_device::ABSOLUTE_MAX);
m_lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, input_device::ABSOLUTE_MAX);
- // update zaxis
+ // update Z/Rz axes
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
- m_z += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
+ m_v += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
+ if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_HWHEEL)
+ m_h += int16_t(rawinput.data.mouse.usButtonData) * input_device::RELATIVE_PER_PIXEL;
// update the button states; always update the corresponding mouse buttons
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) m_lightgun.rgbButtons[0] = 0x80;
@@ -540,12 +634,12 @@ public:
private:
mouse_state m_lightgun;
- LONG m_z;
+ LONG m_v, m_h;
};
//============================================================
-// rawinput_module - base class for rawinput modules
+// rawinput_module - base class for RawInput modules
//============================================================
class rawinput_module : public wininput_module<rawinput_device>
@@ -608,9 +702,7 @@ public:
RAWINPUTDEVICE registration;
registration.usUsagePage = usagepage();
registration.usUsage = usage();
- registration.dwFlags = RIDEV_DEVNOTIFY;
- if (background_input())
- registration.dwFlags |= RIDEV_INPUTSINK;
+ registration.dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
registration.hwndTarget = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window();
// register the device
@@ -654,18 +746,18 @@ protected:
rawinputdevice.hDevice);
}
- virtual bool handle_input_event(input_event eventid, void *eventdata) override
+ virtual bool handle_input_event(input_event eventid, void const *eventdata) override
{
switch (eventid)
{
// handle raw input data
case INPUT_EVENT_RAWINPUT:
{
- HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
+ HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata);
- BYTE small_buffer[4096];
+ union { RAWINPUT r; BYTE b[4096]; } small_buffer;
std::unique_ptr<BYTE []> larger_buffer;
- LPBYTE data = small_buffer;
+ LPVOID data = &small_buffer;
UINT size;
// determine the size of data buffer we need
@@ -675,7 +767,7 @@ protected:
// if necessary, allocate a temporary buffer and fetch the data
if (size > sizeof(small_buffer))
{
- larger_buffer.reset(new (std::nothrow) BYTE [size]);
+ larger_buffer.reset(new (std::align_val_t(alignof(RAWINPUT)), std::nothrow) BYTE [size]);
data = larger_buffer.get();
if (!data)
return false;
@@ -691,7 +783,7 @@ protected:
{
std::lock_guard<std::mutex> scope_lock(m_module_lock);
- auto *input = reinterpret_cast<RAWINPUT *>(data);
+ auto *const input = reinterpret_cast<RAWINPUT const *>(data);
if (!input->header.hDevice)
return false;
@@ -714,7 +806,7 @@ protected:
case INPUT_EVENT_ARRIVAL:
{
- HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
+ HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata);
// determine the length of the device name, allocate it, and fetch it if not nameless
UINT name_length = 0;
@@ -747,7 +839,7 @@ protected:
case INPUT_EVENT_REMOVAL:
{
- HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
+ HRAWINPUT const rawinputdevice = *reinterpret_cast<HRAWINPUT const *>(eventdata);
std::lock_guard<std::mutex> scope_lock(m_module_lock);
@@ -780,7 +872,7 @@ protected:
//============================================================
-// keyboard_input_rawinput - rawinput keyboard module
+// keyboard_input_rawinput - RawInput keyboard module
//============================================================
class keyboard_input_rawinput : public rawinput_module
@@ -807,7 +899,7 @@ protected:
//============================================================
-// mouse_input_rawinput - rawinput mouse module
+// mouse_input_rawinput - RawInput mouse module
//============================================================
class mouse_input_rawinput : public rawinput_module
@@ -834,7 +926,7 @@ protected:
//============================================================
-// lightgun_input_rawinput - rawinput lightgun module
+// lightgun_input_rawinput - RawInput lightgun module
//============================================================
class lightgun_input_rawinput : public rawinput_module