diff -r 5c42e467f6cd include/SDL_events.h --- a/include/SDL_events.h Fri Sep 19 12:09:51 2014 -0400 +++ b/include/SDL_events.h Sat Sep 27 11:22:53 2014 -0400 @@ -109,6 +109,9 @@ SDL_JOYBUTTONUP, /**< Joystick button released */ SDL_JOYDEVICEADDED, /**< A new joystick has been inserted into the system */ SDL_JOYDEVICEREMOVED, /**< An opened joystick has been removed */ + SDL_JOYTOUCHDOWN, /**< Joystick touchpad finger down */ + SDL_JOYTOUCHUP, /**< Joystick touchpad finger up */ + SDL_JOYTOUCHMOTION, /**< Joystick touchpad finger motion */ /* Game controller events */ SDL_CONTROLLERAXISMOTION = 0x650, /**< Game controller axis motion */ @@ -329,6 +332,22 @@ } SDL_JoyButtonEvent; /** + * \brief Joystick touch event structure (event.jtouch.*) + */ +typedef struct SDL_JoyTouchEvent +{ + Uint32 type; /**< ::SDL_JOYTOUCHMOTION or ::SDL_JOYTOUCHDOWN or ::SDL_JOYTOUCHUP */ + Uint32 timestamp; + SDL_JoystickID which; /**< The joystick instance id */ + int fingerIndex; + float x; /**< Normalized in the range 0...1 */ + float y; /**< Normalized in the range 0...1 */ + float dx; /**< Normalized in the range 0...1 */ + float dy; /**< Normalized in the range 0...1 */ + float pressure; /**< Normalized in the range 0...1 */ +} SDL_JoyTouchEvent; + +/** * \brief Joystick device event structure (event.jdevice.*) */ typedef struct SDL_JoyDeviceEvent @@ -511,6 +530,7 @@ SDL_JoyBallEvent jball; /**< Joystick ball event data */ SDL_JoyHatEvent jhat; /**< Joystick hat event data */ SDL_JoyButtonEvent jbutton; /**< Joystick button event data */ + SDL_JoyTouchEvent jtouch; /**< Joystick touch event data */ SDL_JoyDeviceEvent jdevice; /**< Joystick device change event data */ SDL_ControllerAxisEvent caxis; /**< Game Controller axis event data */ SDL_ControllerButtonEvent cbutton; /**< Game Controller button event data */ 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:22:53 2014 -0400 @@ -156,6 +156,11 @@ extern DECLSPEC int SDLCALL SDL_JoystickNumButtons(SDL_Joystick * joystick); /** + * Get the number of supported fingers on a joystick trackpad. + */ +extern DECLSPEC int SDLCALL SDL_JoystickNumTouchFingers(SDL_Joystick * joystick); + +/** * Update the current state of the open joysticks. * * This is called automatically by the event loop if any joystick @@ -236,6 +241,19 @@ extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick, int button); +/* + * Get the current state of a finger on the touchpad. + * + * \return 0, or -1 if you passed it invalid parameters. + * + * The finger indices start at index 0. + */ +extern DECLSPEC int SDLCALL SDL_JoystickGetTouchFinger(SDL_Joystick * joystick, + int finger, + SDL_bool *down, + float *x, float *y, + float *pressure); + /** * Close a joystick previously opened with SDL_JoystickOpen(). */ 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:22:53 2014 -0400 @@ -591,3 +591,5 @@ #define SDL_QueueAudio SDL_QueueAudio_REAL #define SDL_GetQueuedAudioSize SDL_GetQueuedAudioSize_REAL #define SDL_ClearQueuedAudio SDL_ClearQueuedAudio_REAL +#define SDL_JoystickNumTouchFingers SDL_JoystickNumTouchFingers_REAL +#define SDL_JoystickGetTouchFinger SDL_JoystickGetTouchFinger_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:22:53 2014 -0400 @@ -623,3 +623,5 @@ 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(int,SDL_JoystickNumTouchFingers,(SDL_Joystick *a),(a),return) +SDL_DYNAPI_PROC(int,SDL_JoystickGetTouchFinger,(SDL_Joystick *a, int b, SDL_bool *c, float *d, float *e, float *f),(a,b,c,d,e,f),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:22:53 2014 -0400 @@ -157,6 +157,10 @@ joystick->buttons = (Uint8 *) SDL_malloc (joystick->nbuttons * sizeof(Uint8)); } + if (joystick->ntouchpoints > 0) { + joystick->touch = (struct touchdata *) SDL_malloc + (joystick->ntouchpoints * sizeof(*joystick->touch)); + } if (((joystick->naxes > 0) && !joystick->axes) || ((joystick->nhats > 0) && !joystick->hats) || ((joystick->nballs > 0) && !joystick->balls) @@ -261,6 +265,15 @@ return (joystick->nbuttons); } +int +SDL_JoystickNumTouchFingers(SDL_Joystick * joystick) +{ + if (!SDL_PrivateJoystickValid(joystick)) { + return (-1); + } + return (joystick->ntouchpoints); +} + /* * Get the current state of an axis control on a joystick */ @@ -350,6 +363,39 @@ } /* + * Get the current state of a multitouch point + */ +int +SDL_JoystickGetTouchFinger(SDL_Joystick * joystick, int touch_id, + SDL_bool *down, float *x, float *y, float *pressure) +{ + int retval; + + if (!SDL_PrivateJoystickValid(joystick)) { + return (-1); + } + + retval = 0; + if (touch_id < joystick->ntouchpoints) { + if (down) { + *down = joystick->touch[touch_id].down; + } + if (x) { + *x = joystick->touch[touch_id].x; + } + if (y) { + *y = joystick->touch[touch_id].y; + } + if (pressure) { + *pressure = joystick->touch[touch_id].pressure; + } + } else { + return SDL_SetError("Joystick only has %d multitouch points", joystick->ntouchpoints); + } + return (retval); +} + +/* * Return if the joystick in question is currently attached to the system, * \return SDL_FALSE if not plugged in, SDL_TRUE if still present. */ @@ -435,6 +481,7 @@ SDL_free(joystick->axes); SDL_free(joystick->hats); SDL_free(joystick->balls); + SDL_free(joystick->touch); SDL_free(joystick->buttons); SDL_free(joystick); } @@ -651,6 +698,100 @@ return (posted); } +int +SDL_PrivateJoystickTouch(SDL_Joystick * joystick, int finger, SDL_bool down, + float x, float y, float pressure) +{ + SDL_Event event; + int posted; + + /* Make sure we're not getting garbage or duplicate events */ + if (finger < 0 || finger >= joystick->ntouchpoints || + down == joystick->touch[finger].down) { + return 0; + } + + /* We ignore events if we don't have keyboard focus. */ + if (SDL_PrivateJoystickShouldIgnoreEvent()) { + return 0; + } + + /* Update internal touch state */ + joystick->touch[finger].x = x; + joystick->touch[finger].y = y; + joystick->touch[finger].pressure = pressure; + joystick->touch[finger].down = down; + + /* Post the event, if desired */ + posted = 0; +#if !SDL_EVENTS_DISABLED + if (down) + event.type = SDL_JOYTOUCHDOWN; + else + event.type = SDL_JOYTOUCHUP; + + if (SDL_GetEventState(event.type) == SDL_ENABLE) { + event.jtouch.which = joystick->instance_id; + event.jtouch.fingerIndex = finger; + event.jtouch.x = x; + event.jtouch.y = y; + event.jtouch.pressure = pressure; + posted = SDL_PushEvent(&event) == 1; + } +#endif /* !SDL_EVENTS_DISABLED */ + return (posted); +} + +int +SDL_PrivateJoystickTouchMotion(SDL_Joystick * joystick, int finger, + float x, float y, float pressure) +{ + int posted; + float dx, dy, dp; + + /* Make sure we're not getting garbage events */ + if (finger < 0 || finger >= joystick->ntouchpoints || + !joystick->touch[finger].down) { + return 0; + } + + /* We ignore events if we don't have keyboard focus. */ + if (SDL_PrivateJoystickShouldIgnoreEvent()) { + return 0; + } + + dx = x - joystick->touch[finger].x; + dy = y - joystick->touch[finger].y; + dp = pressure - joystick->touch[finger].pressure; + + /* Don't send an event if nothing changed */ + if (!dx && !dy && !dp) + return 0; + + /* Update internal touch state */ + joystick->touch[finger].x = x; + joystick->touch[finger].y = y; + joystick->touch[finger].pressure = pressure; + + /* Post the event, if desired */ + posted = 0; +#if !SDL_EVENTS_DISABLED + if (SDL_GetEventState(SDL_JOYTOUCHMOTION) == SDL_ENABLE) { + SDL_Event event; + event.jtouch.type = SDL_JOYTOUCHMOTION; + event.jtouch.which = joystick->instance_id; + event.jtouch.fingerIndex = finger; + event.jtouch.x = x; + event.jtouch.y = y; + event.jtouch.dx = dx; + event.jtouch.dy = dy; + event.jtouch.pressure = pressure; + posted = SDL_PushEvent(&event) == 1; + } +#endif /* !SDL_EVENTS_DISABLED */ + return (posted); +} + void SDL_JoystickUpdate(void) { diff -r 5c42e467f6cd src/joystick/SDL_joystick_c.h --- a/src/joystick/SDL_joystick_c.h Fri Sep 19 12:09:51 2014 -0400 +++ b/src/joystick/SDL_joystick_c.h Sat Sep 27 11:22:53 2014 -0400 @@ -41,6 +41,11 @@ Uint8 hat, Uint8 value); extern int SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state); +extern int SDL_PrivateJoystickTouch(SDL_Joystick * joystick, + int finger, SDL_bool down, + float x, float y, float pressure); +extern int SDL_PrivateJoystickTouchMotion(SDL_Joystick * joystick, + int finger, float x, float y, float pressure); /* Internal sanity checking functions */ extern int SDL_PrivateJoystickValid(SDL_Joystick * joystick); 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:22:53 2014 -0400 @@ -48,6 +48,14 @@ int nbuttons; /* Number of buttons on the joystick */ Uint8 *buttons; /* Current button states */ + + int ntouchpoints; /* Number of multitouch points */ + struct touchdata { + float x; + float y; + float pressure; + SDL_bool down; + } *touch; /* Touchpad state */ 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:22:53 2014 -0400 @@ -459,6 +459,27 @@ return (0); } +static int +allocate_touchdata(SDL_Joystick * joystick) +{ + int i; + + joystick->hwdata->touch_slot = + (struct hwdata_touch *) SDL_malloc(joystick->ntouchpoints * + sizeof(struct hwdata_touch)); + if (joystick->hwdata->touch_slot == NULL) { + return (-1); + } + for (i = 0; i < joystick->ntouchpoints; ++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].updated = SDL_FALSE; + } + return (0); +} + static void ConfigJoystick(SDL_Joystick * joystick, int fd) { @@ -548,6 +569,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->ntouchpoints = absinfo.maximum + 1; + } else { + joystick->ntouchpoints = 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 +624,11 @@ joystick->nballs = 0; } } + if (joystick->ntouchpoints > 0) { + if (allocate_touchdata(joystick) < 0) { + joystick->ntouchpoints = 0; + } + } } } @@ -658,6 +727,82 @@ 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->ntouchpoints) + 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].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->ntouchpoints; 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->touch[i].down == stick->hwdata->touch_slot[i].down) + SDL_PrivateJoystickTouchMotion(stick, i, x, y, p); + else + SDL_PrivateJoystickTouch(stick, i, stick->hwdata->touch_slot[i].down, x, y, p); + + 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 +898,7 @@ break; case EV_ABS: if (code >= ABS_MISC) { + HandleTouch(joystick, code, events[i].value); break; } @@ -790,6 +936,9 @@ break; case EV_SYN: switch (code) { + case SYN_REPORT: + DispatchTouch(joystick); + break; case SYN_DROPPED : #ifdef DEBUG_INPUT_EVENTS printf("Event SYN_DROPPED detected\n"); @@ -838,6 +987,7 @@ } 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:22:53 2014 -0400 @@ -50,6 +50,27 @@ int used; int coef[3]; } abs_correct[ABS_MAX]; + + /* Touchpad tracking data */ + 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 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:22:53 2014 -0400 @@ -109,6 +109,19 @@ event.jball.which, event.jball.ball, event.jball.xrel, event.jball.yrel); break; + case SDL_JOYTOUCHUP: + case SDL_JOYTOUCHDOWN: + SDL_Log("Joystick %d touch %s %d: (%f,%f)\n", + event.jtouch.which, + event.type == SDL_JOYTOUCHDOWN ? "down" : "up", + event.jtouch.fingerIndex, event.jtouch.x, event.jtouch.y); + break; + case SDL_JOYTOUCHMOTION: + SDL_Log("Joystick %d touch motion %d: (%f,%f) (%f, %f)\n", + event.jtouch.which, + event.jtouch.fingerIndex, event.jtouch.x, event.jtouch.y, + event.jtouch.dx, event.jtouch.dy); + break; case SDL_JOYBUTTONDOWN: SDL_Log("Joystick %d button %d down\n", event.jbutton.which, event.jbutton.button); @@ -190,7 +203,24 @@ DrawRect(screen, x, y, 8, 8); } + + for (i = 0; i < SDL_JoystickNumTouchFingers(joystick); ++i) { + SDL_bool down; + float tx, ty; + SDL_JoystickGetTouchFinger(joystick, i, &down, &tx, &ty, NULL); + + /* Derive the new position */ + int x = (int)(tx * SCREEN_WIDTH); + int y = (int)(ty * SCREEN_HEIGHT); + if (down) + SDL_SetRenderDrawColor(screen, 0xFF, 0xA5, 0x00, SDL_ALPHA_OPAQUE); + else + SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0x00, SDL_ALPHA_OPAQUE); + + DrawRect(screen, x, y, 8, 8); + } + SDL_RenderPresent(screen); if (SDL_JoystickGetAttached( joystick ) == 0) { @@ -237,6 +267,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("touchpoints: %d\n", SDL_JoystickNumTouchFingers(joystick)); SDL_Log("instance id: %d\n", SDL_JoystickInstanceID(joystick)); SDL_Log(" guid: %s\n", guid); SDL_JoystickClose(joystick);