dolphin/Source/Core/InputCommon/XInput2Mouse.cpp

156 lines
3.9 KiB
C++

#include "InputCommon/XInput2Mouse.h"
#include "Core/Host.h"
#include <cstring>
#include <math.h>
int win_w = 0, win_h = 0;
namespace prime
{
bool InitXInput2Mouse(void* const hwnd)
{
Display* dpy = XOpenDisplay(nullptr);
int xi_opcode, event, error;
if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error))
return false;
int major = 2, minor = 0;
if (XIQueryVersion(dpy, &major, &minor) != Success)
return false;
XIDeviceInfo* all_masters;
XIDeviceInfo* current_master;
int num_masters;
all_masters = XIQueryDevice(dpy, XIAllMasterDevices, &num_masters);
if (num_masters < 1)
return false;
current_master = &all_masters[0];
if (current_master->use == XIMasterPointer)
{
g_mouse_input = new XInput2Mouse((Window)hwnd, xi_opcode, current_master->deviceid);
}
XCloseDisplay(dpy);
XIFreeDeviceInfo(all_masters);
return true;
}
XInput2Mouse::XInput2Mouse(Window hwnd, int opcode, int pointer)
: pointer_deviceid(pointer), xi_opcode(opcode), window(hwnd)
{
display = XOpenDisplay(nullptr);
int unused;
XIDeviceInfo* pointer_device = XIQueryDevice(display, pointer_deviceid, &unused);
name = std::string(pointer_device->name);
XIFreeDeviceInfo(pointer_device);
XIEventMask mask;
unsigned char mask_buf[(XI_LASTEVENT + 7) / 8];
mask.mask_len = sizeof(mask_buf);
mask.mask = mask_buf;
memset(mask_buf, 0, sizeof(mask_buf));
XISetMask(mask_buf, XI_RawMotion);
SelectEventsForDevice(DefaultRootWindow(display), &mask, pointer_deviceid);
}
void XInput2Mouse::UpdateInput()
{
XFlush(display);
float delta_x = 0.0f, delta_y = 0.0f;
double delta_delta;
XEvent event;
while (XPending(display))
{
XNextEvent(display, &event);
if (event.xcookie.type != GenericEvent)
continue;
if (event.xcookie.extension != xi_opcode)
continue;
if (!XGetEventData(display, &event.xcookie))
continue;
XIRawEvent* raw_event = (XIRawEvent*)event.xcookie.data;
if (event.xcookie.evtype == XI_RawMotion)
{
if (XIMaskIsSet(raw_event->valuators.mask, 0))
{
delta_delta = raw_event->raw_values[0];
if (delta_delta == delta_delta && 1 + delta_delta != delta_delta)
delta_x += delta_delta;
}
if (XIMaskIsSet(raw_event->valuators.mask, 1))
{
delta_delta = raw_event->raw_values[1];
if (delta_delta == delta_delta && 1 + delta_delta != delta_delta)
delta_y += delta_delta;
}
}
XFreeEventData(display, &event.xcookie);
}
if (cursor_locked)
{
this->dx += std::roundf(delta_x);
this->dy += std::roundf(delta_y);
}
LockCursorToGameWindow();
}
void XInput2Mouse::SelectEventsForDevice(Window root_window, XIEventMask* mask, int deviceid)
{
// Set the event mask for the master device.
mask->deviceid = deviceid;
XISelectEvents(display, root_window, mask, 1);
// Query all the master device's slaves and set the same event mask for
// those too. There are two reasons we want to do this. For mouse devices,
// we want the raw motion events, and only slaves (i.e. physical hardware
// devices) emit those. For keyboard devices, selecting slaves avoids
// dealing with key focus.
XIDeviceInfo* all_slaves;
XIDeviceInfo* current_slave;
int num_slaves;
all_slaves = XIQueryDevice(display, XIAllDevices, &num_slaves);
for (int i = 0; i < num_slaves; i++)
{
current_slave = &all_slaves[i];
if ((current_slave->use != XISlavePointer && current_slave->use != XISlaveKeyboard) ||
current_slave->attachment != deviceid)
continue;
mask->deviceid = current_slave->deviceid;
XISelectEvents(display, root_window, mask, 1);
}
XIFreeDeviceInfo(all_slaves);
}
void XInput2Mouse::LockCursorToGameWindow()
{
if (Host_RendererHasFocus() && cursor_locked)
{
Host_RendererUpdateCursor(true);
}
else
{
cursor_locked = false;
Host_RendererUpdateCursor(false);
}
}
} // namespace prime