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