Mercurial > sdl-ios-xcode
view src/touchscreen/SDL_touchscreen.c @ 2675:5e4274591163 gsoc2008_nds
Started minor changes to the coordinate system used by the touchscreen API as discussed on the mailing list. Also beginning to separate the 'Pressed' and 'Moved' event handling on the private level.
author | Darren Alton <dalton@stevens.edu> |
---|---|
date | Sun, 29 Jun 2008 21:32:31 +0000 |
parents | f1d07ba2e275 |
children |
line wrap: on
line source
/* SDL - Simple DirectMedia Layer Copyright (C) 1997-2006 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" /* This is the touchscreen API for Simple DirectMedia Layer */ #include "SDL_events.h" #include "SDL_systouchscreen.h" #include "SDL_touchscreen_c.h" #if !SDL_EVENTS_DISABLED #include "../events/SDL_events_c.h" #endif /* This is used for Quake III Arena */ #if SDL_EVENTS_DISABLED #define SDL_Lock_EventThread() #define SDL_Unlock_EventThread() #endif Uint8 SDL_numtouchscreens = 0; SDL_Touchscreen **SDL_touchscreens = NULL; static SDL_Touchscreen *default_touchscreen = NULL; int SDL_TouchscreenInit(void) { int arraylen; int status; SDL_numtouchscreens = 0; status = SDL_SYS_TouchscreenInit(); if (status >= 0) { arraylen = (status + 1) * sizeof(*SDL_touchscreens); SDL_touchscreens = (SDL_Touchscreen **) SDL_malloc(arraylen); if (SDL_touchscreens == NULL) { SDL_numtouchscreens = 0; } else { SDL_memset(SDL_touchscreens, 0, arraylen); SDL_numtouchscreens = status; } status = 0; } default_touchscreen = NULL; return (status); } /* * Count the number of touchscreens attached to the system */ int SDL_NumTouchscreens(void) { return SDL_numtouchscreens; } /* * Get the implementation dependent name of a touchscreen */ const char * SDL_TouchscreenName(int device_index) { if ((device_index < 0) || (device_index >= SDL_numtouchscreens)) { SDL_SetError("There are %d touchscreens available", SDL_numtouchscreens); return (NULL); } return (SDL_SYS_TouchscreenName(device_index)); } /* * Open a touchscreen for use - the index passed as an argument refers to * the N'th touchscreen on the system. This index is the value which will * identify this touchscreen in future touchscreen events. * * This function returns a touchscreen identifier, or NULL if an error occurred. */ SDL_Touchscreen * SDL_TouchscreenOpen(int device_index) { int i; SDL_Touchscreen *touchscreen; if ((device_index < 0) || (device_index >= SDL_numtouchscreens)) { SDL_SetError("There are %d touchscreens available", SDL_numtouchscreens); return (NULL); } /* If the touchscreen is already open, return it */ for (i = 0; SDL_touchscreens[i]; ++i) { if (device_index == SDL_touchscreens[i]->index) { touchscreen = SDL_touchscreens[i]; ++touchscreen->ref_count; return (touchscreen); } } /* Create and initialize the touchscreen */ touchscreen = (SDL_Touchscreen *) SDL_malloc((sizeof *touchscreen)); if (touchscreen != NULL) { SDL_memset(touchscreen, 0, (sizeof *touchscreen)); touchscreen->index = device_index; if (SDL_SYS_TouchscreenOpen(touchscreen) < 0) { SDL_free(touchscreen); touchscreen = NULL; } else { if (touchscreen->maxpoints > 0) { touchscreen->points = (struct touchpoint *) SDL_malloc (touchscreen->maxpoints * sizeof(*touchscreen->points)); } if ((touchscreen->maxpoints > 0) && !touchscreen->points) { SDL_OutOfMemory(); SDL_TouchscreenClose(touchscreen); touchscreen = NULL; } if (touchscreen->points) { SDL_memset(touchscreen->points, 0, touchscreen->maxpoints * sizeof(*touchscreen->points)); } } } if (touchscreen) { /* Add touchscreen to list */ ++touchscreen->ref_count; SDL_Lock_EventThread(); for (i = 0; SDL_touchscreens[i]; ++i) /* Skip to next touchscreen */ ; SDL_touchscreens[i] = touchscreen; SDL_Unlock_EventThread(); } return (touchscreen); } /* * Returns 1 if the touchscreen has been opened, or 0 if it has not. */ int SDL_TouchscreenOpened(int device_index) { int i, opened; opened = 0; for (i = 0; SDL_touchscreens[i]; ++i) { if (SDL_touchscreens[i]->index == (Uint8) device_index) { opened = 1; break; } } return (opened); } static int ValidTouchscreen(SDL_Touchscreen ** touchscreen) { int valid; if (*touchscreen == NULL) { *touchscreen = default_touchscreen; } if (*touchscreen == NULL) { SDL_SetError("Touchscreen hasn't been opened yet"); valid = 0; } else { valid = 1; } return valid; } /* * Get the device index of an opened touchscreen. */ int SDL_TouchscreenIndex(SDL_Touchscreen * touchscreen) { if (!ValidTouchscreen(&touchscreen)) { return (-1); } return (touchscreen->index); } /* * Get the max number of points on a multi-touch screen (or 1 on a single-touch) */ int SDL_TouchscreenMaxPoints(SDL_Touchscreen * touchscreen) { if (!ValidTouchscreen(&touchscreen)) { return (-1); } return (touchscreen->maxpoints); } /* * Get the current X,Y position of the indicated point on the touchscreen */ Uint16 SDL_TouchscreenGetXY(SDL_Touchscreen *touchscreen, int point, Uint16 *x, Uint16 *y) { int retval; if (!ValidTouchscreen(&touchscreen)) { return (-1); } retval = 0; if (point < 0) { int i; long avg; if(x) { avg = 0; for(i = 0; i < touchscreen->npoints; ++i) { avg += touchscreen->points[i].x; } *x = avg; } if(y) { avg = 0; for(i = 0; i < touchscreen->npoints; ++i) { avg += touchscreen->points[i].y; } *y = avg; } avg = 0; for(i = 0; i < touchscreen->npoints; ++i) { avg += touchscreen->points[i].pressure; } return (int)avg; } else if (point < touchscreen->maxpoints) { if (x) { *x = touchscreen->points[point].x; } if (y) { *y = touchscreen->points[point].y; } retval = touchscreen->points[point].pressure; } else { SDL_SetError("Touchscreen only can have %d points", touchscreen->maxpoints); retval = -1; } return (retval); } int SDL_TouchscreenGetPoints(SDL_Touchscreen *touchscreen) { if (!ValidTouchscreen(&touchscreen)) { return (-1); } return touchscreen->npoints; } /* * Close a touchscreen previously opened with SDL_TouchscreenOpen() */ void SDL_TouchscreenClose(SDL_Touchscreen * touchscreen) { int i; if (!ValidTouchscreen(&touchscreen)) { return; } /* First decrement ref count */ if (--touchscreen->ref_count > 0) { return; } /* Lock the event queue - prevent touchscreen polling */ SDL_Lock_EventThread(); if (touchscreen == default_touchscreen) { default_touchscreen = NULL; } SDL_SYS_TouchscreenClose(touchscreen); /* Remove touchscreen from list */ for (i = 0; SDL_touchscreens[i]; ++i) { if (touchscreen == SDL_touchscreens[i]) { SDL_memcpy(&SDL_touchscreens[i], &SDL_touchscreens[i + 1], (SDL_numtouchscreens - i) * sizeof(touchscreen)); break; } } /* Let the event thread keep running */ SDL_Unlock_EventThread(); /* Free the data associated with this touchscreen */ if (touchscreen->points) { SDL_free(touchscreen->points); } SDL_free(touchscreen); } void SDL_TouchscreenQuit(void) { /* Stop the event polling */ SDL_Lock_EventThread(); SDL_numtouchscreens = 0; SDL_Unlock_EventThread(); /* Quit the touchscreen setup */ SDL_SYS_TouchscreenQuit(); if (SDL_touchscreens) { SDL_free(SDL_touchscreens); SDL_touchscreens = NULL; } } /* These are global for SDL_systouchscreen.c and SDL_events.c */ int SDL_PrivateTouchPress(SDL_Touchscreen * touchscreen, int point, Uint16 x, Uint16 y, Uint16 pressure) { int posted; if (!ValidTouchscreen(&touchscreen)) { return -1; } if(point >= touchscreen->maxpoints) { SDL_SetError("Touchscreen only can have %d points", touchscreen->maxpoints); return -1; } /* on neg. point, set the given args as the *only* point. so set the struct to have no points pressed, then continue as normal. */ if(point < 0) { point = 0; touchscreen->npoints = 0; SDL_memset(touchscreen->points, 0, touchscreen->maxpoints * sizeof(touchscreen->points[0])); } /* new touch point! that means a TOUCHPRESSED event is due. */ if(point >= touchscreen->npoints) { point = touchscreen->npoints; ++touchscreen->npoints; } /* no motion, no change, don't report an event. */ if(touchscreen->points[point].pressure > 0) { SDL_SetError("Warning: touch point %d was already pressed", point); return -1; } /* Update internal touchscreen point state */ touchscreen->points[point].x = x; touchscreen->points[point].y = y; touchscreen->points[point].pressure = pressure; /* Post the event, if desired */ posted = 0; #if !SDL_EVENTS_DISABLED if (SDL_ProcessEvents[SDL_TOUCHPRESSED] == SDL_ENABLE) { SDL_Event event; event.touch.type = SDL_TOUCHPRESSED; event.touch.which = touchscreen->index; event.touch.point = point; event.touch.xpos = x; event.touch.ypos = y; event.touch.pressure = pressure; if ((SDL_EventOK == NULL) || (*SDL_EventOK) (SDL_EventOKParam, &event)) { posted = 1; SDL_PushEvent(&event); } } #endif /* !SDL_EVENTS_DISABLED */ return (posted); } int SDL_PrivateTouchMove(SDL_Touchscreen * touchscreen, int point, Uint16 x, Uint16 y, Uint16 pressure) { int posted; if (!ValidTouchscreen(&touchscreen)) { return -1; } if(point >= touchscreen->maxpoints) { SDL_SetError("Touchscreen only can have %d points", touchscreen->maxpoints); return -1; } /* on neg. point, set the given args as the *only* point. so set the struct to have no points pressed, then continue as normal. */ if(point < 0) { point = 0; touchscreen->npoints = 0; SDL_memset(touchscreen->points, 0, touchscreen->maxpoints * sizeof(touchscreen->points[0])); } /* new touch point! that means a TOUCHPRESSED event is due. */ if(point >= touchscreen->npoints || touchscreen->points[point].pressure == 0) { SDL_SetError("Touch point %d shouldn't move before it's pressed.", point); return -1; } /* no motion, no change, don't report an event. */ if(touchscreen->points[point].x == x && touchscreen->points[point].y == y && touchscreen->points[point].pressure == pressure) { return 0; } /* Update internal touchscreen point state */ touchscreen->points[point].x = x; touchscreen->points[point].y = y; touchscreen->points[point].pressure = pressure; /* Post the event, if desired */ posted = 0; #if !SDL_EVENTS_DISABLED if (SDL_ProcessEvents[SDL_TOUCHMOTION] == SDL_ENABLE) { SDL_Event event; event.touch.type = SDL_TOUCHMOTION; event.touch.which = touchscreen->index; event.touch.point = point; event.touch.xpos = x; event.touch.ypos = y; event.touch.pressure = pressure; if ((SDL_EventOK == NULL) || (*SDL_EventOK) (SDL_EventOKParam, &event)) { posted = 1; SDL_PushEvent(&event); } } #endif /* !SDL_EVENTS_DISABLED */ return (posted); } int SDL_PrivateTouchRelease(SDL_Touchscreen * touchscreen, int point) { int posted; int i; if (!ValidTouchscreen(&touchscreen)) { return -1; } if(point >= touchscreen->maxpoints) { SDL_SetError("Touchscreen only can have %d points", touchscreen->maxpoints); return -1; } else if(point >= touchscreen->npoints) { SDL_SetError("Point %d up when only %d were down", point, touchscreen->npoints); return -1; } /* on neg. point, clear all points. so set the struct to have one point pressed, then continue as normal. */ if(point < 0) { point = 0; touchscreen->npoints = 1; SDL_memset(&(touchscreen->points[1]), 0, (touchscreen->maxpoints-1) * sizeof(touchscreen->points[0])); } /* Update internal touchscreen point state */ touchscreen->points[point].pressure = 0; touchscreen->points[point].x = 0; touchscreen->points[point].y = 0; if(touchscreen->npoints >= 0) --touchscreen->npoints; for(i = point; i < touchscreen->npoints; ++i) { touchscreen->points[i] = touchscreen->points[i+1]; } /* Post the event, if desired */ posted = 0; #if !SDL_EVENTS_DISABLED if (SDL_ProcessEvents[SDL_TOUCHRELEASED] == SDL_ENABLE) { SDL_Event event; event.touch.type = SDL_TOUCHRELEASED; event.touch.which = touchscreen->index; event.touch.point = point; if ((SDL_EventOK == NULL) || (*SDL_EventOK) (SDL_EventOKParam, &event)) { posted = 1; SDL_PushEvent(&event); } } #endif /* !SDL_EVENTS_DISABLED */ return (posted); } void SDL_TouchscreenUpdate(void) { int i; for (i = 0; SDL_touchscreens[i]; ++i) { SDL_SYS_TouchscreenUpdate(SDL_touchscreens[i]); } } int SDL_TouchscreenEventState(int state) { #if SDL_EVENTS_DISABLED return SDL_IGNORE; #else const Uint8 event_list[] = { SDL_TOUCHPRESSED, SDL_TOUCHRELEASED, SDL_TOUCHMOTION }; unsigned int i; switch (state) { case SDL_QUERY: state = SDL_IGNORE; for (i = 0; i < SDL_arraysize(event_list); ++i) { state = SDL_EventState(event_list[i], SDL_QUERY); if (state == SDL_ENABLE) { break; } } break; default: for (i = 0; i < SDL_arraysize(event_list); ++i) { SDL_EventState(event_list[i], state); } break; } return (state); #endif /* SDL_EVENTS_DISABLED */ } /* vi: set ts=4 sw=4 expandtab: */