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