[SDL] SDL, X.org and multiple mice

Ryan C. Gordon icculus at clutteredmind.org
Wed Jun 22 12:12:36 PDT 2005

> Heh, I have asked very similar 	questions in the past. If you'd have 
> only googled this mailing list for "multiple distinct mice" you 
> probably would have found my posts. Alas, SDL supports this, but no OS 
> known to man does :(

Funny, I just asked this on IRC last week. Popular topic, apparently. :)

Here's my understanding after some research. This is a whole brain dump
for those that are deeply interested. The short of it is "you can't do
it at all now, and with a lot of fighting, you can sorta do it".

1) If the Linux user is using /dev/input/mice for his mouse device in
XFree/x.org, even if he's got five USB mice plugged in, all his mouse
input will be interpolated into one virtual IMPS/2 mouse by the kernel,
and the X server won't know the difference. Most distros are doing this
out of the box now, since for all normal cases it makes a lot of sense,
but it makes assuming you can get multiple mice by default on Linux
basically wrong.

2) Even if you can coerce the X server into noticing multiple mice, you
lose the functionality on Linux with fbcon, etc.

3) Actually, as far as X11 goes, it's worse than that: read on.

Eventually, after getting a mouse motion event from the
OS/Xserver/whatever, _all_ SDL targets call SDL_PrivateMouseMotion(),
which does not let them specify a device index. Here's the exact code in
SDL_PrivateMouseMotion that sends the SDL_MOUSEMOTION event to your app:

    SDL_Event event;
    memset(&event, 0, sizeof(event));
    event.type = SDL_MOUSEMOTION;
    event.motion.state = buttonstate;
    event.motion.x = X;
    event.motion.y = Y;
    event.motion.xrel = Xrel;
    event.motion.yrel = Yrel;
    if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) {
        posted = 1;

...as you can see, no platform, or target on any platform currently
supports multiple mice, since the point where we pass these to the app
never sets the field to anything but zero.

And, while we're at it, here's the structure that backs the X11
"MotionNotify" event, which SDL uses to make SDL_MOUSEMOTION on X11.

typedef struct {
    int type;              /* MotionNotify */
    unsigned long serial;  /* # of last request processed */
    Bool send_event;       /* true if this came from a SendEvent */
    Display *display;      /* Display the event was read from */
    Window window;         /* ``event'' window reported relative to */
    Window root;           /* root window that the event occurred on */
    Window subwindow;      /* child window */
    Time time;             /* milliseconds */
    int x, y;              /* x, y coordinates in event win */
    int x_root, y_root;    /* coordinates relative to root */
    unsigned int state;    /* key or button mask */
    char is_hint;          /* detail */
    Bool same_screen;      /* same screen flag */
} XMotionEvent;

So, the X11 protocol won't send you a device ID.

The WinDib target uses standard Windows messages, which don't specify a
device id. Theoretically, the windx5 target can enumerate multiple mice
via DirectInput, but it doesn't try, probably because the MSDN reference
page for IDirectInput8::EnumDevices() says this:

"On Microsoft Windows XP, Microsoft DirectInput enumerates only one
mouse and one keyboard device, referred to as the system mouse and the
system keyboard."

MacOS X just doesn't do this at all at the Cocoa layer (although, in
10.4 ("Tiger"), you can have multiple Tablet devices)...quartz target is
out of luck.

This is probably true on all the other platforms SDL supports too.

So, here's the good news.

Windows, Linux, and MacOS _can_ all support multiple, distinct mice, but
they don't in the standard event interfaces.

On Windows, you have to enable the WM_INPUT event and then parse out raw
mouse packets.

On MacOS X, you can use HID Manager to get raw HID packets (despite the
name, this works with non-USB things, like the Powerbook's trackpad). If
you use the "HID Utilities" source layered over HID Manager, this is
surprisingly little code, considering how low-level it is. WM_INPUT
isn't much worse on Windows.

On Linux, you can cat "/dev/input/eventX" and see binary crap stream to
the xterm while you wiggle the mouse cursor in the X server...which
means you can read mouse input seperately and directly without
interfering with the X server. I think the "event" device nodes have a
standard interface that is abstracted from the specific hardware
involved. This would also let you handle multiple USB keyboards (etc) if
you were so inclined. More importantly, it'd work from both X11 and
fbcon, but it obviously is useless for remote X11.

My understanding is that using these approaches on these three platforms
will get you support for multiple mice in a generic way, and not just
USB ones (or whatever the next popular standard is).

None of this is written, but I did just have to implement this directly
in application code of an SDL-based game on MacOS, so I know a little
about it.  :)

Some notes:
1) You would have to have SDL ignore normal mouse input when travelling
this path, since you'll still get MOUSEMOTION events for the system
cursor even though you're moving five mice.

2) Since many apps expect you to move the system cursor, multiple mice
are arguably useless unless you have the input bound to your window and
the system cursor hidden. I can't see a reasonably way for SDL to
provide multiple mice input without that condition. Since MacOS 10.3
("Panther"), you can tell the HID Manager to decouple a given mouse from
the system cursor, and, assuming that x.org is only bound to one device,
you can work around it there, too...arguably both issues make this
difficult to assume the end user will have a proper configuration. I
don't know about Windows for this.

3) Assuming a Linux kernel character device interface will never change
is asking for trouble.  :)


More information about the SDL mailing list