Home | History | Annotate | Download | only in caca
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/ozone/platform/caca/caca_event_factory.h"
      6 
      7 #include <caca.h>
      8 
      9 #include "base/bind.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "ui/events/event.h"
     12 #include "ui/events/keycodes/keyboard_codes.h"
     13 #include "ui/ozone/platform/caca/caca_connection.h"
     14 
     15 namespace ui {
     16 
     17 namespace {
     18 
     19 ui::KeyboardCode GetKeyboardCode(const caca_event_t& event) {
     20   // List of special mappings the Caca provides.
     21   static const ui::KeyboardCode kCacaKeyMap[] = {
     22     ui::VKEY_UNKNOWN,
     23     ui::VKEY_A,
     24     ui::VKEY_B,
     25     ui::VKEY_C,
     26     ui::VKEY_D,
     27     ui::VKEY_E,
     28     ui::VKEY_F,
     29     ui::VKEY_G,
     30     ui::VKEY_BACK,
     31     ui::VKEY_TAB,
     32     ui::VKEY_J,
     33     ui::VKEY_K,
     34     ui::VKEY_L,
     35     ui::VKEY_RETURN,
     36     ui::VKEY_N,
     37     ui::VKEY_O,
     38     ui::VKEY_P,
     39     ui::VKEY_Q,
     40     ui::VKEY_R,
     41     ui::VKEY_PAUSE,
     42     ui::VKEY_T,
     43     ui::VKEY_U,
     44     ui::VKEY_V,
     45     ui::VKEY_W,
     46     ui::VKEY_X,
     47     ui::VKEY_Y,
     48     ui::VKEY_Z,
     49     ui::VKEY_ESCAPE,
     50     ui::VKEY_DELETE,
     51     ui::VKEY_UP,
     52     ui::VKEY_DOWN,
     53     ui::VKEY_LEFT,
     54     ui::VKEY_RIGHT,
     55     ui::VKEY_INSERT,
     56     ui::VKEY_HOME,
     57     ui::VKEY_END,
     58     ui::VKEY_PRIOR,
     59     ui::VKEY_NEXT,
     60     ui::VKEY_F1,
     61     ui::VKEY_F2,
     62     ui::VKEY_F3,
     63     ui::VKEY_F4,
     64     ui::VKEY_F5,
     65     ui::VKEY_F6,
     66     ui::VKEY_F7,
     67     ui::VKEY_F8,
     68     ui::VKEY_F9,
     69     ui::VKEY_F10,
     70     ui::VKEY_F11,
     71     ui::VKEY_F12,
     72   };
     73 
     74   int key_code = caca_get_event_key_ch(&event);
     75   if (key_code >= 'a' && key_code <= 'z')
     76     return static_cast<ui::KeyboardCode>(key_code - ('a' - 'A'));
     77   if (key_code >= '0' && key_code <= 'Z')
     78     return static_cast<ui::KeyboardCode>(key_code);
     79   if (static_cast<unsigned int>(key_code) < arraysize(kCacaKeyMap))
     80     return kCacaKeyMap[key_code];
     81 
     82   return ui::VKEY_UNKNOWN;
     83 }
     84 
     85 int ModifierFromKey(const caca_event_t& event) {
     86   int key_code = caca_get_event_key_ch(&event);
     87   if (key_code >= 'A' && key_code <= 'Z')
     88     return ui::EF_SHIFT_DOWN;
     89   if ((key_code >= CACA_KEY_CTRL_A && key_code <= CACA_KEY_CTRL_G) ||
     90       (key_code >= CACA_KEY_CTRL_J && key_code <= CACA_KEY_CTRL_L) ||
     91       (key_code >= CACA_KEY_CTRL_N && key_code <= CACA_KEY_CTRL_R) ||
     92       (key_code >= CACA_KEY_CTRL_T && key_code <= CACA_KEY_CTRL_Z))
     93     return ui::EF_CONTROL_DOWN;
     94 
     95   return ui::EF_NONE;
     96 }
     97 
     98 int ModifierFromButton(const caca_event_t& event) {
     99   switch (caca_get_event_mouse_button(&event)) {
    100     case 1:
    101       return ui::EF_LEFT_MOUSE_BUTTON;
    102     case 2:
    103       return ui::EF_RIGHT_MOUSE_BUTTON;
    104     case 3:
    105       return ui::EF_MIDDLE_MOUSE_BUTTON;
    106   }
    107   return 0;
    108 }
    109 
    110 // Translate coordinates to bitmap coordinates.
    111 gfx::PointF TranslateLocation(const gfx::PointF& location,
    112                               CacaConnection* connection) {
    113   gfx::Size physical_size = connection->physical_size();
    114   gfx::Size bitmap_size = connection->bitmap_size();
    115   return gfx::PointF(
    116       location.x() * bitmap_size.width() / physical_size.width(),
    117       location.y() * bitmap_size.height() / physical_size.height());
    118 }
    119 
    120 ui::EventType GetEventTypeFromNative(const caca_event_t& event) {
    121   switch (caca_get_event_type(&event)) {
    122     case CACA_EVENT_KEY_PRESS:
    123       return ui::ET_KEY_PRESSED;
    124     case CACA_EVENT_KEY_RELEASE:
    125       return ui::ET_KEY_RELEASED;
    126     case CACA_EVENT_MOUSE_PRESS:
    127       return ui::ET_MOUSE_PRESSED;
    128     case CACA_EVENT_MOUSE_RELEASE:
    129       return ui::ET_MOUSE_RELEASED;
    130     case CACA_EVENT_MOUSE_MOTION:
    131       return ui::ET_MOUSE_MOVED;
    132     default:
    133       return ui::ET_UNKNOWN;
    134   }
    135 }
    136 
    137 }  // namespace
    138 
    139 CacaEventFactory::CacaEventFactory(CacaConnection* connection)
    140   : connection_(connection),
    141     weak_ptr_factory_(this),
    142     delay_(base::TimeDelta::FromMilliseconds(10)),
    143     modifier_flags_(0) {
    144 }
    145 
    146 CacaEventFactory::~CacaEventFactory() {
    147 }
    148 
    149 void CacaEventFactory::WarpCursorTo(gfx::AcceleratedWidget widget,
    150                                     const gfx::PointF& location) {
    151   NOTIMPLEMENTED();
    152 }
    153 
    154 void CacaEventFactory::OnDispatcherListChanged() {
    155   ScheduleEventProcessing();
    156 }
    157 
    158 void CacaEventFactory::ScheduleEventProcessing() {
    159   // Caca uses a poll based event retrieval. Since we don't want to block we'd
    160   // either need to spin up a new thread or just poll. For simplicity just poll
    161   // for a message every |delay_| time delta.
    162   base::MessageLoop::current()->PostDelayedTask(
    163       FROM_HERE,
    164       base::Bind(&CacaEventFactory::TryProcessingEvent,
    165                  weak_ptr_factory_.GetWeakPtr()),
    166       delay_);
    167 }
    168 
    169 void CacaEventFactory::TryProcessingEvent() {
    170   caca_event_t event;
    171   int event_mask = CACA_EVENT_KEY_PRESS | CACA_EVENT_KEY_RELEASE |
    172                    CACA_EVENT_MOUSE_PRESS | CACA_EVENT_MOUSE_RELEASE |
    173                    CACA_EVENT_MOUSE_MOTION;
    174   if (connection_->display() &&
    175       caca_get_event(connection_->display(), event_mask, &event, 0)) {
    176 
    177     ui::EventType type = GetEventTypeFromNative(event);
    178     bool pressed = type == ui::ET_KEY_PRESSED || type == ui::ET_MOUSE_PRESSED;
    179 
    180     switch (type) {
    181       case ui::ET_KEY_PRESSED:
    182       case ui::ET_KEY_RELEASED: {
    183         if (pressed)
    184           modifier_flags_ |= ModifierFromKey(event);
    185         else
    186           modifier_flags_ &= ~ModifierFromKey(event);
    187 
    188         ui::KeyEvent key_event(
    189             type, GetKeyboardCode(event), modifier_flags_, true);
    190         DispatchEvent(&key_event);
    191         break;
    192       }
    193       case ui::ET_MOUSE_MOVED:
    194         last_cursor_location_.SetPoint(caca_get_event_mouse_x(&event),
    195                                        caca_get_event_mouse_y(&event));
    196         // Update cursor location.
    197         caca_gotoxy(caca_get_canvas(connection_->display()),
    198                     last_cursor_location_.x(),
    199                     last_cursor_location_.y());
    200       // fallthrough
    201       case ui::ET_MOUSE_PRESSED:
    202       case ui::ET_MOUSE_RELEASED: {
    203         int flags = 0;
    204         int changed_flags = 0;
    205         if (type != ui::ET_MOUSE_MOVED) {
    206           if (pressed) {
    207             changed_flags = ModifierFromButton(event);
    208             modifier_flags_ |= changed_flags;
    209           } else {
    210             modifier_flags_ &= ~changed_flags;
    211           }
    212           // On release the button pressed is removed from |modifier_flags_|,
    213           // but sending the event needs it set.
    214           flags = modifier_flags_ | changed_flags;
    215         }
    216         gfx::PointF location = TranslateLocation(last_cursor_location_,
    217                                                  connection_);
    218         ui::MouseEvent mouse_event(
    219             type, location, location, flags, changed_flags);
    220         DispatchEvent(&mouse_event);
    221         break;
    222       }
    223       default:
    224         NOTIMPLEMENTED();
    225         break;
    226     }
    227   }
    228 
    229   ScheduleEventProcessing();
    230 }
    231 
    232 }  // namespace ui
    233