1/* ______ ___ ___ 2 * /\ _ \ /\_ \ /\_ \ 3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ 4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ 5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ 6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ 7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ 8 * /\____/ 9 * \_/__/ 10 * 11 * iPhone family device touch input driver. 12 * 13 * By Michał Cichoń. 14 * 15 * See readme.txt for copyright information. 16 */ 17#include "allegro5/allegro.h" 18#include "allegro5/internal/aintern_touch_input.h" 19#include "allegro5/internal/aintern_display.h" 20#include "allegro5/internal/aintern_iphone.h" 21 22 23static ALLEGRO_TOUCH_INPUT_STATE touch_input_state; 24static ALLEGRO_MOUSE_STATE mouse_state; 25static ALLEGRO_TOUCH_INPUT touch_input; 26static bool installed = false; 27 28static void generate_touch_input_event(unsigned int type, double timestamp, int id, float x, float y, float dx, float dy, bool primary, ALLEGRO_DISPLAY *disp) 29{ 30 ALLEGRO_EVENT event; 31 32 bool want_touch_event = _al_event_source_needs_to_generate_event(&touch_input.es); 33 bool want_mouse_emulation_event; 34 35 if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_5_0_x) { 36 want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && al_is_mouse_installed(); 37 } 38 else { 39 want_mouse_emulation_event = _al_event_source_needs_to_generate_event(&touch_input.mouse_emulation_es) && primary && al_is_mouse_installed(); 40 } 41 42 if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_NONE) 43 want_mouse_emulation_event = false; 44 else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_INCLUSIVE) 45 want_touch_event = al_is_mouse_installed() ? (want_touch_event && !primary) : want_touch_event; 46 else if (touch_input.mouse_emulation_mode == ALLEGRO_MOUSE_EMULATION_EXCLUSIVE) 47 want_touch_event = al_is_mouse_installed() ? false : want_touch_event; 48 49 50 if (!want_touch_event && !want_mouse_emulation_event) 51 return; 52 53 if (want_touch_event) { 54 55 event.touch.type = type; 56 event.touch.display = (ALLEGRO_DISPLAY*)disp; 57 event.touch.timestamp = timestamp; 58 event.touch.id = id; 59 event.touch.x = x; 60 event.touch.y = y; 61 event.touch.dx = dx; 62 event.touch.dy = dy; 63 event.touch.primary = primary; 64 65 _al_event_source_lock(&touch_input.es); 66 _al_event_source_emit_event(&touch_input.es, &event); 67 _al_event_source_unlock(&touch_input.es); 68 } 69 70 if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_NONE) { 71 _al_event_source_lock(&touch_input.mouse_emulation_es); 72 if (want_mouse_emulation_event) { 73 74 switch (type) { 75 case ALLEGRO_EVENT_TOUCH_BEGIN: type = ALLEGRO_EVENT_MOUSE_BUTTON_DOWN; break; 76 case ALLEGRO_EVENT_TOUCH_CANCEL: 77 case ALLEGRO_EVENT_TOUCH_END: type = ALLEGRO_EVENT_MOUSE_BUTTON_UP; break; 78 case ALLEGRO_EVENT_TOUCH_MOVE: type = ALLEGRO_EVENT_MOUSE_AXES; break; 79 } 80 81 event.mouse.type = type; 82 event.mouse.timestamp = timestamp; 83 event.mouse.display = (ALLEGRO_DISPLAY*)disp; 84 event.mouse.x = (int)x; 85 event.mouse.y = (int)y; 86 event.mouse.dx = (int)dx; 87 event.mouse.dy = (int)dy; 88 event.mouse.dz = 0; 89 event.mouse.dw = 0; 90 if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { 91 event.mouse.button = 1; 92 } 93 else { 94 event.mouse.button = id; 95 } 96 event.mouse.pressure = 1.0; 97 98 if (touch_input.mouse_emulation_mode != ALLEGRO_MOUSE_EMULATION_5_0_x) { 99 al_set_mouse_xy(event.mouse.display, event.mouse.x, event.mouse.y); 100 } 101 102 _al_event_source_emit_event(&touch_input.mouse_emulation_es, &event); 103 } 104 105 mouse_state.x = (int)x; 106 mouse_state.y = (int)y; 107 if (type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) 108 mouse_state.buttons |= id; 109 else if (type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) 110 mouse_state.buttons &= ~id; 111 112 _al_event_source_unlock(&touch_input.mouse_emulation_es); 113 } 114} 115 116 117static bool init_touch_input(void) 118{ 119 if (installed) 120 return false; 121 122 memset(&touch_input_state, 0, sizeof(touch_input_state)); 123 memset(&mouse_state, 0, sizeof(mouse_state)); 124 125 _al_event_source_init(&touch_input.es); 126 _al_event_source_init(&touch_input.mouse_emulation_es); 127 touch_input.mouse_emulation_mode = ALLEGRO_MOUSE_EMULATION_TRANSPARENT; 128 129 installed = true; 130 131 return true; 132} 133 134 135static void exit_touch_input(void) 136{ 137 if (!installed) 138 return; 139 140 memset(&touch_input_state, 0, sizeof(touch_input_state)); 141 memset(&mouse_state, 0, sizeof(mouse_state)); 142 143 _al_event_source_free(&touch_input.es); 144 _al_event_source_free(&touch_input.mouse_emulation_es); 145 146 installed = false; 147} 148 149 150static ALLEGRO_TOUCH_INPUT* get_touch_input(void) 151{ 152 return &touch_input; 153} 154 155 156static void get_touch_input_state(ALLEGRO_TOUCH_INPUT_STATE *ret_state) 157{ 158 _al_event_source_lock(&touch_input.es); 159 *ret_state = touch_input_state; 160 _al_event_source_unlock(&touch_input.es); 161} 162 163 164static void set_mouse_emulation_mode(int mode) 165{ 166 if (touch_input.mouse_emulation_mode != mode) { 167 168 int i; 169 170 for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) { 171 172 ALLEGRO_TOUCH_STATE* touch = touch_input_state.touches + i; 173 174 if (touch->id > 0) { 175 _al_iphone_touch_input_handle_cancel(touch->id, al_get_time(), 176 touch->x, touch->y, touch->primary, touch->display); 177 } 178 } 179 180 touch_input.mouse_emulation_mode = mode; 181 } 182} 183 184 185static ALLEGRO_TOUCH_STATE* find_free_touch_state() 186{ 187 int i; 188 189 for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) 190 if (touch_input_state.touches[i].id <= 0) 191 return touch_input_state.touches + i; 192 193 return NULL; 194} 195 196 197static ALLEGRO_TOUCH_STATE* find_touch_state_with_id(int id) 198{ 199 int i; 200 201 for (i = 0; i < ALLEGRO_TOUCH_INPUT_MAX_TOUCH_COUNT; ++i) 202 if (touch_input_state.touches[i].id == id) 203 return touch_input_state.touches + i; 204 205 return NULL; 206} 207 208 209 210void _al_iphone_touch_input_handle_begin(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) 211{ 212 ALLEGRO_TOUCH_STATE* state = find_free_touch_state(); 213 (void)primary; 214 215 if (NULL == state) 216 return; 217 218 _al_event_source_lock(&touch_input.es); 219 state->id = id; 220 state->x = x; 221 state->y = y; 222 state->dx = 0.0f; 223 state->dy = 0.0f; 224 state->primary = primary; 225 state->display = disp; 226 _al_event_source_unlock(&touch_input.es); 227 228 generate_touch_input_event(ALLEGRO_EVENT_TOUCH_BEGIN, timestamp, 229 state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); 230} 231 232 233void _al_iphone_touch_input_handle_end(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) 234{ 235 ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); 236 (void)primary; 237 238 if (NULL == state) 239 return; 240 241 _al_event_source_lock(&touch_input.es); 242 state->dx = x - state->x; 243 state->dy = y - state->y; 244 state->x = x; 245 state->y = y; 246 _al_event_source_unlock(&touch_input.es); 247 248 generate_touch_input_event(ALLEGRO_EVENT_TOUCH_END, timestamp, 249 state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); 250 251 _al_event_source_lock(&touch_input.es); 252 memset(state, 0, sizeof(ALLEGRO_TOUCH_STATE)); 253 _al_event_source_unlock(&touch_input.es); 254} 255 256 257void _al_iphone_touch_input_handle_move(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) 258{ 259 ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); 260 (void)primary; 261 262 if (NULL == state) 263 return; 264 265 _al_event_source_lock(&touch_input.es); 266 state->dx = x - state->x; 267 state->dy = y - state->y; 268 state->x = x; 269 state->y = y; 270 _al_event_source_unlock(&touch_input.es); 271 272 generate_touch_input_event(ALLEGRO_EVENT_TOUCH_MOVE, timestamp, 273 state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); 274} 275 276 277void _al_iphone_touch_input_handle_cancel(int id, double timestamp, float x, float y, bool primary, ALLEGRO_DISPLAY *disp) 278{ 279 ALLEGRO_TOUCH_STATE* state = find_touch_state_with_id(id); 280 (void)primary; 281 282 if (NULL == state) 283 return; 284 285 _al_event_source_lock(&touch_input.es); 286 state->dx = x - state->x; 287 state->dy = y - state->y; 288 state->x = x; 289 state->y = y; 290 _al_event_source_unlock(&touch_input.es); 291 292 generate_touch_input_event(ALLEGRO_EVENT_TOUCH_CANCEL, timestamp, 293 state->id, state->x, state->y, state->dx, state->dy, state->primary, disp); 294 295 _al_event_source_lock(&touch_input.es); 296 memset(state, 0, sizeof(ALLEGRO_TOUCH_STATE)); 297 _al_event_source_unlock(&touch_input.es); 298} 299 300 301/* the driver vtable */ 302#define TOUCH_INPUT_IPHONE AL_ID('I','T','I','D') 303 304static ALLEGRO_TOUCH_INPUT_DRIVER touch_input_driver = 305{ 306 TOUCH_INPUT_IPHONE, 307 init_touch_input, 308 exit_touch_input, 309 get_touch_input, 310 get_touch_input_state, 311 set_mouse_emulation_mode, 312 NULL 313}; 314 315ALLEGRO_TOUCH_INPUT_DRIVER *_al_get_iphone_touch_input_driver(void) 316{ 317 return &touch_input_driver; 318} 319 320void imouse_get_state(ALLEGRO_MOUSE_STATE *ret_state) 321{ 322 _al_event_source_lock(&touch_input.es); 323 *ret_state = mouse_state; 324 _al_event_source_unlock(&touch_input.es); 325} 326 327