From b60dfec601a242545a57c5154835201aedddaa66 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 25 Aug 2008 06:33:00 +0000 Subject: [PATCH] Final merge of Google Summer of Code 2008 work... Many-mouse and tablet support by Szymon Wilczek, mentored by Ryan C. Gordon Everything concerning the project is noted on the wiki: http://wilku.ravenlord.ws/doku.php?id=start --- configure.in | 5 +- include/SDL_events.h | 27 ++- include/SDL_keysym.h | 2 +- include/SDL_mouse.h | 22 ++- src/SDL_compat.c | 2 +- src/events/SDL_mouse.c | 235 ++++++++++++++++++++----- src/events/SDL_mouse_c.h | 37 +++- src/video/cocoa/SDL_cocoamouse.m | 3 +- src/video/cocoa/SDL_cocoawindow.m | 2 +- src/video/win32/SDL_win32events.c | 275 +++++++++++++----------------- src/video/win32/SDL_win32mouse.c | 168 +++++++++++++++++- src/video/win32/SDL_win32video.c | 12 +- src/video/win32/SDL_win32window.c | 65 ++++++- src/video/x11/SDL_x11dyn.h | 2 +- src/video/x11/SDL_x11events.c | 80 +++++---- src/video/x11/SDL_x11mouse.c | 68 +++++++- src/video/x11/SDL_x11sym.h | 5 + src/video/x11/SDL_x11video.c | 50 +++++- src/video/x11/SDL_x11video.h | 3 +- src/video/x11/SDL_x11window.c | 7 + test/testalpha.c | 2 +- test/testgl.c | 2 +- 22 files changed, 806 insertions(+), 268 deletions(-) diff --git a/configure.in b/configure.in index 8cfa63c98..28151aea6 100644 --- a/configure.in +++ b/configure.in @@ -1033,6 +1033,9 @@ AC_HELP_STRING([--enable-x11-shared], [dynamically load X11 support [[default=ma SOURCES="$SOURCES $srcdir/src/video/Xext/XmuStdCmap/*.c" EXTRA_CFLAGS="$EXTRA_CFLAGS $X_CFLAGS" +echo "FIXME: Need to get dynamic loading of XInput working" + enable_x11_shared=no + if test x$enable_x11_shared = xmaybe; then enable_x11_shared=$x11_symbols_private fi @@ -1055,7 +1058,7 @@ AC_HELP_STRING([--enable-x11-shared], [dynamically load X11 support [[default=ma AC_DEFINE_UNQUOTED(SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT, "$x11ext_lib") else enable_x11_shared=no - EXTRA_LDFLAGS="$EXTRA_LDFLAGS $X_LIBS -lX11 -lXext" + EXTRA_LDFLAGS="$EXTRA_LDFLAGS $X_LIBS -lX11 -lXext -lXi" fi have_video=yes diff --git a/include/SDL_events.h b/include/SDL_events.h index d26cf09d3..79d12ae18 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -72,9 +72,11 @@ typedef enum SDL_JOYBUTTONUP, /**< Joystick button released */ SDL_QUIT, /**< User-requested quit */ SDL_SYSWMEVENT, /**< System specific event */ + SDL_PROXIMITYIN, /**< Proximity In event */ + SDL_PROXIMITYOUT, /**< Proximity Out event */ SDL_EVENT_RESERVED1, /**< Reserved for future use... */ - SDL_EVENT_RESERVED2, /**< Reserved for future use... */ - SDL_EVENT_RESERVED3, /**< Reserved for future use... */ + SDL_EVENT_RESERVED2, + SDL_EVENT_RESERVED3, /* Events SDL_USEREVENT through SDL_MAXEVENTS-1 are for your use */ SDL_USEREVENT = 24, /* This last event is only for bounding internal arrays @@ -112,7 +114,9 @@ typedef enum SDL_EVENTMASK(SDL_JOYHATMOTION) | SDL_EVENTMASK(SDL_JOYBUTTONDOWN) | SDL_EVENTMASK(SDL_JOYBUTTONUP), SDL_QUITMASK = SDL_EVENTMASK(SDL_QUIT), - SDL_SYSWMEVENTMASK = SDL_EVENTMASK(SDL_SYSWMEVENT) + SDL_SYSWMEVENTMASK = SDL_EVENTMASK(SDL_SYSWMEVENT), + SDL_PROXIMITYINMASK = SDL_EVENTMASK(SDL_PROXIMITYIN), + SDL_PROXIMITYOUTMASK = SDL_EVENTMASK(SDL_PROXIMITYOUT) } SDL_EventMask; #define SDL_ALLEVENTS 0xFFFFFFFF @@ -170,6 +174,13 @@ typedef struct SDL_MouseMotionEvent Uint8 state; /**< The current button state */ int x; /**< X coordinate, relative to window */ int y; /**< Y coordinate, relative to window */ + int z; /**< Z coordinate, for future use */ + int pressure; /**< Pressure reported by tablets */ + int pressure_max; /**< Maximum value of the pressure reported by the device */ + int pressure_min; /**< Minimum value of the pressure reported by the device */ + int rotation; /**< For future use */ + int tilt; /**< For future use */ + int cursor; /**< The cursor being used in the event */ int xrel; /**< The relative motion in the X direction */ int yrel; /**< The relative motion in the Y direction */ SDL_WindowID windowID; /**< The window with mouse focus, if any */ @@ -316,6 +327,15 @@ typedef struct SDL_ResizeEvent int h; } SDL_ResizeEvent; +typedef struct SDL_ProximityEvent +{ + Uint8 type; + Uint8 which; + int cursor; + int x; + int y; +} SDL_ProximityEvent; + /** * \union SDL_Event * @@ -337,6 +357,7 @@ typedef union SDL_Event SDL_QuitEvent quit; /**< Quit request event data */ SDL_UserEvent user; /**< Custom event data */ SDL_SysWMEvent syswm; /**< System dependent window event data */ + SDL_ProximityEvent proximity; /**< Proximity In or Out event */ /* Temporarily here for backwards compatibility */ SDL_ActiveEvent active; diff --git a/include/SDL_keysym.h b/include/SDL_keysym.h index 60fdea860..63174ac6f 100644 --- a/include/SDL_keysym.h +++ b/include/SDL_keysym.h @@ -242,7 +242,7 @@ enum SDLK_KBDILLUMDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMDOWN), SDLK_KBDILLUMUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMUP), SDLK_EJECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EJECT), - SDLK_SLEEP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SLEEP), + SDLK_SLEEP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SLEEP) }; /** diff --git a/include/SDL_mouse.h b/include/SDL_mouse.h index 567abccda..4695a8b07 100644 --- a/include/SDL_mouse.h +++ b/include/SDL_mouse.h @@ -72,7 +72,7 @@ extern DECLSPEC int SDLCALL SDL_SelectMouse(int index); * * \brief Get the window which currently has focus for the currently selected mouse. */ -extern DECLSPEC SDL_WindowID SDLCALL SDL_GetMouseFocusWindow(void); +extern DECLSPEC SDL_WindowID SDLCALL SDL_GetMouseFocusWindow(int index); /** * \fn int SDL_SetRelativeMouseMode(SDL_bool enabled) @@ -92,7 +92,8 @@ extern DECLSPEC SDL_WindowID SDLCALL SDL_GetMouseFocusWindow(void); * * \sa SDL_GetRelativeMouseMode() */ -extern DECLSPEC int SDLCALL SDL_SetRelativeMouseMode(SDL_bool enabled); +extern DECLSPEC int SDLCALL SDL_SetRelativeMouseMode(int index, + SDL_bool enabled); /** * \fn SDL_bool SDL_GetRelativeMouseMode() @@ -101,7 +102,7 @@ extern DECLSPEC int SDLCALL SDL_SetRelativeMouseMode(SDL_bool enabled); * * \sa SDL_SetRelativeMouseMode() */ -extern DECLSPEC SDL_bool SDLCALL SDL_GetRelativeMouseMode(void); +extern DECLSPEC SDL_bool SDLCALL SDL_GetRelativeMouseMode(int index); /** * \fn Uint8 SDL_GetMouseState(int *x, int *y) @@ -113,7 +114,7 @@ extern DECLSPEC SDL_bool SDLCALL SDL_GetRelativeMouseMode(void); * mouse cursor position relative to the focus window for the currently * selected mouse. You can pass NULL for either x or y. */ -extern DECLSPEC Uint8 SDLCALL SDL_GetMouseState(int *x, int *y); +extern DECLSPEC Uint8 SDLCALL SDL_GetMouseState(int index, int *x, int *y); /** * \fn Uint8 SDL_GetRelativeMouseState(int *x, int *y) @@ -124,7 +125,8 @@ extern DECLSPEC Uint8 SDLCALL SDL_GetMouseState(int *x, int *y); * be tested using the SDL_BUTTON(X) macros, and x and y are set to the * mouse deltas since the last call to SDL_GetRelativeMouseState(). */ -extern DECLSPEC Uint8 SDLCALL SDL_GetRelativeMouseState(int *x, int *y); +extern DECLSPEC Uint8 SDLCALL SDL_GetRelativeMouseState(int index, int *x, + int *y); /** * \fn void SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y) @@ -203,6 +205,16 @@ extern DECLSPEC int SDLCALL SDL_ShowCursor(int toggle); Button 2: Middle mouse button Button 3: Right mouse button */ + +/* FIXME: Where do these functions go in this header? + Also, add doxygen documentation for these... +*/ +extern DECLSPEC char *SDLCALL SDL_GetMouseName(int index); + +extern DECLSPEC int SDLCALL SDL_GetCursorsNumber(int index); + +extern DECLSPEC int SDLCALL SDL_GetCurrentCursor(int index); + #define SDL_BUTTON(X) (1 << ((X)-1)) #define SDL_BUTTON_LEFT 1 #define SDL_BUTTON_MIDDLE 2 diff --git a/src/SDL_compat.c b/src/SDL_compat.c index 0d29b44d4..1c1572a69 100644 --- a/src/SDL_compat.c +++ b/src/SDL_compat.c @@ -256,7 +256,7 @@ SDL_CompatEventFilter(void *userdata, SDL_Event * event) } selected = SDL_SelectMouse(event->wheel.which); - SDL_GetMouseState(&x, &y); + SDL_GetMouseState(selected, &x, &y); SDL_SelectMouse(selected); if (event->wheel.y > 0) { diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index b2579dc0f..ac133b2e9 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -28,9 +28,13 @@ #include "default_cursor.h" -static int SDL_num_mice; -static int SDL_current_mouse; -static SDL_Mouse **SDL_mice; +static int SDL_num_mice = 0; +static int SDL_current_mouse = -1; +static SDL_Mouse **SDL_mice = NULL; +static int *SDL_IdIndex = NULL; +static int SDL_highestId = -1; +static int last_x, last_y; /* the last reported x and y coordinates by the system cursor */ +int x_max, y_max; /* current window width and height */ /* Public functions */ @@ -50,10 +54,44 @@ SDL_GetMouse(int index) } int -SDL_AddMouse(const SDL_Mouse * mouse, int index) +SDL_SetMouseIndexId(int id, int index) +{ + if (id < 0) { + SDL_SetError("Invalid Mouse ID"); + return -1; + } + if (id > SDL_highestId) { + int *indexes; + indexes = (int *) SDL_realloc(SDL_IdIndex, (id + 1) * sizeof(int)); + if (!indexes) { + SDL_OutOfMemory(); + return -1; + } + SDL_IdIndex = indexes; + SDL_IdIndex[id] = index; + SDL_highestId = id; + } else { + SDL_IdIndex[id] = index; + } + return 1; +} + +SDL_Mouse * +SDL_GetMouseByID(int id) +{ + if (id < 0 || id > SDL_highestId) { + return NULL; + } + return SDL_GetMouse(SDL_IdIndex[id]); +} + +int +SDL_AddMouse(const SDL_Mouse * mouse, int index, char *name, int pressure_max, + int pressure_min, int ends) { SDL_Mouse **mice; int selected_mouse; + int length; /* Add the mouse to the list of mice */ if (index < 0 || index >= SDL_num_mice || SDL_mice[index]) { @@ -75,7 +113,13 @@ SDL_AddMouse(const SDL_Mouse * mouse, int index) } *SDL_mice[index] = *mouse; - /* Create the default cursor for the mouse */ + /* we're setting the mouse properties */ + length = 0; + length = SDL_strlen(name); + SDL_mice[index]->name = SDL_malloc((length + 1) * sizeof(char)); + SDL_strlcpy(SDL_mice[index]->name, name, length); + SDL_mice[index]->pressure_max = pressure_max; + SDL_mice[index]->pressure_min = pressure_min; SDL_mice[index]->cursor_shown = SDL_TRUE; selected_mouse = SDL_SelectMouse(index); SDL_mice[index]->cur_cursor = NULL; @@ -83,6 +127,14 @@ SDL_AddMouse(const SDL_Mouse * mouse, int index) SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY); SDL_SetCursor(SDL_mice[index]->def_cursor); + /* we're assuming that all mice are in the computer sensing zone */ + SDL_mice[index]->proximity = SDL_TRUE; + /* we're assuming that all mice are working in the absolute position mode + thanx to that, the users that don't want to use many mice don't have to + worry about anything */ + SDL_mice[index]->relative_mode = SDL_FALSE; + SDL_mice[index]->current_end = 0; + SDL_mice[index]->total_ends = ends; SDL_SelectMouse(selected_mouse); return index; @@ -98,6 +150,7 @@ SDL_DelMouse(int index) } mouse->def_cursor = NULL; + SDL_free(mouse->name); while (mouse->cursors) { SDL_FreeCursor(mouse->cursors); } @@ -155,9 +208,9 @@ SDL_SelectMouse(int index) } SDL_WindowID -SDL_GetMouseFocusWindow() +SDL_GetMouseFocusWindow(int index) { - SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_Mouse *mouse = SDL_GetMouse(index); if (!mouse) { return 0; @@ -177,9 +230,9 @@ FlushMouseMotion(void *param, SDL_Event * event) } int -SDL_SetRelativeMouseMode(SDL_bool enabled) +SDL_SetRelativeMouseMode(int index, SDL_bool enabled) { - SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_Mouse *mouse = SDL_GetMouse(index); if (!mouse) { return -1; @@ -205,9 +258,9 @@ SDL_SetRelativeMouseMode(SDL_bool enabled) } SDL_bool -SDL_GetRelativeMouseMode() +SDL_GetRelativeMouseMode(int index) { - SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_Mouse *mouse = SDL_GetMouse(index); if (!mouse) { return SDL_FALSE; @@ -216,9 +269,9 @@ SDL_GetRelativeMouseMode() } Uint8 -SDL_GetMouseState(int *x, int *y) +SDL_GetMouseState(int index, int *x, int *y) { - SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_Mouse *mouse = SDL_GetMouse(index); if (!mouse) { if (x) { @@ -240,9 +293,9 @@ SDL_GetMouseState(int *x, int *y) } Uint8 -SDL_GetRelativeMouseState(int *x, int *y) +SDL_GetRelativeMouseState(int index, int *x, int *y) { - SDL_Mouse *mouse = SDL_GetMouse(SDL_current_mouse); + SDL_Mouse *mouse = SDL_GetMouse(index); if (!mouse) { if (x) { @@ -266,16 +319,18 @@ SDL_GetRelativeMouseState(int *x, int *y) } void -SDL_SetMouseFocus(int index, SDL_WindowID windowID) +SDL_SetMouseFocus(int id, SDL_WindowID windowID) { - SDL_Mouse *mouse = SDL_GetMouse(index); - int i; + SDL_Mouse *mouse = SDL_GetMouseByID(id); + int i, index; SDL_bool focus; if (!mouse || (mouse->focus == windowID)) { return; } + index = SDL_IdIndex[id]; + /* See if the current window has lost focus */ if (mouse->focus) { focus = SDL_FALSE; @@ -315,28 +370,62 @@ SDL_SetMouseFocus(int index, SDL_WindowID windowID) } int -SDL_SendMouseMotion(int index, int relative, int x, int y) +SDL_SendProximity(int id, int x, int y, int type) { - SDL_Mouse *mouse = SDL_GetMouse(index); + SDL_Mouse *mouse = SDL_GetMouseByID(id); + int posted = 0; + last_x = x; + last_y = y; + if (SDL_ProcessEvents[type] == SDL_ENABLE) { + SDL_Event event; + event.proximity.which = (Uint8) index; + event.proximity.x = x; + event.proximity.y = y; + event.proximity.cursor = mouse->current_end; + event.proximity.type = type; + posted = (SDL_PushEvent(&event) > 0); + if (type == SDL_PROXIMITYIN) { + mouse->proximity = SDL_TRUE; + } else { + mouse->proximity = SDL_FALSE; + } + } + return posted; +} + +int +SDL_SendMouseMotion(int id, int relative, int x, int y, int pressure) +{ + SDL_Mouse *mouse = SDL_GetMouseByID(id); int posted; int xrel; int yrel; + /* while using the relative mode and many windows, we have to be sure, + that the pointers find themselves inside the windows */ + if (x > x_max) { + x = x_max; + } + if (y > y_max) { + y = y_max; + } + if (!mouse || mouse->flush_motion) { return 0; } - if (relative) { - /* Push the cursor around */ - xrel = x; - yrel = y; - x = (mouse->x + xrel); - y = (mouse->y + yrel); - } else { - xrel = x - mouse->x; - yrel = y - mouse->y; + /* if the mouse is out of proximity we don't to want to have any motion from it */ + if (mouse->proximity == SDL_FALSE) { + last_x = x; + last_y = y; + return 0; } + /* the relative motion is calculated regarding the system cursor last position */ + + xrel = x - last_x; + yrel = y - last_y; + /* Drop events that don't change state */ if (!xrel && !yrel) { #if 0 @@ -345,13 +434,29 @@ SDL_SendMouseMotion(int index, int relative, int x, int y) return 0; } - /* Update internal mouse state */ - if (!mouse->relative_mode) { + /* Update internal mouse coordinates */ + if (mouse->relative_mode == SDL_FALSE) { mouse->x = x; mouse->y = y; + } else { + if (mouse->x + xrel > x_max) { + mouse->x = x_max; + } else if (mouse->x + xrel < 0) { + mouse->x = 0; + } else { + mouse->x += xrel; + } + if (mouse->y + yrel > y_max) { + mouse->y = y_max; + } else if (mouse->y + yrel < 0) { + mouse->y = 0; + } else { + mouse->y += yrel; + } } mouse->xdelta += xrel; mouse->ydelta += yrel; + mouse->pressure = pressure; /* Move the mouse cursor, if needed */ if (mouse->cursor_shown && !mouse->relative_mode && @@ -361,25 +466,32 @@ SDL_SendMouseMotion(int index, int relative, int x, int y) /* Post the event, if desired */ posted = 0; - if (SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE) { + if (SDL_ProcessEvents[SDL_MOUSEMOTION] == SDL_ENABLE && + mouse->proximity == SDL_TRUE) { SDL_Event event; event.motion.type = SDL_MOUSEMOTION; event.motion.which = (Uint8) index; event.motion.state = mouse->buttonstate; event.motion.x = mouse->x; event.motion.y = mouse->y; + event.motion.pressure = mouse->pressure; event.motion.xrel = xrel; event.motion.yrel = yrel; event.motion.windowID = mouse->focus; + event.motion.pressure_max = mouse->pressure_max; + event.motion.pressure_min = mouse->pressure_min; + event.motion.cursor = mouse->current_end; posted = (SDL_PushEvent(&event) > 0); } + last_x = x; + last_y = y; return posted; } int -SDL_SendMouseButton(int index, Uint8 state, Uint8 button) +SDL_SendMouseButton(int id, Uint8 state, Uint8 button) { - SDL_Mouse *mouse = SDL_GetMouse(index); + SDL_Mouse *mouse = SDL_GetMouseByID(id); int posted; Uint8 type; @@ -398,10 +510,6 @@ SDL_SendMouseButton(int index, Uint8 state, Uint8 button) mouse->buttonstate |= SDL_BUTTON(button); break; case SDL_RELEASED: - if (!(mouse->buttonstate & SDL_BUTTON(button))) { - /* Ignore this event, no state change */ - return 0; - } type = SDL_MOUSEBUTTONUP; mouse->buttonstate &= ~SDL_BUTTON(button); break; @@ -463,7 +571,7 @@ SDL_WarpMouseInWindow(SDL_WindowID windowID, int x, int y) mouse->WarpMouse(mouse, windowID, x, y); } else { SDL_SetMouseFocus(SDL_current_mouse, windowID); - SDL_SendMouseMotion(SDL_current_mouse, 0, x, y); + SDL_SendMouseMotion(SDL_current_mouse, 0, x, y, 0); } } @@ -649,4 +757,53 @@ SDL_ShowCursor(int toggle) return shown; } +char * +SDL_GetMouseName(int index) +{ + SDL_Mouse *mouse = SDL_GetMouse(index); + if (!mouse) { + return NULL; + } + return mouse->name; +} + +void +SDL_UpdateCoordinates(int x, int y) +{ + x_max = x; + y_max = y; +} + +void +SDL_ChangeEnd(int id, int end) +{ + SDL_Mouse *mouse = SDL_GetMouseByID(id); + + if (mouse) { + mouse->current_end = end; + } +} + +int +SDL_GetCursorsNumber(int index) +{ + SDL_Mouse *mouse = SDL_GetMouse(index); + + if (!mouse) { + return -1; + } + return mouse->total_ends; +} + +int +SDL_GetCurrentCursor(int index) +{ + SDL_Mouse *mouse = SDL_GetMouse(index); + + if (!mouse) { + return -1; + } + return mouse->current_end; +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/events/SDL_mouse_c.h b/src/events/SDL_mouse_c.h index 530e38106..ba1abc9da 100644 --- a/src/events/SDL_mouse_c.h +++ b/src/events/SDL_mouse_c.h @@ -29,9 +29,7 @@ typedef struct SDL_Mouse SDL_Mouse; struct SDL_Cursor { SDL_Mouse *mouse; - SDL_Cursor *next; - void *driverdata; }; @@ -56,14 +54,27 @@ struct SDL_Mouse /* Free the mouse when it's time */ void (*FreeMouse) (SDL_Mouse * mouse); + /* data common for tablets */ + int pressure; + int pressure_max; + int pressure_min; + int tilt; /* for future use */ + int rotation; /* for future use */ + int total_ends; + int current_end; + /* Data common to all mice */ SDL_WindowID focus; + int which; int x; int y; + int z; /* for future use */ int xdelta; int ydelta; + char *name; Uint8 buttonstate; SDL_bool relative_mode; + SDL_bool proximity; SDL_bool flush_motion; SDL_Cursor *cursors; @@ -74,17 +85,23 @@ struct SDL_Mouse void *driverdata; }; - /* Initialize the mouse subsystem */ extern int SDL_MouseInit(void); /* Get the mouse at an index */ extern SDL_Mouse *SDL_GetMouse(int index); +/* Assign an id to a mouse at an index */ +extern int SDL_SetMouseIndexId(int id, int index); + +/* Get the mouse by id */ +extern SDL_Mouse *SDL_GetMouseByID(int id); + /* Add a mouse, possibly reattaching at a particular index (or -1), returning the index of the mouse, or -1 if there was an error. */ -extern int SDL_AddMouse(const SDL_Mouse * mouse, int index); +extern int SDL_AddMouse(const SDL_Mouse * mouse, int index, char *name, + int pressure_max, int pressure_min, int ends); /* Remove a mouse at an index, clearing the slot for later */ extern void SDL_DelMouse(int index); @@ -93,20 +110,24 @@ extern void SDL_DelMouse(int index); extern void SDL_ResetMouse(int index); /* Set the mouse focus window */ -extern void SDL_SetMouseFocus(int index, SDL_WindowID windowID); +extern void SDL_SetMouseFocus(int id, SDL_WindowID windowID); /* Send a mouse motion event for a mouse at an index */ -extern int SDL_SendMouseMotion(int index, int relative, int x, int y); +extern int SDL_SendMouseMotion(int id, int relative, int x, int y, int z); /* Send a mouse button event for a mouse at an index */ -extern int SDL_SendMouseButton(int index, Uint8 state, Uint8 button); +extern int SDL_SendMouseButton(int id, Uint8 state, Uint8 button); /* Send a mouse wheel event for a mouse at an index */ -extern int SDL_SendMouseWheel(int index, int x, int y); +extern int SDL_SendMouseWheel(int id, int x, int y); /* Shutdown the mouse subsystem */ extern void SDL_MouseQuit(void); +/* FIXME: Where do these functions go in this header? */ +extern void SDL_UpdateCoordinates(int x, int y); +extern void SDL_ChangeEnd(int id, int end); + #endif /* _SDL_mouse_c_h */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/cocoa/SDL_cocoamouse.m b/src/video/cocoa/SDL_cocoamouse.m index 2a36c9aae..9eebd2d6f 100644 --- a/src/video/cocoa/SDL_cocoamouse.m +++ b/src/video/cocoa/SDL_cocoamouse.m @@ -32,7 +32,8 @@ SDL_Mouse mouse; SDL_zero(mouse); - data->mouse = SDL_AddMouse(&mouse, -1); + data->mouse = SDL_AddMouse(&mouse, -1, "Mouse", 0, 0, 1); + SDL_SetMouseIndexId(data->mouse, data->mouse); } void diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 30e94240e..15f96a177 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -250,7 +250,7 @@ - (void)mouseMoved:(NSEvent *)theEvent if (mouse->focus != _data->windowID) { SDL_SetMouseFocus(index, _data->windowID); } - SDL_SendMouseMotion(index, 0, (int)point.x, (int)point.y); + SDL_SendMouseMotion(index, 0, (int)point.x, (int)point.y, 0); } } diff --git a/src/video/win32/SDL_win32events.c b/src/video/win32/SDL_win32events.c index 5f257136d..dfb8218d3 100644 --- a/src/video/win32/SDL_win32events.c +++ b/src/video/win32/SDL_win32events.c @@ -19,6 +19,12 @@ Sam Lantinga slouken@libsdl.org */ + +#if (_WIN32_WINNT < 0x0501) +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif + #include "SDL_config.h" #include "SDL_win32video.h" @@ -26,6 +32,11 @@ #include "SDL_vkeys.h" #include "../../events/SDL_events_c.h" +#include +#define PACKETDATA ( PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_CURSOR) +#define PACKETMODE 0 +#include + /*#define WMMSG_DEBUG*/ #ifdef WMMSG_DEBUG #include @@ -49,6 +60,12 @@ #define GET_XBUTTON_WPARAM(w) (HIWORD(w)) #endif +extern HCTX *g_hCtx; +extern HANDLE *mice; +extern int total_mice; +extern int tablet; +int pressure = 0; /* the pressure reported by the tablet */ + static WPARAM RemapVKEY(WPARAM wParam, LPARAM lParam) { @@ -84,6 +101,8 @@ LRESULT CALLBACK WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { SDL_WindowData *data; + RAWINPUT *raw; + PACKET packet; /* Send a SDL_SYSWMEVENT if the application wants them */ if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) { @@ -114,10 +133,40 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam); fclose(log); } + #endif switch (msg) { + case WT_PACKET: + { + /* if we receive such data we need to update the pressure */ + if (WTPacket((HCTX) lParam, wParam, &packet)) { + SDL_ChangeEnd(tablet, (int) packet.pkCursor); + pressure = (int) packet.pkNormalPressure; + } + } + break; + + case WT_PROXIMITY: + { + /* checking where the proximity message showed up */ + int h_context = LOWORD(lParam); + LPPOINT point; + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + + /* are we in proximity or out of proximity */ + if (h_context == 0) { + SDL_SendProximity(tablet, (int) (&point->x), + (int) (&point->y), SDL_PROXIMITYOUT); + } else { + SDL_SendProximity(tablet, (int) (&point->x), + (int) (&point->y), SDL_PROXIMITYIN); + } + } + break; + case WM_SHOWWINDOW: { if (wParam) { @@ -161,48 +210,72 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) SDL_WINDOWEVENT_MINIMIZED, 0, 0); } } - return (0); } - break; + return (0); - case WM_MOUSEMOVE: + case WM_INPUT: /* mouse events */ { + LPBYTE lpb; + int w, h; + const RAWINPUTHEADER *header; int index; - SDL_Mouse *mouse; - int x, y; - - index = data->videodata->mouse; - mouse = SDL_GetMouse(index); - - if (mouse->focus != data->windowID) { - TRACKMOUSEEVENT tme; - - tme.cbSize = sizeof(tme); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hwnd; - TrackMouseEvent(&tme); - - SDL_SetMouseFocus(index, data->windowID); + int i; + int size = 0; + const RAWMOUSE *raw_mouse = NULL; + LPPOINT point; + USHORT flags; + + /* we're collecting data from the mouse */ + GetRawInputData((HRAWINPUT) lParam, RID_INPUT, NULL, &size, + sizeof(RAWINPUTHEADER)); + lpb = SDL_malloc(size * sizeof(LPBYTE)); + GetRawInputData((HRAWINPUT) lParam, RID_INPUT, lpb, &size, + sizeof(RAWINPUTHEADER)); + raw = (RAWINPUT *) lpb; + header = &raw->header; + flags = raw->data.mouse.usButtonFlags; + + /* we're checking which mouse generated the event */ + for (i = 0; i < total_mice; ++i) { + if (mice[i] == header->hDevice) { + index = i; + break; + } } + GetCursorPos(&point); + ScreenToClient(hwnd, &point); + SDL_GetWindowSize(data->windowID, &w, &h); + SDL_UpdateCoordinates(w, h); /* we're updating the current window size */ - /* mouse has moved within the window */ - x = LOWORD(lParam); - y = HIWORD(lParam); - if (mouse->relative_mode) { - int w, h; - POINT center; - SDL_GetWindowSize(data->windowID, &w, &h); - center.x = (w / 2); - center.y = (h / 2); - x -= center.x; - y -= center.y; - if (x || y) { - ClientToScreen(hwnd, ¢er); - SetCursorPos(center.x, center.y); - SDL_SendMouseMotion(index, 1, x, y); - } + /* if the message was sent by a tablet we have to send also pressure */ + if (i == tablet) { + SDL_SendMouseMotion(index, 0, (int) (&point->x), + (int) (&point->y), pressure); } else { - SDL_SendMouseMotion(index, 0, x, y); + SDL_SendMouseMotion(index, 0, (int) (&point->x), + (int) (&point->y), 0); + } + /* we're sending mouse buttons messages to check up if sth changed */ + if (flags & RI_MOUSE_BUTTON_1_DOWN) { + SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_LEFT); + } else if (flags & RI_MOUSE_BUTTON_1_UP) { + SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_LEFT); + } + if (flags & RI_MOUSE_BUTTON_2_DOWN) { + SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_MIDDLE); + } else if (flags & RI_MOUSE_BUTTON_2_UP) { + SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_MIDDLE); + } + if (flags & RI_MOUSE_BUTTON_3_DOWN) { + SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_RIGHT); + } else if (flags & RI_MOUSE_BUTTON_3_UP) { + SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_RIGHT); + } + if (flags & RI_MOUSE_WHEEL) { + if (raw->data.mouse.usButtonData != 0) { + SDL_SendMouseWheel(index, 0, + raw->data.mouse.usButtonData); + } } } return (0); @@ -221,117 +294,6 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) } return (0); - case WM_LBUTTONDOWN: - case WM_LBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONUP: - case WM_RBUTTONDOWN: - case WM_RBUTTONUP: - case WM_XBUTTONDOWN: - case WM_XBUTTONUP: - { - int xbuttonval = 0; - int index; - SDL_Mouse *mouse; - Uint8 button, state; - - /* DJM: - We want the SDL window to take focus so that - it acts like a normal windows "component" - (e.g. gains keyboard focus on a mouse click). - */ - SetFocus(hwnd); - - index = data->videodata->mouse; - mouse = SDL_GetMouse(index); - - /* Figure out which button to use */ - switch (msg) { - case WM_LBUTTONDOWN: - button = SDL_BUTTON_LEFT; - state = SDL_PRESSED; - break; - case WM_LBUTTONUP: - button = SDL_BUTTON_LEFT; - state = SDL_RELEASED; - break; - case WM_MBUTTONDOWN: - button = SDL_BUTTON_MIDDLE; - state = SDL_PRESSED; - break; - case WM_MBUTTONUP: - button = SDL_BUTTON_MIDDLE; - state = SDL_RELEASED; - break; - case WM_RBUTTONDOWN: - button = SDL_BUTTON_RIGHT; - state = SDL_PRESSED; - break; - case WM_RBUTTONUP: - button = SDL_BUTTON_RIGHT; - state = SDL_RELEASED; - break; - case WM_XBUTTONDOWN: - xbuttonval = GET_XBUTTON_WPARAM(wParam); - button = SDL_BUTTON_X1 + xbuttonval - 1; - state = SDL_PRESSED; - break; - case WM_XBUTTONUP: - xbuttonval = GET_XBUTTON_WPARAM(wParam); - button = SDL_BUTTON_X1 + xbuttonval - 1; - state = SDL_RELEASED; - break; - default: - /* Eh? Unknown button? */ - return (0); - } - if (state == SDL_PRESSED) { - /* Grab mouse so we get up events */ - if (++data->mouse_pressed > 0) { - SetCapture(hwnd); - } - } else { - /* Release mouse after all up events */ - if (--data->mouse_pressed <= 0) { - ReleaseCapture(); - data->mouse_pressed = 0; - } - } - - if (!mouse->relative_mode) { - int x, y; - x = LOWORD(lParam); - y = HIWORD(lParam); - SDL_SendMouseMotion(index, 0, x, y); - } - SDL_SendMouseButton(index, state, button); - - /* - * MSDN says: - * "Unlike the WM_LBUTTONUP, WM_MBUTTONUP, and WM_RBUTTONUP - * messages, an application should return TRUE from [an - * XBUTTON message] if it processes it. Doing so will allow - * software that simulates this message on Microsoft Windows - * systems earlier than Windows 2000 to determine whether - * the window procedure processed the message or called - * DefWindowProc to process it. - */ - if (xbuttonval > 0) { - return (TRUE); - } - } - return (0); - - case WM_MOUSEWHEEL: - { - int index; - int motion = (short) HIWORD(wParam); - - index = data->videodata->mouse; - SDL_SendMouseWheel(index, 0, motion); - } - return (0); - case WM_SYSKEYDOWN: case WM_KEYDOWN: { @@ -426,6 +388,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) wParam = VK_ENTER; break; } + /* Windows only reports keyup for print screen */ if (wParam == VK_SNAPSHOT && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] == @@ -499,11 +462,9 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) inside their function, so I have to do it here. */ style = GetWindowLong(hwnd, GWL_STYLE); - AdjustWindowRect(&size, - style, - style & WS_CHILDWINDOW ? FALSE : GetMenu(hwnd) != - NULL); - + AdjustWindowRect(&size, style, + style & WS_CHILDWINDOW ? FALSE : GetMenu(hwnd) + != NULL); w = size.right - size.left; h = size.bottom - size.top; @@ -661,8 +622,9 @@ SDL_RegisterApp(char *name, Uint32 style, void *hInst) /* Register the application class */ class.hCursor = NULL; - class.hIcon = LoadImage(SDL_Instance, SDL_Appname, - IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); + class.hIcon = + LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0, + LR_DEFAULTCOLOR); class.lpszMenuName = NULL; class.lpszClassName = SDL_Appname; class.hbrBackground = NULL; @@ -707,11 +669,8 @@ WIN_SetError(const char *prefix) { TCHAR buffer[1024]; char *message; - - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - GetLastError(), 0, buffer, SDL_arraysize(buffer), NULL); - + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, + buffer, SDL_arraysize(buffer), NULL); message = WIN_StringToUTF8(buffer); SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ":" : "", message); SDL_free(message); diff --git a/src/video/win32/SDL_win32mouse.c b/src/video/win32/SDL_win32mouse.c index e2b4dd88c..52f7adcb4 100644 --- a/src/video/win32/SDL_win32mouse.c +++ b/src/video/win32/SDL_win32mouse.c @@ -19,20 +19,179 @@ Sam Lantinga slouken@libsdl.org */ + +/* we need to define it, so that raw input is included*/ + +#if (_WIN32_WINNT < 0x0501) +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif + #include "SDL_config.h" #include "SDL_win32video.h" #include "../../events/SDL_mouse_c.h" +#include + +#define PACKETDATA ( PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_CURSOR) +#define PACKETMODE 0 +#include +extern HANDLE *mice; +extern int total_mice; +extern int tablet; + void WIN_InitMouse(_THIS) { + int index = 0; + RAWINPUTDEVICELIST *deviceList = NULL; + int devCount = 0; + int i; + int tmp = 0; + char *buffer = NULL; + char *tab = "wacom"; /* since windows does't give us handles to tablets, we have to detect a tablet by it's name */ + const char *rdp = "rdp_mou"; SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - SDL_Mouse mouse; - SDL_zero(mouse); - data->mouse = SDL_AddMouse(&mouse, -1); + /* we're checking for the number of rawinput devices */ + if (GetRawInputDeviceList(NULL, &devCount, sizeof(RAWINPUTDEVICELIST))) { + return; + } + + deviceList = SDL_malloc(sizeof(RAWINPUTDEVICELIST) * devCount); + + /* we're getting the raw input device list */ + GetRawInputDeviceList(deviceList, &devCount, sizeof(RAWINPUTDEVICELIST)); + mice = SDL_malloc(devCount * sizeof(HANDLE)); + + /* we're getting the details of the devices */ + for (i = 0; i < devCount; ++i) { + int is_rdp = 0; + int j; + int k; + char *default_device_name = "Pointing device xx"; + const char *reg_key_root = "System\\CurrentControlSet\\Enum\\"; + char *device_name = SDL_malloc(256 * sizeof(char)); + char *key_name = NULL; + char *tmp_name = NULL; + LONG rc = 0; + HKEY hkey; + DWORD regtype = REG_SZ; + DWORD out = 256 * sizeof(char); + SDL_Mouse mouse; + int l; + if (deviceList[i].dwType != RIM_TYPEMOUSE) { /* if a device isn't a mouse type we don't want it */ + continue; + } + if (GetRawInputDeviceInfoA + (deviceList[i].hDevice, RIDI_DEVICENAME, NULL, &tmp) < 0) { + continue; + } + buffer = SDL_malloc((tmp + 1) * sizeof(char)); + key_name = SDL_malloc(tmp + sizeof(reg_key_root) * sizeof(char)); + + /* we're getting the device registry path and polishing it to get it's name, + surely there must be an easier way, but we haven't found it yet */ + if (GetRawInputDeviceInfoA + (deviceList[i].hDevice, RIDI_DEVICENAME, buffer, &tmp) < 0) { + continue; + } + buffer += 4; + tmp -= 4; + tmp_name = buffer; + for (j = 0; j < tmp; ++j) { + if (*tmp_name == '#') { + *tmp_name = '\\'; + } + + else if (*tmp_name == '{') { + break; + } + ++tmp_name; + } + *tmp_name = '\0'; + SDL_memcpy(key_name, reg_key_root, SDL_strlen(reg_key_root)); + SDL_memcpy(key_name + (SDL_strlen(reg_key_root)), buffer, j + 1); + l = SDL_strlen(key_name); + is_rdp = 0; + if (l >= 7) { + for (j = 0; j < l - 7; ++j) { + for (k = 0; k < 7; ++k) { + if (rdp[k] != + SDL_tolower((unsigned char) key_name[j + k])) { + break; + } + } + if (k == 7) { + is_rdp = 1; + break; + } + } + } + if (is_rdp == 1) { + SDL_free(buffer); + SDL_free(key_name); + SDL_free(device_name); + is_rdp = 0; + continue; + } + + /* we're opening the registry key to get the mouse name */ + rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &hkey); + if (rc != ERROR_SUCCESS) { + SDL_memcpy(device_name, default_device_name, + SDL_strlen(default_device_name)); + } + rc = RegQueryValueExA(hkey, "DeviceDesc", NULL, ®type, device_name, + &out); + RegCloseKey(hkey); + if (rc != ERROR_SUCCESS) { + SDL_memcpy(device_name, default_device_name, + SDL_strlen(default_device_name)); + } + + /* we're saving the handle to the device */ + mice[index] = deviceList[i].hDevice; + SDL_zero(mouse); + SDL_SetMouseIndexId(index, index); + l = SDL_strlen(device_name); + + /* we're checking if the device isn't by any chance a tablet */ + if (tablet == -1) { + for (j = 0; j < l - 5; ++j) { + for (k = 0; k < 5; ++k) { + if (tab[k] != + SDL_tolower((unsigned char) device_name[j + k])) { + break; + } + } + if (k == 5) { + tablet = index; + break; + } + } + } + + /* if it's a tablet, let's read it's maximum and minimum pressure */ + if (tablet == index) { + AXIS pressure; + int cursors; + WTInfo(WTI_DEVICES, DVC_NPRESSURE, &pressure); + WTInfo(WTI_DEVICES, DVC_NCSRTYPES, &cursors); + data->mouse = + SDL_AddMouse(&mouse, index, device_name, pressure.axMax, + pressure.axMin, cursors); + } else { + data->mouse = SDL_AddMouse(&mouse, index, device_name, 0, 0, 1); + } + ++index; + SDL_free(buffer); + SDL_free(key_name); + } + total_mice = index; + SDL_free(deviceList); } void @@ -40,7 +199,8 @@ WIN_QuitMouse(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - SDL_DelMouse(data->mouse); + /* let's delete all of the mice */ + SDL_MouseQuit(); } /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/win32/SDL_win32video.c b/src/video/win32/SDL_win32video.c index f00cc9442..f77a54065 100644 --- a/src/video/win32/SDL_win32video.c +++ b/src/video/win32/SDL_win32video.c @@ -31,10 +31,17 @@ #include "SDL_d3drender.h" #include "SDL_gdirender.h" +#include + /* Initialization/Query functions */ static int WIN_VideoInit(_THIS); static void WIN_VideoQuit(_THIS); +int total_mice = 0; /* total mouse count */ +HANDLE *mice = NULL; /* the handles to the detected mice */ +HCTX *g_hCtx = NULL; /* handles to tablet contexts */ +int tablet = -1; /* we're assuming that there is no tablet */ + /* WIN32 driver bootstrap functions */ static int @@ -140,8 +147,7 @@ WIN_CreateDevice(int devindex) } VideoBootStrap WIN32_bootstrap = { - "win32", "SDL Win32/64 video driver", - WIN_Available, WIN_CreateDevice + "win32", "SDL Win32/64 video driver", WIN_Available, WIN_CreateDevice }; @@ -157,6 +163,7 @@ WIN_VideoInit(_THIS) GDI_AddRenderDriver(_this); #endif + g_hCtx = SDL_malloc(sizeof(HCTX)); WIN_InitKeyboard(_this); WIN_InitMouse(_this); @@ -169,6 +176,7 @@ WIN_VideoQuit(_THIS) WIN_QuitModes(_this); WIN_QuitKeyboard(_this); WIN_QuitMouse(_this); + SDL_free(g_hCtx); } /* vim: set ts=4 sw=4 expandtab: */ diff --git a/src/video/win32/SDL_win32window.c b/src/video/win32/SDL_win32window.c index 07dc1a1f2..239582f8f 100644 --- a/src/video/win32/SDL_win32window.c +++ b/src/video/win32/SDL_win32window.c @@ -19,6 +19,14 @@ Sam Lantinga slouken@libsdl.org */ + +/* we need to define it, so that raw input is included */ + +#if (_WIN32_WINNT < 0x0501) +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif + #include "SDL_config.h" #include "../SDL_sysvideo.h" @@ -29,6 +37,15 @@ /* This is included after SDL_win32video.h, which includes windows.h */ #include "SDL_syswm.h" +#include + +/* we're telling wintab that we want to receive movement, button events and pressure information in packets */ +#define PACKETDATA ( PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_CURSOR) +#define PACKETMODE 0 +#include + +extern HCTX *g_hCtx; /* the table of tablet event contexts, each windows has to have it's own tablet context */ +int highestId = 0; /* the highest id of the tablet context */ static int SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created) @@ -132,6 +149,9 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created) int WIN_CreateWindow(_THIS, SDL_Window * window) { + RAWINPUTDEVICE Rid; + AXIS TabX, TabY; + LOGCONTEXT lc; HWND hwnd; HWND top; RECT rect; @@ -180,13 +200,53 @@ WIN_CreateWindow(_THIS, SDL_Window * window) hwnd = CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, NULL, NULL, SDL_Instance, NULL); - WIN_PumpEvents(_this); - if (!hwnd) { WIN_SetError("Couldn't create window"); return -1; } + /* we're configuring the tablet data. See Wintab reference for more info */ + if (WTInfo(WTI_DEFSYSCTX, 0, &lc) != 0) { + lc.lcPktData = PACKETDATA; + lc.lcPktMode = PACKETMODE; + lc.lcOptions |= CXO_MESSAGES; + lc.lcOptions |= CXO_SYSTEM; + lc.lcMoveMask = PACKETDATA; + lc.lcBtnDnMask = lc.lcBtnUpMask = PACKETDATA; + WTInfo(WTI_DEVICES, DVC_X, &TabX); + WTInfo(WTI_DEVICES, DVC_Y, &TabY); + lc.lcInOrgX = 0; + lc.lcInOrgY = 0; + lc.lcInExtX = TabX.axMax; + lc.lcInExtY = TabY.axMax; + lc.lcOutOrgX = 0; + lc.lcOutOrgY = 0; + lc.lcOutExtX = GetSystemMetrics(SM_CXSCREEN); + lc.lcOutExtY = -GetSystemMetrics(SM_CYSCREEN); + if (window->id > highestId) { + HCTX *tmp_hctx; + highestId = window->id; + tmp_hctx = + (HCTX *) SDL_realloc(g_hCtx, (highestId + 1) * sizeof(HCTX)); + if (!tmp_hctx) { + SDL_OutOfMemory(); + DestroyWindow(hwnd); + return -1; + } + g_hCtx = tmp_hctx; + } + g_hCtx[window->id] = WTOpen(hwnd, &lc, TRUE); + } + + /* we're telling the window, we want it to report raw input events from mice */ + Rid.usUsagePage = 0x01; + Rid.usUsage = 0x02; + Rid.dwFlags = RIDEV_INPUTSINK; + Rid.hwndTarget = hwnd; + RegisterRawInputDevices(&Rid, 1, sizeof(Rid)); + + WIN_PumpEvents(_this); + if (SetupWindowData(_this, window, hwnd, SDL_TRUE) < 0) { DestroyWindow(hwnd); return -1; @@ -389,6 +449,7 @@ WIN_DestroyWindow(_THIS, SDL_Window * window) #endif ReleaseDC(data->hwnd, data->hdc); if (data->created) { + WTClose(g_hCtx[window->id]); DestroyWindow(data->hwnd); } SDL_free(data); diff --git a/src/video/x11/SDL_x11dyn.h b/src/video/x11/SDL_x11dyn.h index fc99073d0..4078a0a0a 100644 --- a/src/video/x11/SDL_x11dyn.h +++ b/src/video/x11/SDL_x11dyn.h @@ -29,7 +29,7 @@ #include #include #include - +//#include #include "../Xext/extensions/Xext.h" #include "../Xext/extensions/extutil.h" diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 382c9373d..4c0478184 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -29,6 +29,12 @@ #include "SDL_x11video.h" #include "../../events/SDL_events_c.h" +extern int motion; /* the motion event id defined by an XInput function */ +extern int button_pressed; /* the button_pressed event id defined by an XInput function */ +extern int button_released; /* the button_released event id defined by an XInput function */ +extern int proximity_in; /* the proximity in event defined by an XInput function */ +extern int proximity_out; /* the proximity out event defined by an XInput function */ + static void X11_DispatchEvent(_THIS) { @@ -91,9 +97,10 @@ X11_DispatchEvent(_THIS) #endif if ((xevent.xcrossing.mode != NotifyGrab) && (xevent.xcrossing.mode != NotifyUngrab)) { - SDL_SetMouseFocus(videodata->mouse, data->windowID); - SDL_SendMouseMotion(videodata->mouse, 0, xevent.xcrossing.x, - xevent.xcrossing.y); + XDeviceMotionEvent *move = (XDeviceMotionEvent *) & xevent; + SDL_SetMouseFocus(move->deviceid, data->windowID); + SDL_SendMouseMotion(move->deviceid, 0, move->x, + move->y, move->axis_data[2]); } } break; @@ -111,9 +118,8 @@ X11_DispatchEvent(_THIS) if ((xevent.xcrossing.mode != NotifyGrab) && (xevent.xcrossing.mode != NotifyUngrab) && (xevent.xcrossing.detail != NotifyInferior)) { - SDL_SendMouseMotion(videodata->mouse, 0, - xevent.xcrossing.x, xevent.xcrossing.y); - SDL_SetMouseFocus(videodata->mouse, 0); + XDeviceMotionEvent *move = (XDeviceMotionEvent *) & xevent; + SDL_SetMouseFocus(move->deviceid, 0); } } break; @@ -166,30 +172,6 @@ X11_DispatchEvent(_THIS) } break; - /* Mouse motion? */ - case MotionNotify:{ -#ifdef DEBUG_MOTION - printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y); -#endif - SDL_SendMouseMotion(videodata->mouse, 0, xevent.xmotion.x, - xevent.xmotion.y); - } - break; - - /* Mouse button press? */ - case ButtonPress:{ - SDL_SendMouseButton(videodata->mouse, SDL_PRESSED, - xevent.xbutton.button); - } - break; - - /* Mouse button release? */ - case ButtonRelease:{ - SDL_SendMouseButton(videodata->mouse, SDL_RELEASED, - xevent.xbutton.button); - } - break; - /* Key press? */ case KeyPress:{ KeyCode keycode = xevent.xkey.keycode; @@ -301,8 +283,44 @@ X11_DispatchEvent(_THIS) break; default:{ + if (xevent.type == motion) { /* MotionNotify */ +#ifdef DEBUG_MOTION + printf("X11 motion: %d,%d\n", xevent.xmotion.x, + xevent.xmotion.y); +#endif + XWindowAttributes attrib; + XGetWindowAttributes(videodata->display, + ((XAnyEvent *) & xevent)->window, + &attrib); + SDL_UpdateCoordinates(attrib.width, attrib.height); + XDeviceMotionEvent *move = (XDeviceMotionEvent *) & xevent; + SDL_SendMouseMotion(move->deviceid, 0, move->x, + move->y, move->axis_data[2]); + } else if (xevent.type == button_pressed) { /* ButtonPress */ + XDeviceButtonPressedEvent *pressed = + (XDeviceButtonPressedEvent *) & xevent; + SDL_SendMouseButton(pressed->deviceid, SDL_PRESSED, + pressed->button); + } else if (xevent.type == button_released) { /* ButtonRelease */ + XDeviceButtonReleasedEvent *released = + (XDeviceButtonReleasedEvent *) & xevent; + SDL_SendMouseButton(released->deviceid, SDL_RELEASED, + released->button); + } else if (xevent.type == proximity_in) { + XProximityNotifyEvent *proximity = + (XProximityNotifyEvent *) & xevent; + SDL_SendProximity(proximity->deviceid, proximity->x, + proximity->y, SDL_PROXIMITYIN); + } else if (xevent.type == proximity_out) { + XProximityNotifyEvent *proximity = + (XProximityNotifyEvent *) & xevent; + SDL_SendProximity(proximity->deviceid, proximity->x, + proximity->y, SDL_PROXIMITYOUT); + } #ifdef DEBUG_XEVENTS - printf("Unhandled event %d\n", xevent.type); + else { + printf("Unhandled event %d\n", xevent.type); + } #endif } break; diff --git a/src/video/x11/SDL_x11mouse.c b/src/video/x11/SDL_x11mouse.c index e5ad6c969..0eac1b30f 100644 --- a/src/video/x11/SDL_x11mouse.c +++ b/src/video/x11/SDL_x11mouse.c @@ -28,11 +28,70 @@ void X11_InitMouse(_THIS) { + extern XDevice **SDL_XDevices; + XDevice **newDevices; + int i, j, index = 0, numOfDevices; + extern int SDL_NumOfXDevices; + XDeviceInfo *DevList; + XAnyClassPtr deviceClass; SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - SDL_Mouse mouse; - SDL_zero(mouse); - data->mouse = SDL_AddMouse(&mouse, -1); + /* we're getting the list of input devices */ + DevList = XListInputDevices(data->display, &numOfDevices); + SDL_XDevices = (XDevice **) SDL_malloc(sizeof(XDevice)); + + /* we're aquiring valuators:mices, tablets, etc. */ + for (i = 0; i < numOfDevices; ++i) { + /* if it's the core pointer or core keyborard we don't want it */ + if ((DevList[i].use != IsXPointer && DevList[i].use != IsXKeyboard)) { + /* we have to check all of the device classes */ + deviceClass = DevList[i].inputclassinfo; + for (j = 0; j < DevList[i].num_classes; ++j) { + if (deviceClass->class == ValuatorClass) { /* bingo ;) */ + XValuatorInfo *valInfo; + SDL_Mouse mouse; + + newDevices = + (XDevice **) SDL_realloc(SDL_XDevices, + (index + + 1) * sizeof(*newDevices)); + if (!newDevices) { + SDL_OutOfMemory(); + return; + } + SDL_XDevices = newDevices; + SDL_XDevices[index] = + XOpenDevice(data->display, DevList[i].id); + SDL_zero(mouse); + + /* the id of the device differs from its index + * so we're assigning the index of a device to it's id */ + SDL_SetMouseIndexId(DevList[i].id, index); + /* lets get the device parameters */ + valInfo = (XValuatorInfo *) deviceClass; + /* if the device reports pressure, lets check it parameteres */ + if (valInfo->num_axes > 2) { + data->mouse = + SDL_AddMouse(&mouse, index++, DevList[i].name, + valInfo->axes[2].max_value, + valInfo->axes[2].min_value, 1); + } else { + data->mouse = + SDL_AddMouse(&mouse, index++, DevList[i].name, 0, + 0, 1); + } + break; + } + /* if it's not class we're interested in, lets go further */ + deviceClass = + (XAnyClassPtr) ((char *) deviceClass + + deviceClass->length); + } + } + } + XFreeDeviceList(DevList); + + SDL_NumOfXDevices = index; } void @@ -40,7 +99,8 @@ X11_QuitMouse(_THIS) { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - SDL_DelMouse(data->mouse); + /* let's delete all of the mice */ + SDL_MouseQuit(); } /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index be881ab18..6004e6cc6 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -144,6 +144,11 @@ SDL_X11_SYM(SDL_X11_XESetWireToEventRetType,XESetWireToEvent,(Display* a,int b,S SDL_X11_SYM(SDL_X11_XESetEventToWireRetType,XESetEventToWire,(Display* a,int b,SDL_X11_XESetEventToWireRetType c),(a,b,c),return) SDL_X11_SYM(XExtensionErrorHandler,XSetExtensionErrorHandler,(XExtensionErrorHandler a),(a),return) +/*SDL_X11_SYM(XDeviceInfo* , XListInputDevices, (Display* a, int* b), (a,b),return) +SDL_X11_SYM(void, XFreeDeviceList, (XDeviceInfo* a), (a),) +SDL_X11_SYM(int, XSelectExtensionEvent,(Display* a, Window b, XEventClass* c, int d),(a,b,c,d),return) +SDL_X11_SYM(XDevice* ,XOpenDevice,(Display* a, XID b), (a,b),return)*/ + #if NeedWidePrototypes SDL_X11_SYM(KeySym,XKeycodeToKeysym,(Display* a,unsigned int b,int c),(a,b,c),return) #else diff --git a/src/video/x11/SDL_x11video.c b/src/video/x11/SDL_x11video.c index bec97f1a8..020b49aa8 100644 --- a/src/video/x11/SDL_x11video.c +++ b/src/video/x11/SDL_x11video.c @@ -27,8 +27,14 @@ #include "../SDL_pixels_c.h" #include "SDL_x11video.h" -//#include "SDL_d3drender.h" -//#include "SDL_gdirender.h" + +XDevice **SDL_XDevices; +int SDL_NumOfXDevices; +XEventClass SDL_XEvents[256]; +int SDL_NumOfXEvents; + +int motion, button_pressed, button_released; /* the definitions of the mice events */ +int proximity_in, proximity_out; /* Initialization/Query functions */ static int X11_VideoInit(_THIS); @@ -97,7 +103,6 @@ static void X11_DeleteDevice(SDL_VideoDevice * device) { SDL_VideoData *data = (SDL_VideoData *) device->driverdata; - if (data->display) { XCloseDisplay(data->display); } @@ -212,6 +217,8 @@ VideoBootStrap X11_bootstrap = { int X11_VideoInit(_THIS) { + int i, index = 0, event_code; + XEventClass xEvent; SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; /* Get the window class name, usually the name of the application */ @@ -241,6 +248,42 @@ X11_VideoInit(_THIS) } X11_InitMouse(_this); + /* we're generating the table of events that should be recognized */ + for (i = 0; i < SDL_NumOfXDevices; ++i) { + /* button events */ + DeviceButtonPress(SDL_XDevices[i], event_code, xEvent); + if (xEvent) { + SDL_XEvents[index++] = xEvent; + button_pressed = event_code; + } + DeviceButtonRelease(SDL_XDevices[i], event_code, xEvent); + if (xEvent) { + SDL_XEvents[index++] = xEvent; + button_released = event_code; + } + + /* proximity events */ + ProximityIn(SDL_XDevices[i], event_code, xEvent); + if (xEvent) { + SDL_XEvents[index++] = xEvent; + proximity_in = event_code; + } + ProximityOut(SDL_XDevices[i], event_code, xEvent); + if (xEvent) { + SDL_XEvents[index++] = xEvent; + proximity_out = event_code; + } + + /* motion events */ + DeviceMotionNotify(SDL_XDevices[i], event_code, xEvent); + if (xEvent) { + SDL_XEvents[index++] = xEvent; + motion = event_code; + } + + } + SDL_NumOfXEvents = index; + return 0; } @@ -263,6 +306,7 @@ X11_VideoQuit(_THIS) X11_QuitModes(_this); X11_QuitKeyboard(_this); X11_QuitMouse(_this); + free(SDL_XDevices); } /* vim: set ts=4 sw=4 expandtab: */ diff --git a/src/video/x11/SDL_x11video.h b/src/video/x11/SDL_x11video.h index bbc6a1205..6526f707c 100644 --- a/src/video/x11/SDL_x11video.h +++ b/src/video/x11/SDL_x11video.h @@ -29,6 +29,7 @@ #include #include #include +#include #if SDL_VIDEO_DRIVER_X11_XINERAMA #include "../Xext/extensions/Xinerama.h" @@ -68,7 +69,7 @@ typedef struct SDL_VideoData int numwindows; SDL_WindowData **windowlist; int windowlistlength; - int mouse; + int *mouse; int keyboard; Atom WM_DELETE_WINDOW; SDL_scancode key_layout[256]; diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 9de82581c..c5f747fd1 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -153,6 +153,8 @@ X11_CreateWindow(_THIS, SDL_Window * window) XSizeHints *sizehints; XWMHints *wmhints; XClassHint *classhints; + extern XEventClass SDL_XEvents[]; + extern int SDL_NumOfXEvents; #if SDL_VIDEO_DRIVER_X11_XINERAMA /* FIXME @@ -481,6 +483,7 @@ X11_CreateWindow(_THIS, SDL_Window * window) Uint32 fevent = 0; pXGetICValues(((SDL_WindowData *) window->driverdata)->ic, XNFilterEvents, &fevent, NULL); + XMapWindow(data->display, w); XSelectInput(data->display, w, (FocusChangeMask | EnterWindowMask | LeaveWindowMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | @@ -489,6 +492,7 @@ X11_CreateWindow(_THIS, SDL_Window * window) KeymapStateMask | fevent)); } #else + XMapWindow(data->display, w); XSelectInput(data->display, w, (FocusChangeMask | EnterWindowMask | LeaveWindowMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | @@ -497,6 +501,9 @@ X11_CreateWindow(_THIS, SDL_Window * window) KeymapStateMask)); #endif + /* we're informing the display what extension events we want to receive from it */ + XSelectExtensionEvent(data->display, w, SDL_XEvents, SDL_NumOfXEvents); + return 0; } diff --git a/test/testalpha.c b/test/testalpha.c index 5c6b20674..1dedde552 100644 --- a/test/testalpha.c +++ b/test/testalpha.c @@ -273,7 +273,7 @@ MoveSprite(SDL_Surface * screen, SDL_Surface * light) if (light != NULL) { int x, y; - SDL_GetMouseState(&x, &y); + SDL_GetMouseState(0, &x, &y); FlashLight(screen, light, x, y); } diff --git a/test/testgl.c b/test/testgl.c index 26e736d85..dc1558ae7 100644 --- a/test/testgl.c +++ b/test/testgl.c @@ -270,7 +270,7 @@ DrawLogoCursor(void) } /* Move the image around */ - SDL_GetMouseState(&x, &y); + SDL_GetMouseState(0, &x, &y); x -= w / 2; y -= h / 2;