• 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 /* 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
_push_event(int type,int code,int value)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
_mtsstate_get_pointer_index(const MTSState * mts_state,int tracking_id)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
_mtsstate_get_available_pointer_index(const MTSState * mts_state)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
_mts_pointer_down(MTSState * mts_state,int tracking_id,int x,int y,int pressure)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
_mts_pointer_up(MTSState * mts_state,int slot_index)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
_mts_pointer_move(MTSState * mts_state,int slot_index,int x,int y,int pressure)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
_on_fb_sent(void * opaque,ATResult res,void * data,int size,int sent)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
_mt_fb_common_update(MTSState * mts_state,int x,int y,int w,int h)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
_mt_fb_update(void * opaque,int x,int y,int w,int h)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
multitouch_opengles_fb_update(void * context,int w,int h,int ydir,int format,int type,unsigned char * pixels)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
multitouch_init(AndroidMTSPort * mtsp)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
multitouch_update_pointer(MTESource source,int tracking_id,int x,int y,int pressure)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
multitouch_get_max_slot()452 multitouch_get_max_slot()
453 {
454     return MTS_POINTERS_NUM - 1;
455 }
456 
457 void
multitouch_set_device_screen_size(int width,int height)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