• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
_push_event(int type,int code,int value)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
_mtsstate_get_pointer_index(const MTSState * mts_state,int tracking_id)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
_mtsstate_get_available_pointer_index(const MTSState * mts_state)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
_mts_pointer_down(MTSState * mts_state,int tracking_id,int x,int y,int pressure)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
_mts_pointer_up(MTSState * mts_state,int slot_index)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
_mts_pointer_move(MTSState * mts_state,int slot_index,int x,int y,int pressure)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
_on_fb_sent(void * opaque,SDKCtlDirectPacket * packet,AsyncIOState status)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
_mt_fb_common_update(MTSState * mts_state,int x,int y,int w,int h)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
_mt_fb_update(void * opaque,int x,int y,int w,int h)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
multitouch_opengles_fb_update(void * context,int w,int h,int ydir,int format,int type,unsigned char * pixels)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
multitouch_refresh_screen(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
multitouch_fb_updated(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
multitouch_init(AndroidMTSPort * mtsp)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
multitouch_update_pointer(MTESource source,int tracking_id,int x,int y,int pressure)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
multitouch_get_max_slot()502 multitouch_get_max_slot()
503 {
504     return MTS_POINTERS_NUM - 1;
505 }
506