Mercurial > sdl-ios-xcode
diff src/events/SDL_touch.c @ 4640:f068a6dfc858
Added SDL_touch.c/SDL_touch_c.h as slightly modifeind SDL_mouse*. Made reads in touchSimp non-blocking.
author | Jim Grandpre <jim.tla@gmail.com> |
---|---|
date | Tue, 25 May 2010 23:23:23 -0400 |
parents | |
children | 49a97daea6ec |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/events/SDL_touch.c Tue May 25 23:23:23 2010 -0400 @@ -0,0 +1,575 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* General touch handling code for SDL */ + +#include "SDL_events.h" +#include "SDL_events_c.h" +#include "../video/SDL_sysvideo.h" + + +static int SDL_num_touch = 0; +static int SDL_current_touch = -1; +static SDL_Touch **SDL_touch = NULL; + + +/* Public functions */ +int +SDL_TouchInit(void) +{ + return (0); +} + +SDL_Touch * +SDL_GetTouch(int index) +{ + if (index < 0 || index >= SDL_num_touch) { + return NULL; + } + return SDL_touch[index]; +} + +static int +SDL_GetTouchIndexId(int id) +{ + int index; + SDL_Touch *touch; + + for (index = 0; index < SDL_num_touch; ++index) { + touch = SDL_GetTouch(index); + if (touch->id == id) { + return index; + } + } + return -1; +} + +int +SDL_AddTouch(const SDL_Touch * touch, char *name, int pressure_max, + int pressure_min, int ends) +{ + SDL_Touch **touch; + int selected_touch; + int index; + size_t length; + + if (SDL_GetTouchIndexId(touch->id) != -1) { + SDL_SetError("Touch ID already in use"); + } + + /* Add the touch to the list of touch */ + touch = (SDL_Touch **) SDL_realloc(SDL_touch, + (SDL_num_touch + 1) * sizeof(*touch)); + if (!touch) { + SDL_OutOfMemory(); + return -1; + } + + SDL_touch = touch; + index = SDL_num_touch++; + + SDL_touch[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touch[index])); + if (!SDL_touch[index]) { + SDL_OutOfMemory(); + return -1; + } + *SDL_touch[index] = *touch; + + /* we're setting the touch properties */ + length = 0; + length = SDL_strlen(name); + SDL_touch[index]->focus = 0; + SDL_touch[index]->name = SDL_malloc((length + 2) * sizeof(char)); + SDL_strlcpy(SDL_touch[index]->name, name, length + 1); + SDL_touch[index]->pressure_max = pressure_max; + SDL_touch[index]->pressure_min = pressure_min; + SDL_touch[index]->cursor_shown = SDL_TRUE; + selected_touch = SDL_SelectTouch(index); + SDL_touch[index]->cur_cursor = NULL; + SDL_touch[index]->def_cursor = + /* we're assuming that all touch are in the computer sensing zone */ + SDL_touch[index]->proximity = SDL_TRUE; + /* we're assuming that all touch are working in the absolute position mode + thanx to that, the users that don't want to use many touch don't have to + worry about anything */ + SDL_touch[index]->relative_mode = SDL_FALSE; + SDL_touch[index]->current_end = 0; + SDL_touch[index]->total_ends = ends; + SDL_SelectTouch(selected_touch); + + return index; +} + +void +SDL_DelTouch(int index) +{ + SDL_Touch *touch = SDL_GetTouch(index); + + if (!touch) { + return; + } + + touch->def_cursor = NULL; + SDL_free(touch->name); + + if (touch->FreeTouch) { + touch->FreeTouch(touch); + } + SDL_free(touch); + + SDL_touch[index] = NULL; +} + +void +SDL_ResetTouch(int index) +{ + SDL_Touch *touch = SDL_GetTouch(index); + + if (!touch) { + return; + } + + /* FIXME */ +} + +void +SDL_TouchQuit(void) +{ + int i; + + for (i = 0; i < SDL_num_touch; ++i) { + SDL_DelTouch(i); + } + SDL_num_touch = 0; + SDL_current_touch = -1; + + if (SDL_touch) { + SDL_free(SDL_touch); + SDL_touch = NULL; + } +} + +int +SDL_GetNumTouch(void) +{ + return SDL_num_touch; +} + +int +SDL_SelectTouch(int index) +{ + if (index >= 0 && index < SDL_num_touch) { + SDL_current_touch = index; + } + return SDL_current_touch; +} + +SDL_Window * +SDL_GetTouchFocusWindow(int index) +{ + SDL_Touch *touch = SDL_GetTouch(index); + + if (!touch) { + return 0; + } + return touch->focus; +} + +static int SDLCALL +FlushTouchMotion(void *param, SDL_Event * event) +{ + if (event->type == SDL_TOUCHMOTION + && event->motion.which == (Uint8) SDL_current_touch) { + return 0; + } else { + return 1; + } +} + +int +SDL_SetRelativeTouchMode(int index, SDL_bool enabled) +{ + SDL_Touch *touch = SDL_GetTouch(index); + + if (!touch) { + return -1; + } + + /* Flush pending touch motion */ + touch->flush_motion = SDL_TRUE; + SDL_PumpEvents(); + touch->flush_motion = SDL_FALSE; + SDL_FilterEvents(FlushTouchMotion, touch); + + /* Set the relative mode */ + touch->relative_mode = enabled; + + + + if (!enabled) { + /* Restore the expected touch position */ + SDL_WarpTouchInWindow(touch->focus, touch->x, touch->y); + } + return 0; +} + +SDL_bool +SDL_GetRelativeTouchMode(int index) +{ + SDL_Touch *touch = SDL_GetTouch(index); + + if (!touch) { + return SDL_FALSE; + } + return touch->relative_mode; +} + +Uint8 +SDL_GetTouchState(int *x, int *y) +{ + SDL_Touch *touch = SDL_GetTouch(SDL_current_touch); + + if (!touch) { + if (x) { + *x = 0; + } + if (y) { + *y = 0; + } + return 0; + } + + if (x) { + *x = touch->x; + } + if (y) { + *y = touch->y; + } + return touch->buttonstate; +} + +Uint8 +SDL_GetRelativeTouchState(int index, int *x, int *y) +{ + SDL_Touch *touch = SDL_GetTouch(index); + + if (!touch) { + if (x) { + *x = 0; + } + if (y) { + *y = 0; + } + return 0; + } + + if (x) { + *x = touch->xdelta; + } + if (y) { + *y = touch->ydelta; + } + touch->xdelta = 0; + touch->ydelta = 0; + return touch->buttonstate; +} + +void +SDL_SetTouchFocus(int id, SDL_Window * window) +{ + int index = SDL_GetTouchIndexId(id); + SDL_Touch *touch = SDL_GetTouch(index); + int i; + SDL_bool focus; + + if (!touch || (touch->focus == window)) { + return; + } + + /* See if the current window has lost focus */ + if (touch->focus) { + focus = SDL_FALSE; + for (i = 0; i < SDL_num_touch; ++i) { + SDL_Touch *check; + if (i != index) { + check = SDL_GetTouch(i); + if (check && check->focus == touch->focus) { + focus = SDL_TRUE; + break; + } + } + } + if (!focus) { + SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_LEAVE, 0, 0); + } + } + + touch->focus = window; + + if (touch->focus) { + focus = SDL_FALSE; + for (i = 0; i < SDL_num_touch; ++i) { + SDL_Touch *check; + if (i != index) { + check = SDL_GetTouch(i); + if (check && check->focus == touch->focus) { + focus = SDL_TRUE; + break; + } + } + } + if (!focus) { + SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_ENTER, 0, 0); + } + } +} + +int +SDL_SendProximity(int id, int x, int y, int type) +{ + int index = SDL_GetTouchIndexId(id); + SDL_Touch *touch = SDL_GetTouch(index); + int posted = 0; + + if (!touch) { + return 0; + } + + touch->last_x = x; + touch->last_y = y; + if (SDL_GetEventState(type) == SDL_ENABLE) { + SDL_Event event; + event.proximity.which = (Uint8) index; + event.proximity.x = x; + event.proximity.y = y; + event.proximity.cursor = touch->current_end; + event.proximity.type = type; + /* FIXME: is this right? */ + event.proximity.windowID = touch->focus ? touch->focus->id : 0; + posted = (SDL_PushEvent(&event) > 0); + if (type == SDL_PROXIMITYIN) { + touch->proximity = SDL_TRUE; + } else { + touch->proximity = SDL_FALSE; + } + } + return posted; +} + +int +SDL_SendTouchMotion(int id, int relative, int x, int y, int pressure) +{ + int index = SDL_GetTouchIndexId(id); + SDL_Touch *touch = SDL_GetTouch(index); + int posted; + int xrel; + int yrel; + int x_max = 0, y_max = 0; + + if (!touch || touch->flush_motion) { + return 0; + } + + /* if the touch is out of proximity we don't to want to have any motion from it */ + if (touch->proximity == SDL_FALSE) { + touch->last_x = x; + touch->last_y = y; + return 0; + } + + /* the relative motion is calculated regarding the system cursor last position */ + if (relative) { + xrel = x; + yrel = y; + x = (touch->last_x + x); + y = (touch->last_y + y); + } else { + xrel = x - touch->last_x; + yrel = y - touch->last_y; + } + + /* Drop events that don't change state */ + if (!xrel && !yrel) { +#if 0 + printf("Touch event didn't change state - dropped!\n"); +#endif + return 0; + } + + /* Update internal touch coordinates */ + if (touch->relative_mode == SDL_FALSE) { + touch->x = x; + touch->y = y; + } else { + touch->x += xrel; + touch->y += yrel; + } + + SDL_GetWindowSize(touch->focus, &x_max, &y_max); + + /* make sure that the pointers find themselves inside the windows */ + /* only check if touch->xmax is set ! */ + if (x_max && touch->x > x_max) { + touch->x = x_max; + } else if (touch->x < 0) { + touch->x = 0; + } + + if (y_max && touch->y > y_max) { + touch->y = y_max; + } else if (touch->y < 0) { + touch->y = 0; + } + + touch->xdelta += xrel; + touch->ydelta += yrel; + touch->pressure = pressure; + + + + /* Post the event, if desired */ + posted = 0; + if (SDL_GetEventState(SDL_TOUCHMOTION) == SDL_ENABLE && + touch->proximity == SDL_TRUE) { + SDL_Event event; + event.motion.type = SDL_TOUCHMOTION; + event.motion.which = (Uint8) index; + event.motion.state = touch->buttonstate; + event.motion.x = touch->x; + event.motion.y = touch->y; + event.motion.z = touch->z; + event.motion.pressure = touch->pressure; + event.motion.pressure_max = touch->pressure_max; + event.motion.pressure_min = touch->pressure_min; + event.motion.rotation = 0; + event.motion.tilt_x = 0; + event.motion.tilt_y = 0; + event.motion.cursor = touch->current_end; + event.motion.xrel = xrel; + event.motion.yrel = yrel; + event.motion.windowID = touch->focus ? touch->focus->id : 0; + posted = (SDL_PushEvent(&event) > 0); + } + touch->last_x = touch->x; + touch->last_y = touch->y; + return posted; +} + +int +SDL_SendTouchButton(int id, Uint8 state, Uint8 button) +{ + int index = SDL_GetTouchIndexId(id); + SDL_Touch *touch = SDL_GetTouch(index); + int posted; + Uint32 type; + + if (!touch) { + return 0; + } + + /* Figure out which event to perform */ + switch (state) { + case SDL_PRESSED: + if (touch->buttonstate & SDL_BUTTON(button)) { + /* Ignore this event, no state change */ + return 0; + } + type = SDL_TOUCHBUTTONDOWN; + touch->buttonstate |= SDL_BUTTON(button); + break; + case SDL_RELEASED: + if (!(touch->buttonstate & SDL_BUTTON(button))) { + /* Ignore this event, no state change */ + return 0; + } + type = SDL_TOUCHBUTTONUP; + touch->buttonstate &= ~SDL_BUTTON(button); + break; + default: + /* Invalid state -- bail */ + return 0; + } + + /* Post the event, if desired */ + posted = 0; + if (SDL_GetEventState(type) == SDL_ENABLE) { + SDL_Event event; + event.type = type; + event.button.which = (Uint8) index; + event.button.state = state; + event.button.button = button; + event.button.x = touch->x; + event.button.y = touch->y; + event.button.windowID = touch->focus ? touch->focus->id : 0; + posted = (SDL_PushEvent(&event) > 0); + } + return posted; +} + +int +SDL_SendTouchWheel(int index, int x, int y) +{ + SDL_Touch *touch = SDL_GetTouch(index); + int posted; + + if (!touch || (!x && !y)) { + return 0; + } + + /* Post the event, if desired */ + posted = 0; + if (SDL_GetEventState(SDL_TOUCHWHEEL) == SDL_ENABLE) { + SDL_Event event; + event.type = SDL_TOUCHWHEEL; + event.wheel.which = (Uint8) index; + event.wheel.x = x; + event.wheel.y = y; + event.wheel.windowID = touch->focus ? touch->focus->id : 0; + posted = (SDL_PushEvent(&event) > 0); + } + return posted; +} + + +char * +SDL_GetTouchName(int index) +{ + SDL_Touch *touch = SDL_GetTouch(index); + if (!touch) { + return NULL; + } + return touch->name; +} + +void +SDL_ChangeEnd(int id, int end) +{ + int index = SDL_GetTouchIndexId(id); + SDL_Touch *touch = SDL_GetTouch(index); + + if (touch) { + touch->current_end = end; + } +} + +/* vi: set ts=4 sw=4 expandtab: */