1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "qemu-common.h" 18 #include "user-events.h" 19 #include "android/display-core.h" 20 #include "android/hw-events.h" 21 #include "android/charmap.h" 22 #include "android/globals.h" /* for android_hw */ 23 #include "android/utils/misc.h" 24 #include "android/utils/debug.h" 25 #include "android/multitouch-screen.h" 26 27 #define E(...) derror(__VA_ARGS__) 28 #define W(...) dwarning(__VA_ARGS__) 29 #define D(...) VERBOSE_PRINT(mtscreen,__VA_ARGS__) 30 #define D_ACTIVE VERBOSE_CHECK(mtscreen) 31 32 #define TRACE_ON 1 33 34 #if TRACE_ON 35 #define T(...) VERBOSE_PRINT(mtscreen,__VA_ARGS__) 36 #else 37 #define T(...) 38 #endif 39 40 41 /* Maximum number of pointers, supported by multi-touch emulation. */ 42 #define MTS_POINTERS_NUM 10 43 /* Signals that pointer is not tracked (or is "up"). */ 44 #define MTS_POINTER_UP -1 45 /* Special tracking ID for a mouse pointer. */ 46 #define MTS_POINTER_MOUSE -2 47 48 /* Describes state of a multi-touch pointer */ 49 typedef struct MTSPointerState { 50 /* Tracking ID assigned to the pointer by an app emulating multi-touch. */ 51 int tracking_id; 52 /* X - coordinate of the tracked pointer. */ 53 int x; 54 /* Y - coordinate of the tracked pointer. */ 55 int y; 56 /* Current pressure value. */ 57 int pressure; 58 } MTSPointerState; 59 60 /* Describes state of an emulated multi-touch screen. */ 61 typedef struct MTSState { 62 /* Multi-touch port connected to the device. */ 63 AndroidMTSPort* mtsp; 64 /* Emulator's display state. */ 65 DisplayState* ds; 66 /* Number of tracked pointers. */ 67 int tracked_ptr_num; 68 /* Index in the 'tracked_pointers' array of the last pointer for which 69 * ABS_MT_SLOT was sent. -1 indicates that no slot selection has been made 70 * yet. */ 71 int current_slot; 72 /* Accumulator for ABS_TOUCH_MAJOR value. */ 73 int touch_major; 74 /* Array of multi-touch pointers. */ 75 MTSPointerState tracked_pointers[MTS_POINTERS_NUM]; 76 /* Header collecting framebuffer information and updates. */ 77 MTFrameHeader fb_header; 78 /* Boolean value indicating if framebuffer updates are currently being 79 * transferred to the application running on the device. */ 80 int fb_transfer_in_progress; 81 /* Indicates direction in which lines are arranged in the framebuffer. If 82 * this value is negative, lines are arranged in bottom-up format (i.e. the 83 * bottom line is at the beginning of the buffer). */ 84 int ydir; 85 /* Current framebuffer pointer. */ 86 uint8_t* current_fb; 87 } MTSState; 88 89 /* Default multi-touch screen descriptor */ 90 static MTSState _MTSState = { 0 }; 91 92 /* Pushes event to the event device. */ 93 static void 94 _push_event(int type, int code, int value) 95 { 96 user_event_generic(type, code, value); 97 } 98 99 /* Gets an index in the MTS's tracking pointers array MTS for the given 100 * tracking id. 101 * Return: 102 * Index of a matching entry in the MTS's tracking pointers array, or -1 if 103 * matching entry was not found. 104 */ 105 static int 106 _mtsstate_get_pointer_index(const MTSState* mts_state, int tracking_id) 107 { 108 int index; 109 for (index = 0; index < MTS_POINTERS_NUM; index++) { 110 if (mts_state->tracked_pointers[index].tracking_id == tracking_id) { 111 return index; 112 } 113 } 114 return -1; 115 } 116 117 /* Gets an index of the first untracking pointer in the MTS's tracking pointers 118 * array. 119 * Return: 120 * An index of the first untracking pointer, or -1 if all pointers are tracked. 121 */ 122 static int 123 _mtsstate_get_available_pointer_index(const MTSState* mts_state) 124 { 125 return _mtsstate_get_pointer_index(mts_state, MTS_POINTER_UP); 126 } 127 128 /* Handles a "pointer down" event 129 * Param: 130 * mts_state - MTS state descriptor. 131 * tracking_id - Tracking ID of the "downed" pointer. 132 * x, y - "Downed" pointer coordinates, 133 * pressure - Pressure value for the pointer. 134 */ 135 static void 136 _mts_pointer_down(MTSState* mts_state, int tracking_id, int x, int y, int pressure) 137 { 138 /* Get first available slot for the new pointer. */ 139 const int slot_index = _mtsstate_get_available_pointer_index(mts_state); 140 141 /* Make sure there is a place for the pointer. */ 142 if (slot_index >= 0) { 143 /* Initialize pointer's entry. */ 144 mts_state->tracked_ptr_num++; 145 mts_state->tracked_pointers[slot_index].tracking_id = tracking_id; 146 mts_state->tracked_pointers[slot_index].x = x; 147 mts_state->tracked_pointers[slot_index].y = y; 148 mts_state->tracked_pointers[slot_index].pressure = pressure; 149 150 /* Send events indicating a "pointer down" to the EventHub */ 151 /* Make sure that correct slot is selected. */ 152 if (slot_index != mts_state->current_slot) { 153 _push_event(EV_ABS, ABS_MT_SLOT, slot_index); 154 } 155 _push_event(EV_ABS, ABS_MT_TRACKING_ID, slot_index); 156 _push_event(EV_ABS, ABS_MT_TOUCH_MAJOR, ++mts_state->touch_major); 157 _push_event(EV_ABS, ABS_MT_PRESSURE, pressure); 158 _push_event(EV_ABS, ABS_MT_POSITION_X, x); 159 _push_event(EV_ABS, ABS_MT_POSITION_Y, y); 160 _push_event(EV_SYN, SYN_REPORT, 0); 161 mts_state->current_slot = slot_index; 162 } else { 163 D("MTS pointer count is exceeded."); 164 return; 165 } 166 } 167 168 /* Handles a "pointer up" event 169 * Param: 170 * mts_state - MTS state descriptor. 171 * slot_index - Pointer's index in the MTS's array of tracked pointers. 172 */ 173 static void 174 _mts_pointer_up(MTSState* mts_state, int slot_index) 175 { 176 /* Make sure that correct slot is selected. */ 177 if (slot_index != mts_state->current_slot) { 178 _push_event(EV_ABS, ABS_MT_SLOT, slot_index); 179 } 180 181 /* Send event indicating "pointer up" to the EventHub. */ 182 _push_event(EV_ABS, ABS_MT_TRACKING_ID, -1); 183 _push_event(EV_SYN, SYN_REPORT, 0); 184 185 /* Update MTS descriptor, removing the tracked pointer. */ 186 mts_state->tracked_pointers[slot_index].tracking_id = MTS_POINTER_UP; 187 mts_state->tracked_pointers[slot_index].x = 0; 188 mts_state->tracked_pointers[slot_index].y = 0; 189 mts_state->tracked_pointers[slot_index].pressure = 0; 190 191 /* Since current slot is no longer tracked, make sure we will do a "select" 192 * next time we send events to the EventHub. */ 193 mts_state->current_slot = -1; 194 mts_state->tracked_ptr_num--; 195 assert(mts_state->tracked_ptr_num >= 0); 196 } 197 198 /* Handles a "pointer move" event 199 * Param: 200 * mts_state - MTS state descriptor. 201 * slot_index - Pointer's index in the MTS's array of tracked pointers. 202 * x, y - New pointer coordinates, 203 * pressure - Pressure value for the pointer. 204 */ 205 static void 206 _mts_pointer_move(MTSState* mts_state, int slot_index, int x, int y, int pressure) 207 { 208 MTSPointerState* ptr_state = &mts_state->tracked_pointers[slot_index]; 209 210 /* Make sure that coordinates have really changed. */ 211 if (ptr_state->x == x && ptr_state->y == y) { 212 /* Coordinates didn't change. Bail out. */ 213 return; 214 } 215 216 /* Make sure that the right slot is selected. */ 217 if (slot_index != mts_state->current_slot) { 218 _push_event(EV_ABS, ABS_MT_SLOT, slot_index); 219 mts_state->current_slot = slot_index; 220 } 221 222 /* Push the changes down. */ 223 if (ptr_state->pressure != pressure && pressure != 0) { 224 _push_event(EV_ABS, ABS_MT_PRESSURE, pressure); 225 ptr_state->pressure = pressure; 226 } 227 if (ptr_state->x != x) { 228 _push_event(EV_ABS, ABS_MT_POSITION_X, x); 229 ptr_state->x = x; 230 } 231 if (ptr_state->y != y) { 232 _push_event(EV_ABS, ABS_MT_POSITION_Y, y); 233 ptr_state->y = y; 234 } 235 _push_event(EV_SYN, SYN_REPORT, 0); 236 } 237 238 /******************************************************************************** 239 * Multi-touch API 240 *******************************************************************************/ 241 242 /* Multi-touch service initialization flag. */ 243 static int _is_mt_initialized = 0; 244 245 /* Callback that is invoked when framebuffer update has been transmitted to the 246 * device. */ 247 static AsyncIOAction 248 _on_fb_sent(void* opaque, SDKCtlDirectPacket* packet, AsyncIOState status) 249 { 250 MTSState* const mts_state = (MTSState*)opaque; 251 252 if (status == ASIO_STATE_SUCCEEDED) { 253 /* Lets see if we have accumulated more changes while transmission has been 254 * in progress. */ 255 if (mts_state->fb_header.w && mts_state->fb_header.h && 256 !mts_state->fb_transfer_in_progress) { 257 mts_state->fb_transfer_in_progress = 1; 258 /* Send accumulated updates. */ 259 if (mts_port_send_frame(mts_state->mtsp, &mts_state->fb_header, 260 mts_state->current_fb, _on_fb_sent, mts_state, 261 mts_state->ydir)) { 262 mts_state->fb_transfer_in_progress = 0; 263 } 264 } 265 } 266 267 return ASIO_ACTION_DONE; 268 } 269 270 /* Common handler for framebuffer updates invoked by both, software, and OpenGLES 271 * renderers. 272 */ 273 static void 274 _mt_fb_common_update(MTSState* mts_state, int x, int y, int w, int h) 275 { 276 if (mts_state->fb_header.w == 0 && mts_state->fb_header.h == 0) { 277 /* First update after previous one has been transmitted to the device. */ 278 mts_state->fb_header.x = x; 279 mts_state->fb_header.y = y; 280 mts_state->fb_header.w = w; 281 mts_state->fb_header.h = h; 282 } else { 283 /* 284 * Accumulate framebuffer changes in the header. 285 */ 286 287 /* "right" and "bottom" coordinates of the current update. */ 288 int right = mts_state->fb_header.x + mts_state->fb_header.w; 289 int bottom = mts_state->fb_header.y + mts_state->fb_header.h; 290 291 /* "right" and "bottom" coordinates of the new update. */ 292 const int new_right = x + w; 293 const int new_bottom = y + h; 294 295 /* Accumulate changed rectangle coordinates in the header. */ 296 if (mts_state->fb_header.x > x) { 297 mts_state->fb_header.x = x; 298 } 299 if (mts_state->fb_header.y > y) { 300 mts_state->fb_header.y = y; 301 } 302 if (right < new_right) { 303 right = new_right; 304 } 305 if (bottom < new_bottom) { 306 bottom = new_bottom; 307 } 308 mts_state->fb_header.w = right - mts_state->fb_header.x; 309 mts_state->fb_header.h = bottom - mts_state->fb_header.y; 310 } 311 312 /* We will send updates to the device only after previous transmission is 313 * completed. */ 314 if (!mts_state->fb_transfer_in_progress) { 315 mts_state->fb_transfer_in_progress = 1; 316 if (mts_port_send_frame(mts_state->mtsp, &mts_state->fb_header, 317 mts_state->current_fb, _on_fb_sent, mts_state, 318 mts_state->ydir)) { 319 mts_state->fb_transfer_in_progress = 0; 320 } 321 } 322 } 323 324 /* A callback invoked on framebuffer updates by software renderer. 325 * Param: 326 * opaque - MTSState instance. 327 * x, y, w, h - Defines an updated rectangle inside the framebuffer. 328 */ 329 static void 330 _mt_fb_update(void* opaque, int x, int y, int w, int h) 331 { 332 MTSState* const mts_state = (MTSState*)opaque; 333 const DisplaySurface* const surface = mts_state->ds->surface; 334 335 T("Multi-touch: Software renderer framebuffer update: %d:%d -> %dx%d", 336 x, y, w, h); 337 338 /* TODO: For sofware renderer general framebuffer properties can change on 339 * the fly. Find a callback that can catch that. For now, just copy FB 340 * properties over in every FB update. */ 341 mts_state->fb_header.bpp = surface->pf.bytes_per_pixel; 342 mts_state->fb_header.bpl = surface->linesize; 343 mts_state->fb_header.disp_width = surface->width; 344 mts_state->fb_header.disp_height = surface->height; 345 mts_state->current_fb = surface->data; 346 mts_state->ydir = 1; 347 348 _mt_fb_common_update(mts_state, x, y, w, h); 349 } 350 351 void 352 multitouch_opengles_fb_update(void* context, 353 int w, int h, int ydir, 354 int format, int type, 355 unsigned char* pixels) 356 { 357 MTSState* const mts_state = &_MTSState; 358 359 /* Make sure MT port is initialized. */ 360 if (!_is_mt_initialized) { 361 return; 362 } 363 364 T("Multi-touch: openGLES framebuffer update: 0:0 -> %dx%d", w, h); 365 366 /* GLES format is always RGBA8888 */ 367 mts_state->fb_header.bpp = 4; 368 mts_state->fb_header.bpl = 4 * w; 369 mts_state->fb_header.disp_width = w; 370 mts_state->fb_header.disp_height = h; 371 mts_state->current_fb = pixels; 372 mts_state->ydir = ydir; 373 374 /* GLES emulator alwas update the entire framebuffer. */ 375 _mt_fb_common_update(mts_state, 0, 0, w, h); 376 } 377 378 void 379 multitouch_refresh_screen(void) 380 { 381 MTSState* const mts_state = &_MTSState; 382 383 /* Make sure MT port is initialized. */ 384 if (!_is_mt_initialized) { 385 return; 386 } 387 388 /* Lets see if any updates have been received so far. */ 389 if (NULL != mts_state->current_fb) { 390 _mt_fb_common_update(mts_state, 0, 0, mts_state->fb_header.disp_width, 391 mts_state->fb_header.disp_height); 392 } 393 } 394 395 void 396 multitouch_fb_updated(void) 397 { 398 MTSState* const mts_state = &_MTSState; 399 400 /* This concludes framebuffer update. */ 401 mts_state->fb_transfer_in_progress = 0; 402 403 /* Lets see if we have accumulated more changes while transmission has been 404 * in progress. */ 405 if (mts_state->fb_header.w && mts_state->fb_header.h) { 406 mts_state->fb_transfer_in_progress = 1; 407 /* Send accumulated updates. */ 408 if (mts_port_send_frame(mts_state->mtsp, &mts_state->fb_header, 409 mts_state->current_fb, _on_fb_sent, mts_state, 410 mts_state->ydir)) { 411 mts_state->fb_transfer_in_progress = 0; 412 } 413 } 414 } 415 416 void 417 multitouch_init(AndroidMTSPort* mtsp) 418 { 419 if (!_is_mt_initialized) { 420 MTSState* const mts_state = &_MTSState; 421 DisplayState* const ds = get_displaystate(); 422 DisplayUpdateListener* dul; 423 int index; 424 425 /* 426 * Initialize the descriptor. 427 */ 428 429 memset(mts_state, 0, sizeof(MTSState)); 430 mts_state->tracked_ptr_num = 0; 431 mts_state->current_slot = -1; 432 for (index = 0; index < MTS_POINTERS_NUM; index++) { 433 mts_state->tracked_pointers[index].tracking_id = MTS_POINTER_UP; 434 } 435 mts_state->mtsp = mtsp; 436 mts_state->fb_header.header_size = sizeof(MTFrameHeader); 437 mts_state->fb_transfer_in_progress = 0; 438 439 /* 440 * Set framebuffer update listener. 441 */ 442 443 ANEW0(dul); 444 dul->opaque = &_MTSState; 445 dul->dpy_update = _mt_fb_update; 446 447 /* Initialize framebuffer information in the screen descriptor. */ 448 mts_state->ds = ds; 449 mts_state->fb_header.disp_width = ds->surface->width; 450 mts_state->fb_header.disp_height = ds->surface->height; 451 mts_state->fb_header.x = mts_state->fb_header.y = 0; 452 mts_state->fb_header.w = mts_state->fb_header.h = 0; 453 mts_state->fb_header.bpp = ds->surface->pf.bytes_per_pixel; 454 mts_state->fb_header.bpl = ds->surface->linesize; 455 mts_state->fb_transfer_in_progress = 0; 456 457 register_displayupdatelistener(ds, dul); 458 459 _is_mt_initialized = 1; 460 } 461 } 462 463 void 464 multitouch_update_pointer(MTESource source, 465 int tracking_id, 466 int x, 467 int y, 468 int pressure) 469 { 470 MTSState* const mts_state = &_MTSState; 471 472 /* Assign a fixed tracking ID to the mouse pointer. */ 473 if (source == MTES_MOUSE) { 474 tracking_id = MTS_POINTER_MOUSE; 475 } 476 477 /* Find the tracked pointer for the tracking ID. */ 478 const int slot_index = _mtsstate_get_pointer_index(mts_state, tracking_id); 479 if (slot_index < 0) { 480 /* This is the first time the pointer is seen. Must be "pressed", 481 * otherwise it's "hoovering", which we don't support yet. */ 482 if (pressure == 0) { 483 if (tracking_id != MTS_POINTER_MOUSE) { 484 D("Unexpected MTS pointer update for tracking id: %d", 485 tracking_id); 486 } 487 return; 488 } 489 490 /* This is a "pointer down" event */ 491 _mts_pointer_down(mts_state, tracking_id, x, y, pressure); 492 } else if (pressure == 0) { 493 /* This is a "pointer up" event */ 494 _mts_pointer_up(mts_state, slot_index); 495 } else { 496 /* This is a "pointer move" event */ 497 _mts_pointer_move(mts_state, slot_index, x, y, pressure); 498 } 499 } 500 501 int 502 multitouch_get_max_slot() 503 { 504 return MTS_POINTERS_NUM - 1; 505 } 506