Home | History | Annotate | Download | only in android
      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