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 #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