diff -r 5c42e467f6cd include/SDL_joystick.h --- a/include/SDL_joystick.h Fri Sep 19 12:09:51 2014 -0400 +++ b/include/SDL_joystick.h Sat Sep 27 11:37:32 2014 -0400 @@ -42,6 +42,8 @@ #include "SDL_stdinc.h" #include "SDL_error.h" +#include "SDL_touch.h" + #include "begin_code.h" /* Set up for C function definitions, even when using C++ */ #ifdef __cplusplus @@ -237,6 +239,13 @@ int button); /** + * Get the ID of the touch device on the joystick. + * + * \return the ID of the associated touch device or -1 if none exists. + */ +extern DECLSPEC SDL_TouchID SDLCALL SDL_JoystickGetTouchDevice(SDL_Joystick * joystick); + +/** * Close a joystick previously opened with SDL_JoystickOpen(). */ extern DECLSPEC void SDLCALL SDL_JoystickClose(SDL_Joystick * joystick); diff -r 5c42e467f6cd src/dynapi/SDL_dynapi_overrides.h --- a/src/dynapi/SDL_dynapi_overrides.h Fri Sep 19 12:09:51 2014 -0400 +++ b/src/dynapi/SDL_dynapi_overrides.h Sat Sep 27 11:37:32 2014 -0400 @@ -591,3 +591,4 @@ #define SDL_QueueAudio SDL_QueueAudio_REAL #define SDL_GetQueuedAudioSize SDL_GetQueuedAudioSize_REAL #define SDL_ClearQueuedAudio SDL_ClearQueuedAudio_REAL +#define SDL_JoystickGetTouchDevice SDL_JoystickGetTouchDevice_REAL \ No newline at end of file diff -r 5c42e467f6cd src/dynapi/SDL_dynapi_procs.h --- a/src/dynapi/SDL_dynapi_procs.h Fri Sep 19 12:09:51 2014 -0400 +++ b/src/dynapi/SDL_dynapi_procs.h Sat Sep 27 11:37:32 2014 -0400 @@ -623,3 +623,4 @@ SDL_DYNAPI_PROC(int,SDL_QueueAudio,(SDL_AudioDeviceID a, const void *b, Uint32 c),(a,b,c),return) SDL_DYNAPI_PROC(Uint32,SDL_GetQueuedAudioSize,(SDL_AudioDeviceID a),(a),return) SDL_DYNAPI_PROC(void,SDL_ClearQueuedAudio,(SDL_AudioDeviceID a),(a),) +SDL_DYNAPI_PROC(SDL_TouchID,SDL_JoystickGetTouchDevice,(SDL_Joystick *a),(a),return) \ No newline at end of file diff -r 5c42e467f6cd src/joystick/SDL_joystick.c --- a/src/joystick/SDL_joystick.c Fri Sep 19 12:09:51 2014 -0400 +++ b/src/joystick/SDL_joystick.c Sat Sep 27 11:37:32 2014 -0400 @@ -130,6 +130,7 @@ } SDL_memset(joystick, 0, (sizeof *joystick)); + joystick->touchId = -1; if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) { SDL_free(joystick); return NULL; @@ -349,6 +350,16 @@ return (state); } +SDL_TouchID +SDL_JoystickGetTouchDevice(SDL_Joystick * joystick) +{ + if (!SDL_PrivateJoystickValid(joystick)) { + return (0); + } + + return joystick->touchId; +} + /* * Return if the joystick in question is currently attached to the system, * \return SDL_FALSE if not plugged in, SDL_TRUE if still present. diff -r 5c42e467f6cd src/joystick/SDL_sysjoystick.h --- a/src/joystick/SDL_sysjoystick.h Fri Sep 19 12:09:51 2014 -0400 +++ b/src/joystick/SDL_sysjoystick.h Sat Sep 27 11:37:32 2014 -0400 @@ -48,6 +48,8 @@ int nbuttons; /* Number of buttons on the joystick */ Uint8 *buttons; /* Current button states */ + + SDL_TouchID touchId; /* ID of the touchpad on the joystick */ struct joystick_hwdata *hwdata; /* Driver dependent information */ diff -r 5c42e467f6cd src/joystick/linux/SDL_sysjoystick.c --- a/src/joystick/linux/SDL_sysjoystick.c Fri Sep 19 12:09:51 2014 -0400 +++ b/src/joystick/linux/SDL_sysjoystick.c Sat Sep 27 11:37:32 2014 -0400 @@ -459,6 +459,39 @@ return (0); } +static int +allocate_touchdata(SDL_Joystick * joystick) +{ + SDL_TouchID new_id = 0; + int i; + + joystick->hwdata->touch_slot = + (struct hwdata_touch *) SDL_malloc(joystick->hwdata->num_touch_slots * + sizeof(struct hwdata_touch)); + if (joystick->hwdata->touch_slot == NULL) { + return (-1); + } + for (i = 0; i < joystick->hwdata->num_touch_slots; ++i) { + joystick->hwdata->touch_slot[i].x = 0; + joystick->hwdata->touch_slot[i].y = 0; + joystick->hwdata->touch_slot[i].pressure = 0; + joystick->hwdata->touch_slot[i].down = SDL_FALSE; + joystick->hwdata->touch_slot[i].down_event = SDL_FALSE; + joystick->hwdata->touch_slot[i].updated = SDL_FALSE; + } + + /* Find an unused touchpad ID */ + while(SDL_GetTouch(new_id)) + new_id++; + + if(SDL_AddTouch(new_id, "") < 0) + return -1; + + joystick->touchId = new_id; + + return (0); +} + static void ConfigJoystick(SDL_Joystick * joystick, int fd) { @@ -548,6 +581,49 @@ if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) { ++joystick->nballs; } + if (test_bit(ABS_MT_POSITION_X, absbit) || test_bit(ABS_MT_POSITION_Y, absbit)) { + struct input_absinfo absinfo; + + if (test_bit(ABS_MT_SLOT, absbit) && + ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &absinfo) >= 0) { + joystick->hwdata->num_touch_slots = absinfo.maximum + 1; + } else { + joystick->hwdata->num_touch_slots = 1; + } + + if (test_bit(ABS_MT_POSITION_X, absbit) && + ioctl(fd, EVIOCGABS(ABS_MT_POSITION_X), &absinfo) >= 0) { + if (absinfo.maximum > absinfo.minimum) { + joystick->hwdata->tx_offset = -absinfo.minimum; + joystick->hwdata->tx_scaler = 1.0f / (float)(absinfo.maximum - absinfo.minimum); + } else { + joystick->hwdata->tx_offset = 0; + joystick->hwdata->tx_scaler = 1.0f; + } + } + + if (test_bit(ABS_MT_POSITION_Y, absbit) && + ioctl(fd, EVIOCGABS(ABS_MT_POSITION_Y), &absinfo) >= 0) { + if (absinfo.maximum > absinfo.minimum) { + joystick->hwdata->ty_offset = -absinfo.minimum; + joystick->hwdata->ty_scaler = 1.0f / (float)(absinfo.maximum - absinfo.minimum); + } else { + joystick->hwdata->ty_offset = 0; + joystick->hwdata->ty_scaler = 1.0f; + } + } + + if (test_bit(ABS_MT_PRESSURE, absbit) && + ioctl(fd, EVIOCGABS(ABS_MT_PRESSURE), &absinfo) >= 0) { + if (absinfo.maximum > absinfo.minimum) { + joystick->hwdata->pressure_offset = -absinfo.minimum; + joystick->hwdata->pressure_scaler = 1.0f / (float)(absinfo.maximum - absinfo.minimum); + } else { + joystick->hwdata->pressure_offset = 0; + joystick->hwdata->pressure_scaler = 1.0f; + } + } + } /* Allocate data to keep track of these thingamajigs */ if (joystick->nhats > 0) { @@ -560,6 +636,11 @@ joystick->nballs = 0; } } + if (joystick->hwdata->num_touch_slots > 0) { + if (allocate_touchdata(joystick) < 0) { + joystick->hwdata->num_touch_slots = 0; + } + } } } @@ -658,6 +739,85 @@ stick->hwdata->balls[ball].axis[axis] += value; } +static SDL_INLINE void +HandleTouch(SDL_Joystick * stick, int axis, int value) +{ + int slot = stick->hwdata->active_touch_slot; + + /* Is the slot valid? */ + if (slot < 0 || slot >= stick->hwdata->num_touch_slots) + return; + + switch(axis) + { + case ABS_MT_SLOT: + stick->hwdata->active_touch_slot = value; + break; + case ABS_MT_TRACKING_ID: + if (value != -1) { + /* + * A new touch was detected. + * Set the pressure to 1 for devices that don't report it. + * Those that do should send ABS_MT_PRESSURE with the real + * value in a forthcoming event. + */ + stick->hwdata->touch_slot[slot].pressure = 1; + stick->hwdata->touch_slot[slot].down = SDL_TRUE; + } else { + /* A finger was lifted. */ + stick->hwdata->touch_slot[slot].pressure = 0; + stick->hwdata->touch_slot[slot].down = SDL_FALSE; + } + + stick->hwdata->touch_slot[slot].down_event = SDL_TRUE; + stick->hwdata->touch_slot[slot].updated = SDL_TRUE; + stick->hwdata->pending_touch_events = SDL_TRUE; + break; + case ABS_MT_POSITION_X: + stick->hwdata->touch_slot[slot].x = value; + stick->hwdata->touch_slot[slot].updated = SDL_TRUE; + stick->hwdata->pending_touch_events = SDL_TRUE; + break; + case ABS_MT_POSITION_Y: + stick->hwdata->touch_slot[slot].y = value; + stick->hwdata->touch_slot[slot].updated = SDL_TRUE; + stick->hwdata->pending_touch_events = SDL_TRUE; + break; + case ABS_MT_PRESSURE: + stick->hwdata->touch_slot[slot].pressure = value; + stick->hwdata->touch_slot[slot].updated = SDL_TRUE; + stick->hwdata->pending_touch_events = SDL_TRUE; + break; + } +} + +static SDL_INLINE void +DispatchTouch(SDL_Joystick * stick) +{ + int i; + + if (stick->hwdata->pending_touch_events) { + for (i = 0; i < stick->hwdata->num_touch_slots; i++) { + if (stick->hwdata->touch_slot[i].updated) { + float x = (float)(stick->hwdata->touch_slot[i].x + stick->hwdata->tx_offset) * stick->hwdata->tx_scaler; + float y = (float)(stick->hwdata->touch_slot[i].y + stick->hwdata->ty_offset) * stick->hwdata->ty_scaler; + float p = (float)(stick->hwdata->touch_slot[i].pressure + stick->hwdata->pressure_offset) * stick->hwdata->pressure_scaler; + + /* If the up/down state didn't change it's just a motion event */ + if (!stick->hwdata->touch_slot[i].down_event) { + SDL_SendTouchMotion(stick->touchId, i, x, y, p); + } else { + SDL_SendTouch(stick->touchId, i, stick->hwdata->touch_slot[i].down, x, y, p); + stick->hwdata->touch_slot[i].down_event = SDL_FALSE; + } + + stick->hwdata->touch_slot[i].updated = SDL_FALSE; + } + } + + stick->hwdata->pending_touch_events = SDL_FALSE; + } +} static SDL_INLINE int AxisCorrect(SDL_Joystick * joystick, int which, int value) @@ -753,6 +913,7 @@ break; case EV_ABS: if (code >= ABS_MISC) { + HandleTouch(joystick, code, events[i].value); break; } @@ -790,6 +951,10 @@ break; case EV_SYN: switch (code) { + case SYN_REPORT: + /* Dispatch pending touch events */ + DispatchTouch(joystick); + break; case SYN_DROPPED : #ifdef DEBUG_INPUT_EVENTS printf("Event SYN_DROPPED detected\n"); @@ -836,8 +1001,12 @@ if (joystick->hwdata->item) { joystick->hwdata->item->hwdata = NULL; } + + SDL_DelTouch(joystick->touchId); + SDL_free(joystick->hwdata->hats); SDL_free(joystick->hwdata->balls); + SDL_free(joystick->hwdata->touch_slot); SDL_free(joystick->hwdata->fname); SDL_free(joystick->hwdata); joystick->hwdata = NULL; diff -r 5c42e467f6cd src/joystick/linux/SDL_sysjoystick_c.h --- a/src/joystick/linux/SDL_sysjoystick_c.h Fri Sep 19 12:09:51 2014 -0400 +++ b/src/joystick/linux/SDL_sysjoystick_c.h Sat Sep 27 11:37:32 2014 -0400 @@ -50,6 +50,29 @@ int used; int coef[3]; } abs_correct[ABS_MAX]; + + /* Touchpad tracking data */ + int num_touch_slots; + int active_touch_slot; + int tx_offset; + int ty_offset; + int pressure_offset; + float tx_scaler; + float ty_scaler; + float pressure_scaler; + + /* Touch events will be dispatched when SYN_REPORT events are received */ + SDL_bool pending_touch_events; + + struct hwdata_touch + { + int x; + int y; + int pressure; + SDL_bool down; + SDL_bool down_event; + SDL_bool updated; + } *touch_slot; int fresh; }; diff -r 5c42e467f6cd test/testjoystick.c --- a/test/testjoystick.c Fri Sep 19 12:09:51 2014 -0400 +++ b/test/testjoystick.c Sat Sep 27 11:37:32 2014 -0400 @@ -45,6 +45,7 @@ SDL_bool retval = SDL_FALSE; SDL_bool done = SDL_FALSE; SDL_Event event; + SDL_TouchID touch_id; int i; /* Create a window to display joystick axis position */ @@ -75,6 +76,11 @@ SDL_Log("Joystick has %d axes, %d hats, %d balls, and %d buttons\n", SDL_JoystickNumAxes(joystick), SDL_JoystickNumHats(joystick), SDL_JoystickNumBalls(joystick), SDL_JoystickNumButtons(joystick)); + + touch_id = SDL_JoystickGetTouchDevice(joystick); + + if (touch_id >= 0) + SDL_Log("Joystick touchpad ID = %d\n", touch_id); /* Loop, getting joystick events! */ while (!done) { @@ -109,6 +115,23 @@ event.jball.which, event.jball.ball, event.jball.xrel, event.jball.yrel); break; + case SDL_FINGERUP: + case SDL_FINGERDOWN: + if (event.tfinger.touchId == touch_id) { + SDL_Log("Joystick %d touch %s %d: (%f,%f)\n", + event.tfinger.touchId, + event.type == SDL_FINGERDOWN ? "down" : "up", + event.tfinger.fingerId, event.tfinger.x, event.tfinger.y); + } + break; + case SDL_FINGERMOTION: + if (event.tfinger.touchId == touch_id) { + SDL_Log("Joystick %d touch motion %d: (%f,%f) (%f, %f)\n", + event.tfinger.touchId, + event.tfinger.fingerId, event.tfinger.x, event.tfinger.y, + event.tfinger.dx, event.tfinger.dy); + } + break; case SDL_JOYBUTTONDOWN: SDL_Log("Joystick %d button %d down\n", event.jbutton.which, event.jbutton.button); @@ -123,7 +146,6 @@ break; } /* Fall through to signal quit */ - case SDL_FINGERDOWN: case SDL_MOUSEBUTTONDOWN: case SDL_QUIT: done = SDL_TRUE; @@ -190,7 +212,23 @@ DrawRect(screen, x, y, 8, 8); } - + + if (touch_id >= 0) { + SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0x00, SDL_ALPHA_OPAQUE); + for (i = 0; i < SDL_GetNumTouchFingers(touch_id); ++i) { + SDL_bool down; + float tx, ty; + SDL_Finger *f; + f = SDL_GetTouchFinger(touch_id, i); + + /* Derive the new position */ + int x = (int)(f->x * SCREEN_WIDTH); + int y = (int)(f->y * SCREEN_HEIGHT); + + DrawRect(screen, x, y, 8, 8); + } + } + SDL_RenderPresent(screen); if (SDL_JoystickGetAttached( joystick ) == 0) { @@ -237,6 +275,7 @@ SDL_Log(" balls: %d\n", SDL_JoystickNumBalls(joystick)); SDL_Log(" hats: %d\n", SDL_JoystickNumHats(joystick)); SDL_Log(" buttons: %d\n", SDL_JoystickNumButtons(joystick)); + SDL_Log(" touchID: %d\n", SDL_JoystickGetTouchDevice(joystick)); SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick)); SDL_Log(" guid: %s\n", guid); SDL_JoystickClose(joystick);