summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/sdl/input.c
diff options
context:
space:
mode:
author R. Belmont <rb6502@users.noreply.github.com>2012-07-25 01:32:48 +0000
committer R. Belmont <rb6502@users.noreply.github.com>2012-07-25 01:32:48 +0000
commitbeba6394711186366ceefd00cdd5a8d6c23a6e6d (patch)
treed478d0ee9567f7089a5d08d19251dc750aacf991 /src/osd/sdl/input.c
parent4e6f0480c37e6231aaf0c6922ce48d6b9a887ab8 (diff)
SDL: Use XInput to allow multiple lightguns on Linux/*BSD targets. [Markus Rathgeb, based on a patch by SpritesMods.com]
Diffstat (limited to 'src/osd/sdl/input.c')
-rw-r--r--src/osd/sdl/input.c419
1 files changed, 418 insertions, 1 deletions
diff --git a/src/osd/sdl/input.c b/src/osd/sdl/input.c
index 7dbbab91a37..55deeefe33c 100644
--- a/src/osd/sdl/input.c
+++ b/src/osd/sdl/input.c
@@ -17,6 +17,13 @@
#include <ctype.h>
#include <stddef.h>
+#if USE_XINPUT
+// for xinput
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput.h>
+#include <X11/Xutil.h>
+#endif
+
// MAME headers
#include "emu.h"
#include "ui.h"
@@ -53,6 +60,18 @@ enum
#define MAX_POV 4
#define MAX_DEVMAP_ENTRIES 16
+#if (USE_XINPUT)
+//For xinput
+#define INVALID_EVENT_TYPE -1
+static int motion_type = INVALID_EVENT_TYPE;
+static int button_press_type = INVALID_EVENT_TYPE;
+static int button_release_type = INVALID_EVENT_TYPE;
+static int key_press_type = INVALID_EVENT_TYPE;
+static int key_release_type = INVALID_EVENT_TYPE;
+static int proximity_in_type = INVALID_EVENT_TYPE;
+static int proximity_out_type = INVALID_EVENT_TYPE;
+#endif
+
//============================================================
// MACROS
//============================================================
@@ -98,6 +117,19 @@ struct _joystick_state
INT32 balls[MAX_AXES];
};
+#if (USE_XINPUT)
+// state information for a lightgun
+typedef struct _lightgun_state lightgun_state;
+struct _lightgun_state
+{
+ INT32 lX, lY;
+ INT32 buttons[MAX_BUTTONS];
+ XID deviceid; //Xinput device id
+ INT32 maxx,maxy;
+ INT32 minx,miny;
+};
+#endif
+
// generic device information
typedef struct _device_info device_info;
struct _device_info
@@ -116,6 +148,9 @@ struct _device_info
keyboard_state keyboard;
mouse_state mouse;
joystick_state joystick;
+#if (USE_XINPUT)
+ lightgun_state lightgun;
+#endif
};
};
@@ -166,6 +201,10 @@ struct _device_map_t
static device_map_t joy_map;
static device_map_t mouse_map;
static device_map_t keyboard_map;
+#if (USE_XINPUT)
+static device_map_t lightgun_map;
+Display *XDisplay;
+#endif
static int sixaxis_mode;
@@ -889,6 +928,225 @@ static void sdlinput_register_mice(running_machine &machine)
}
#endif
+#if (USE_XINPUT)
+//============================================================
+// lightgun helpers: copy-past from xinfo
+//============================================================
+
+XDeviceInfo*
+find_device_info(Display *display,
+ char *name,
+ Bool only_extended)
+{
+ XDeviceInfo *devices;
+ XDeviceInfo *found = NULL;
+ int loop;
+ int num_devices;
+ int len = strlen(name);
+ Bool is_id = True;
+ XID id = (XID)-1;
+
+ for(loop=0; loop<len; loop++) {
+ if (!isdigit(name[loop])) {
+ is_id = False;
+ break;
+ }
+ }
+
+ if (is_id) {
+ id = atoi(name);
+ }
+
+ devices = XListInputDevices(display, &num_devices);
+
+ for(loop=0; loop<num_devices; loop++) {
+ if ((!only_extended || (devices[loop].use >= IsXExtensionDevice)) &&
+ ((!is_id && strcmp(devices[loop].name, name) == 0) ||
+ (is_id && devices[loop].id == id))) {
+ if (found) {
+ fprintf(stderr,
+ "Warning: There are multiple devices named \"%s\".\n"
+ "To ensure the correct one is selected, please use "
+ "the device ID instead.\n\n", name);
+ } else {
+ found = &devices[loop];
+ }
+ }
+ }
+ return found;
+}
+
+//Copypasted from xinfo
+static int
+register_events(Display *dpy,
+ XDeviceInfo *info,
+ char *dev_name,
+ Bool handle_proximity)
+{
+ int number = 0; /* number of events registered */
+ XEventClass event_list[7];
+ int i;
+ XDevice *device;
+ Window root_win;
+ unsigned long screen;
+ XInputClassInfo *ip;
+
+ screen = DefaultScreen(dpy);
+ root_win = RootWindow(dpy, screen);
+
+ device = XOpenDevice(dpy, info->id);
+
+ if (!device) {
+ fprintf(stderr, "unable to open device %s\n", dev_name);
+ return 0;
+ }
+
+ if (device->num_classes > 0) {
+ for (ip = device->classes, i=0; i<info->num_classes; ip++, i++) {
+ switch (ip->input_class) {
+ case KeyClass:
+ DeviceKeyPress(device, key_press_type, event_list[number]); number++;
+ DeviceKeyRelease(device, key_release_type, event_list[number]); number++;
+ break;
+
+ case ButtonClass:
+ DeviceButtonPress(device, button_press_type, event_list[number]); number++;
+ DeviceButtonRelease(device, button_release_type, event_list[number]); number++;
+ break;
+
+ case ValuatorClass:
+ DeviceMotionNotify(device, motion_type, event_list[number]); number++;
+ fprintf(stderr, "Motion = %i\n",motion_type);
+ if (handle_proximity) {
+ ProximityIn(device, proximity_in_type, event_list[number]); number++;
+ ProximityOut(device, proximity_out_type, event_list[number]); number++;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "unknown class\n");
+ break;
+ }
+ }
+
+ if (XSelectExtensionEvent(dpy, root_win, event_list, number)) {
+ fprintf(stderr, "error selecting extended events\n");
+ return 0;
+ }
+ }
+ return number;
+}
+
+//============================================================
+// sdlinput_register_lightguns
+//============================================================
+
+static void sdlinput_register_lightguns(running_machine &machine)
+{
+ int index;
+ XExtensionVersion *version;
+
+ lightgun_enabled = machine.options().lightgun();
+ devmap_init(machine, &lightgun_map, SDLOPTION_LIGHTGUNINDEX, 8, "Lightgun mapping");
+
+ XDisplay = XOpenDisplay(NULL);
+
+ if (XDisplay == NULL) {
+ fprintf(stderr, "Unable to connect to X server\n");
+ return;
+ }
+
+ version = XGetExtensionVersion(XDisplay, INAME);
+
+ if (!version || (version == (XExtensionVersion*) NoSuchExtension)) {
+ fprintf(stderr, "xinput extension not available!\n");
+ return;
+ }
+
+
+ for (index=0; index<8; index++) {
+ XDeviceInfo *info;
+ if (strlen(lightgun_map.map[index].name)!=0) {
+ device_info *devinfo;
+ char *name=lightgun_map.map[index].name;
+ char defname[512];
+ devinfo = devmap_class_register(machine, &lightgun_map, index, &lightgun_list, DEVICE_CLASS_LIGHTGUN);
+ fprintf(stderr, "%i: %s\n",index, name);
+ info=find_device_info(XDisplay, name, 0);
+ if (!info) continue;
+
+ //Grab device info and translate to stuff mame can use
+ if (info->num_classes > 0) {
+ XAnyClassPtr any = (XAnyClassPtr) (info->inputclassinfo);
+ int i;
+ for (i=0; i<info->num_classes; i++) {
+ int button;
+ XValuatorInfoPtr v;
+ XAxisInfoPtr a;
+ int j;
+ XButtonInfoPtr b;
+#if defined(__cplusplus) || defined(c_plusplus)
+ switch (any->c_class) {
+#else
+ switch (any->class) {
+#endif
+ case ButtonClass:
+ b = (XButtonInfoPtr) any;
+ for (button = 0; button < b->num_buttons; button++)
+ {
+ input_item_id itemid;
+ itemid = (input_item_id) (ITEM_ID_BUTTON1 + button);
+ sprintf(defname, "B%d", button + 1);
+ devinfo->device->add_item(defname, itemid, generic_button_get_state, &devinfo->lightgun.buttons[button]);
+ }
+ break;
+ case ValuatorClass:
+ v = (XValuatorInfoPtr) any;
+ a = (XAxisInfoPtr) ((char *) v + sizeof (XValuatorInfo));
+ for (j=0; j<v->num_axes; j++, a++) {
+ if (j==0) {
+#if (USE_XINPUT_DEBUG)
+ fprintf(stderr, "For index %d: Set minx=%d, maxx=%d\n",
+ index,
+ a->min_value, a->max_value);
+#endif
+ devinfo->lightgun.maxx=a->max_value;
+ devinfo->lightgun.minx=a->min_value;
+ }
+ if (j==1) {
+#if (USE_XINPUT_DEBUG)
+ fprintf(stderr, "For index %d: Set miny=%d, maxy=%d\n",
+ index,
+ a->min_value, a->max_value);
+#endif
+ devinfo->lightgun.maxy=a->max_value;
+ devinfo->lightgun.miny=a->min_value;
+ }
+ }
+ break;
+ }
+ any = (XAnyClassPtr) ((char *) any + any->length);
+ }
+ }
+
+
+ sprintf(defname, "X %s", devinfo->name);
+ devinfo->device->add_item(defname, ITEM_ID_XAXIS, generic_axis_get_state, &devinfo->lightgun.lX);
+ sprintf(defname, "Y %s", devinfo->name);
+ devinfo->device->add_item(defname, ITEM_ID_YAXIS, generic_axis_get_state, &devinfo->lightgun.lY);
+
+
+ devinfo->lightgun.deviceid=info->id;
+ if (!info) {
+ fprintf(stderr, "Can't find device %s!\n", lightgun_map.map[index].name);
+ } else {
+ fprintf(stderr, "Device %i: Registered %i events.\n",(int)info->id, register_events(XDisplay, info, lightgun_map.map[index].name, 0));
+ }
+ }
+ }
+ mame_printf_verbose("Lightgun: End initialization\n");
+}
+#endif
//============================================================
// lookup_sdl_code
@@ -1142,6 +1400,11 @@ void sdlinput_init(running_machine &machine)
// register the mice
sdlinput_register_mice(machine);
+#if (USE_XINPUT)
+ // register the lightguns
+ sdlinput_register_lightguns(machine);
+#endif
+
if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
{
mame_printf_warning("Debug Build: Disabling input grab for -debug\n");
@@ -1158,7 +1421,9 @@ void sdlinput_init(running_machine &machine)
device_list_reset_devices(keyboard_list);
device_list_reset_devices(mouse_list);
device_list_reset_devices(joystick_list);
-
+#if (USE_XINPUT)
+ device_list_reset_devices(lightgun_list);
+#endif
}
@@ -1211,6 +1476,58 @@ sdl_window_info *sdlinput_get_focus_window(running_machine &machine)
return sdl_window_list;
}
+#if (USE_XINPUT)
+device_info *get_lightgun_info_for_deviceid(XID deviceid) {
+ device_info *devinfo;
+ int index;
+ //Find lightgun according to device id
+ for (index=0; ; index++) {
+ devinfo = generic_device_find_index(lightgun_list, index);
+ if (devinfo==NULL) break;
+ if (devinfo->lightgun.deviceid==deviceid) break;
+ }
+ return devinfo;
+}
+
+INT32 normalize_absolute_axis(INT32 raw, INT32 rawmin, INT32 rawmax)
+{
+ INT32 rv;
+
+ INT32 center = ((INT64)rawmax + (INT64)rawmin) / 2;
+
+ // make sure we have valid data
+ if (rawmin >= rawmax)
+ {
+ rv = raw;
+ goto out;
+ }
+
+ // above center
+ if (raw >= center)
+ {
+ INT32 result = (INT64)(raw - center) * (INT64)INPUT_ABSOLUTE_MAX / (INT64)(rawmax - center);
+ rv = MIN(result, INPUT_ABSOLUTE_MAX);
+ goto out;
+ }
+
+ // below center
+ else
+ {
+ INT32 result = -((INT64)(center - raw) * (INT64)-INPUT_ABSOLUTE_MIN / (INT64)(center - rawmin));
+ rv = MAX(result, INPUT_ABSOLUTE_MIN);
+ goto out;
+ }
+
+ out:
+
+#if (USE_XINPUT_DEBUG)
+ fprintf(stderr, "raw: %d, rawmin: %d, rawmax: %d, center: %d, rv: %d, ABS_MIN: %d, ABS_MAX: %d\n",
+ raw, rawmin, rawmax, center, rv, INPUT_ABSOLUTE_MIN, INPUT_ABSOLUTE_MAX);
+#endif
+
+ return rv;
+}
+#endif
//============================================================
// sdlinput_poll
@@ -1288,6 +1605,10 @@ void sdlinput_poll(running_machine &machine)
int loc_event_buf_count;
int bufp;
+#if (USE_XINPUT)
+ XEvent xevent;
+#endif
+
for (index=0; ;index++)
{
devinfo = generic_device_find_index( mouse_list, index);
@@ -1297,6 +1618,102 @@ void sdlinput_poll(running_machine &machine)
devinfo->mouse.lY = 0;
}
+#if (USE_XINPUT)
+ //Get XInput events
+ while (XPending(XDisplay)!=0)
+ {
+ XNextEvent(XDisplay, &xevent);
+ if (xevent.type==motion_type)
+ {
+ XDeviceMotionEvent *motion = (XDeviceMotionEvent *) &xevent;
+
+#if (USE_XINPUT_DEBUG)
+ /*
+ * print a lot of debug informations of the motion event(s).
+ */
+ fprintf(stderr,
+ "XDeviceMotionEvent:\n"
+ " type: %d\n"
+ " serial: %lu\n"
+ " send_event: %d\n"
+ " display: %p\n"
+ " window: --\n"
+ " deviceid: %lu\n"
+ " root: --\n"
+ " subwindow: --\n"
+ " time: --\n"
+ " x: %d, y: %d\n"
+ " x_root: %d, y_root: %d\n"
+ " state: %u\n"
+ " is_hint: %2.2X\n"
+ " same_screen: %d\n"
+ " device_state: %u\n"
+ " axes_count: %2.2X\n"
+ " first_axis: %2.2X\n"
+ " axis_data[6]: {%d,%d,%d,%d,%d,%d}\n",
+ motion->type,
+ motion->serial,
+ motion->send_event,
+ motion->display,
+ /* motion->window, */
+ motion->deviceid,
+ /* motion->root */
+ /* motion->subwindow */
+ /* motion->time, */
+ motion->x, motion->y,
+ motion->x_root, motion->y_root,
+ motion->state,
+ motion->is_hint,
+ motion->same_screen,
+ motion->device_state,
+ motion->axes_count,
+ motion->first_axis,
+ motion->axis_data[0], motion->axis_data[1], motion->axis_data[2], motion->axis_data[3], motion->axis_data[4], motion->axis_data[5]
+ );
+#endif
+
+ devinfo=get_lightgun_info_for_deviceid(motion->deviceid);
+
+ /*
+ * We have to check with axis will start on array index 0.
+ * We have also to check the number of axes that are stored in the array.
+ */
+ switch (motion->first_axis)
+ {
+ /*
+ * Starting with x, check number of axis, if there is also the y axis stored.
+ */
+ case 0:
+ if (motion->axes_count >= 1)
+ {
+ devinfo->lightgun.lX=normalize_absolute_axis(motion->axis_data[0], devinfo->lightgun.minx, devinfo->lightgun.maxx);
+ if (motion->axes_count >= 2)
+ {
+ devinfo->lightgun.lY=normalize_absolute_axis(motion->axis_data[1], devinfo->lightgun.miny, devinfo->lightgun.maxy);
+ }
+ }
+ break;
+
+ /*
+ * Starting with y, ...
+ */
+ case 1:
+ if (motion->axes_count >= 1)
+ {
+ devinfo->lightgun.lY=normalize_absolute_axis(motion->axis_data[0], devinfo->lightgun.miny, devinfo->lightgun.maxy);
+ }
+ break;
+ }
+ }
+ else if (xevent.type==button_press_type || xevent.type==button_release_type)
+ {
+ XDeviceButtonEvent *button = (XDeviceButtonEvent *) &xevent;
+ devinfo=get_lightgun_info_for_deviceid(button->deviceid);
+ devinfo->lightgun.buttons[button->button]=(xevent.type==button_press_type)?0x80:0;
+ }
+ }
+#endif
+
if (SDLMAME_EVENTS_IN_WORKER_THREAD)
{
osd_lock_acquire(input_lock);