Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "apps/moterm/moterm_view.h" | 5 #include "apps/moterm/moterm_view.h" |
| 6 | 6 |
| 7 #ifndef GL_GLEXT_PROTOTYPES | 7 #ifndef GL_GLEXT_PROTOTYPES |
| 8 #define GL_GLEXT_PROTOTYPES | 8 #define GL_GLEXT_PROTOTYPES |
| 9 #endif | 9 #endif |
| 10 | 10 |
| 11 #include <GLES2/gl2.h> | 11 #include <GLES2/gl2.h> |
| 12 #include <GLES2/gl2ext.h> | 12 #include <GLES2/gl2ext.h> |
| 13 | 13 |
| 14 #include <algorithm> | 14 #include <algorithm> |
| 15 #include <string> | 15 #include <string> |
| 16 | 16 |
| 17 #include "apps/moterm/key_util.h" | 17 #include "apps/moterm/key_util.h" |
| 18 #include "base/bind.h" | |
| 18 #include "base/logging.h" | 19 #include "base/logging.h" |
| 20 #include "mojo/public/cpp/application/connect.h" | |
| 19 #include "mojo/public/cpp/bindings/interface_request.h" | 21 #include "mojo/public/cpp/bindings/interface_request.h" |
| 20 #include "mojo/services/files/interfaces/file.mojom.h" | 22 #include "mojo/services/files/interfaces/file.mojom.h" |
| 21 #include "mojo/services/files/interfaces/types.mojom.h" | 23 #include "mojo/services/files/interfaces/types.mojom.h" |
| 22 #include "mojo/services/input_events/interfaces/input_event_constants.mojom.h" | |
| 23 #include "mojo/services/input_events/interfaces/input_events.mojom.h" | |
| 24 #include "mojo/services/terminal/interfaces/terminal_client.mojom.h" | 24 #include "mojo/services/terminal/interfaces/terminal_client.mojom.h" |
| 25 #include "skia/ext/refptr.h" | 25 #include "mojo/skia/ganesh_texture_surface.h" |
| 26 #include "third_party/dejavu-fonts-ttf-2.34/kDejaVuSansMonoRegular.h" | 26 #include "third_party/dejavu-fonts-ttf-2.34/kDejaVuSansMonoRegular.h" |
| 27 #include "third_party/skia/include/core/SkBitmap.h" | 27 #include "third_party/skia/include/core/SkBitmap.h" |
| 28 #include "third_party/skia/include/core/SkCanvas.h" | 28 #include "third_party/skia/include/core/SkCanvas.h" |
| 29 #include "third_party/skia/include/core/SkColor.h" | 29 #include "third_party/skia/include/core/SkColor.h" |
| 30 #include "third_party/skia/include/core/SkImageInfo.h" | 30 #include "third_party/skia/include/core/SkImageInfo.h" |
| 31 #include "third_party/skia/include/core/SkPaint.h" | 31 #include "third_party/skia/include/core/SkPaint.h" |
| 32 #include "third_party/skia/include/core/SkRect.h" | 32 #include "third_party/skia/include/core/SkRect.h" |
| 33 #include "third_party/skia/include/core/SkStream.h" | 33 #include "third_party/skia/include/core/SkStream.h" |
| 34 #include "third_party/skia/include/core/SkXfermode.h" | 34 #include "third_party/skia/include/core/SkXfermode.h" |
| 35 | 35 |
| 36 namespace { | 36 constexpr uint32_t kMotermImageResourceId = 1; |
| 37 | 37 constexpr uint32_t kRootNodeId = mojo::gfx::composition::kSceneRootNodeId; |
| 38 const GLint kTextureFormat = | |
| 39 (kN32_SkColorType == kRGBA_8888_SkColorType) ? GL_RGBA : GL_BGRA_EXT; | |
| 40 | |
| 41 mojo::Size RectToSize(const mojo::Rect& rect) { | |
| 42 mojo::Size size; | |
| 43 size.width = rect.width; | |
| 44 size.height = rect.height; | |
| 45 return size; | |
| 46 } | |
| 47 | |
| 48 } // namespace | |
| 49 | 38 |
| 50 MotermView::MotermView( | 39 MotermView::MotermView( |
| 51 mojo::Shell* shell, | 40 mojo::ApplicationImpl* app_impl, |
| 52 mojo::View* view, | 41 mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request, |
| 53 mojo::InterfaceRequest<mojo::ServiceProvider> service_provider_request) | 42 const mojo::ui::ViewProvider::CreateViewCallback& create_view_callback) |
| 54 : view_(view), | 43 : GaneshView(app_impl, "Moterm", create_view_callback), |
| 55 gl_helper_(this, | 44 choreographer_(scene(), this), |
| 56 shell, | 45 input_handler_(view_service_provider(), this), |
| 57 kTextureFormat, | |
| 58 false, | |
| 59 RectToSize(view->bounds())), | |
| 60 model_(MotermModel::Size(240, 160), MotermModel::Size(24, 80), this), | 46 model_(MotermModel::Size(240, 160), MotermModel::Size(24, 80), this), |
| 61 frame_pending_(false), | |
| 62 force_next_draw_(false), | 47 force_next_draw_(false), |
| 63 ascent_(0), | 48 ascent_(0), |
| 64 line_height_(0), | 49 line_height_(0), |
| 65 advance_width_(0), | 50 advance_width_(0), |
| 66 keypad_application_mode_(false) { | 51 keypad_application_mode_(false) { |
| 67 // TODO(vtl): |service_provider_impl_|'s ctor doesn't like an invalid request, | 52 // TODO(vtl): |service_provider_impl_|'s ctor doesn't like an invalid request, |
| 68 // so we have to conditionally, explicitly bind. | 53 // so we have to conditionally, explicitly bind. |
| 69 if (service_provider_request.is_pending()) { | 54 if (service_provider_request.is_pending()) { |
| 70 service_provider_impl_.Bind(service_provider_request.Pass()); | 55 service_provider_impl_.Bind(service_provider_request.Pass()); |
| 71 service_provider_impl_.AddService<mojo::terminal::Terminal>(this); | 56 service_provider_impl_.AddService<mojo::terminal::Terminal>(this); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 82 // Figure out appropriate metrics. | 67 // Figure out appropriate metrics. |
| 83 SkPaint::FontMetrics fm = {}; | 68 SkPaint::FontMetrics fm = {}; |
| 84 fg_paint.getFontMetrics(&fm); | 69 fg_paint.getFontMetrics(&fm); |
| 85 ascent_ = static_cast<int>(ceilf(-fm.fAscent)); | 70 ascent_ = static_cast<int>(ceilf(-fm.fAscent)); |
| 86 line_height_ = ascent_ + static_cast<int>(ceilf(fm.fDescent + fm.fLeading)); | 71 line_height_ = ascent_ + static_cast<int>(ceilf(fm.fDescent + fm.fLeading)); |
| 87 DCHECK_GT(line_height_, 0); | 72 DCHECK_GT(line_height_, 0); |
| 88 // To figure out the advance width, measure an X. Better hope the font is | 73 // To figure out the advance width, measure an X. Better hope the font is |
| 89 // monospace. | 74 // monospace. |
| 90 advance_width_ = static_cast<int>(ceilf(fg_paint.measureText("X", 1))); | 75 advance_width_ = static_cast<int>(ceilf(fg_paint.measureText("X", 1))); |
| 91 DCHECK_GT(advance_width_, 0); | 76 DCHECK_GT(advance_width_, 0); |
| 92 | |
| 93 view_->AddObserver(this); | |
| 94 | |
| 95 // Force an initial draw. | |
| 96 Draw(true); | |
| 97 } | 77 } |
| 98 | 78 |
| 99 MotermView::~MotermView() { | 79 MotermView::~MotermView() { |
| 100 if (driver_) | 80 if (driver_) |
| 101 driver_->Detach(); | 81 driver_->Detach(); |
| 102 } | 82 } |
| 103 | 83 |
| 104 void MotermView::OnViewDestroyed(mojo::View* view) { | 84 void MotermView::OnLayout(mojo::ui::ViewLayoutParamsPtr layout_params, |
| 105 DCHECK_EQ(view, view_); | 85 mojo::Array<uint32_t> children_needing_layout, |
| 106 view_->RemoveObserver(this); | 86 const OnLayoutCallback& callback) { |
| 107 delete this; | 87 view_size_.width = layout_params->constraints->max_width; |
| 88 view_size_.height = layout_params->constraints->max_height; | |
| 89 | |
| 90 ScheduleDraw(true); | |
| 91 | |
| 92 auto info = mojo::ui::ViewLayoutResult::New(); | |
| 93 info->size = view_size_.Clone(); | |
| 94 callback.Run(info.Pass()); | |
| 108 } | 95 } |
| 109 | 96 |
| 110 void MotermView::OnViewBoundsChanged(mojo::View* view, | 97 void MotermView::OnEvent(mojo::EventPtr event, |
| 111 const mojo::Rect& old_bounds, | 98 const OnEventCallback& callback) { |
| 112 const mojo::Rect& new_bounds) { | 99 if (event->action == mojo::EventType::KEY_PRESSED) { |
| 113 DCHECK_EQ(view, view_); | 100 OnKeyPressed(event.Pass()); |
| 114 gl_helper_.SetSurfaceSize(RectToSize(view_->bounds())); | 101 callback.Run(true); |
| 115 bitmap_device_.clear(); | 102 } else { |
| 116 Draw(true); | 103 callback.Run(false); |
| 117 } | 104 } |
| 118 | |
| 119 void MotermView::OnViewInputEvent(mojo::View* view, | |
| 120 const mojo::EventPtr& event) { | |
| 121 if (event->action == mojo::EventType::KEY_PRESSED) | |
| 122 OnKeyPressed(event); | |
| 123 } | |
| 124 | |
| 125 void MotermView::OnSurfaceIdChanged(mojo::SurfaceIdPtr surface_id) { | |
| 126 view_->SetSurfaceId(surface_id.Pass()); | |
| 127 } | |
| 128 | |
| 129 void MotermView::OnContextLost() { | |
| 130 // TODO(vtl): We'll need to force a draw when we regain a context. | |
| 131 } | |
| 132 | |
| 133 void MotermView::OnFrameDisplayed(uint32_t frame_id) { | |
| 134 DCHECK(frame_pending_); | |
| 135 frame_pending_ = false; | |
| 136 Draw(false); | |
| 137 } | 105 } |
| 138 | 106 |
| 139 void MotermView::OnResponse(const void* buf, size_t size) { | 107 void MotermView::OnResponse(const void* buf, size_t size) { |
| 140 if (driver_) | 108 if (driver_) |
| 141 driver_->SendData(buf, size); | 109 driver_->SendData(buf, size); |
| 142 } | 110 } |
| 143 | 111 |
| 144 void MotermView::OnSetKeypadMode(bool application_mode) { | 112 void MotermView::OnSetKeypadMode(bool application_mode) { |
| 145 keypad_application_mode_ = application_mode; | 113 keypad_application_mode_ = application_mode; |
| 146 } | 114 } |
| 147 | 115 |
| 148 void MotermView::OnDataReceived(const void* bytes, size_t num_bytes) { | 116 void MotermView::OnDataReceived(const void* bytes, size_t num_bytes) { |
| 149 model_.ProcessInput(bytes, num_bytes, &model_state_changes_); | 117 model_.ProcessInput(bytes, num_bytes, &model_state_changes_); |
| 150 Draw(false); | 118 ScheduleDraw(false); |
| 151 } | 119 } |
| 152 | 120 |
| 153 void MotermView::OnClosed() { | 121 void MotermView::OnClosed() { |
| 154 DCHECK(driver_); | 122 DCHECK(driver_); |
| 155 driver_->Detach(); | 123 driver_->Detach(); |
| 156 driver_.reset(); | 124 driver_.reset(); |
| 157 | 125 |
| 158 OnDestroyed(); | 126 OnDestroyed(); |
| 159 } | 127 } |
| 160 | 128 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 void MotermView::GetSize(const GetSizeCallback& callback) { | 186 void MotermView::GetSize(const GetSizeCallback& callback) { |
| 219 MotermModel::Size size = model_.GetSize(); | 187 MotermModel::Size size = model_.GetSize(); |
| 220 callback.Run(mojo::files::Error::OK, size.rows, size.columns); | 188 callback.Run(mojo::files::Error::OK, size.rows, size.columns); |
| 221 } | 189 } |
| 222 | 190 |
| 223 void MotermView::SetSize(uint32_t rows, | 191 void MotermView::SetSize(uint32_t rows, |
| 224 uint32_t columns, | 192 uint32_t columns, |
| 225 bool reset, | 193 bool reset, |
| 226 const SetSizeCallback& callback) { | 194 const SetSizeCallback& callback) { |
| 227 if (!rows) { | 195 if (!rows) { |
| 228 rows = std::max(1u, std::min(MotermModel::kMaxRows, | 196 rows = std::max( |
| 229 static_cast<uint32_t>(view_->bounds().height) / | 197 1u, std::min(MotermModel::kMaxRows, |
| 230 line_height_)); | 198 static_cast<uint32_t>(view_size_.height) / line_height_)); |
| 231 } | 199 } |
| 232 if (!columns) { | 200 if (!columns) { |
| 233 columns = | 201 columns = std::max( |
| 234 std::max(1u, std::min(MotermModel::kMaxColumns, | 202 1u, std::min(MotermModel::kMaxColumns, |
| 235 static_cast<uint32_t>(view_->bounds().width) / | 203 static_cast<uint32_t>(view_size_.width) / advance_width_)); |
| 236 advance_width_)); | |
| 237 } | 204 } |
| 238 | 205 |
| 239 model_.SetSize(MotermModel::Size(rows, columns), reset); | 206 model_.SetSize(MotermModel::Size(rows, columns), reset); |
| 240 callback.Run(mojo::files::Error::OK, rows, columns); | 207 callback.Run(mojo::files::Error::OK, rows, columns); |
| 241 | 208 |
| 242 Draw(false); | 209 ScheduleDraw(false); |
| 243 } | 210 } |
| 244 | 211 |
| 245 void MotermView::Draw(bool force) { | 212 void MotermView::ScheduleDraw(bool force) { |
| 246 // TODO(vtl): See TODO above |frame_pending_| in the class declaration. | 213 if (view_size_.width == 0 || view_size_.height == 0 || |
| 247 if (frame_pending_) { | 214 (!model_state_changes_.IsDirty() && !force && !force_next_draw_)) { |
| 248 force_next_draw_ |= force; | 215 force_next_draw_ |= force; |
| 249 return; | 216 return; |
| 250 } | 217 } |
| 218 force_next_draw_ = false; | |
| 219 choreographer_.ScheduleDraw(); | |
| 220 } | |
| 251 | 221 |
| 252 force |= force_next_draw_; | 222 void MotermView::OnDraw(const mojo::gfx::composition::FrameInfo& frame_info, |
| 253 force_next_draw_ = false; | 223 const base::TimeDelta& time_delta) { |
| 254 | |
| 255 if (!force && !model_state_changes_.IsDirty()) | |
| 256 return; | |
| 257 | |
| 258 // TODO(vtl): If |!force|, draw only the dirty region(s)? | 224 // TODO(vtl): If |!force|, draw only the dirty region(s)? |
|
viettrungluu
2016/01/26 18:33:35
Hmmm. This TODO doesn't quite make sense anymore.
jeffbrown
2016/01/26 23:10:44
Done.
| |
| 259 model_state_changes_.Reset(); | 225 model_state_changes_.Reset(); |
| 260 | 226 |
| 261 int32_t width = view_->bounds().width; | 227 mojo::Rect bounds; |
| 262 int32_t height = view_->bounds().height; | 228 bounds.width = view_size_.width; |
| 263 DCHECK_GT(width, 0); | 229 bounds.height = view_size_.height; |
| 264 DCHECK_GT(height, 0); | |
| 265 | 230 |
| 266 if (!bitmap_device_) { | 231 auto update = mojo::gfx::composition::SceneUpdate::New(); |
| 267 bitmap_device_ = skia::AdoptRef(SkBitmapDevice::Create(SkImageInfo::Make( | 232 mojo::gfx::composition::ResourcePtr moterm_resource = |
| 268 width, height, kN32_SkColorType, kOpaque_SkAlphaType))); | 233 ganesh_renderer()->DrawCanvas( |
| 269 } | 234 view_size_, |
| 235 base::Bind(&MotermView::DrawContent, base::Unretained(this))); | |
| 236 DCHECK(moterm_resource); | |
| 237 update->resources.insert(kMotermImageResourceId, moterm_resource.Pass()); | |
| 270 | 238 |
| 271 SkCanvas canvas(bitmap_device_.get()); | 239 auto root_node = mojo::gfx::composition::Node::New(); |
| 272 canvas.clear(SK_ColorBLACK); | 240 root_node->op = mojo::gfx::composition::NodeOp::New(); |
| 241 root_node->op->set_image(mojo::gfx::composition::ImageNodeOp::New()); | |
| 242 root_node->op->get_image()->content_rect = bounds.Clone(); | |
| 243 root_node->op->get_image()->image_resource_id = kMotermImageResourceId; | |
| 244 update->nodes.insert(kRootNodeId, root_node.Pass()); | |
| 245 | |
| 246 auto metadata = mojo::gfx::composition::SceneMetadata::New(); | |
| 247 metadata->presentation_time = frame_info.presentation_time; | |
| 248 | |
| 249 scene()->Update(update.Pass()); | |
| 250 scene()->Publish(metadata.Pass()); | |
| 251 } | |
| 252 | |
| 253 void MotermView::DrawContent(SkCanvas* canvas) { | |
| 254 canvas->clear(SK_ColorBLACK); | |
| 273 | 255 |
| 274 SkPaint bg_paint; | 256 SkPaint bg_paint; |
| 275 bg_paint.setStyle(SkPaint::kFill_Style); | 257 bg_paint.setStyle(SkPaint::kFill_Style); |
| 276 | 258 |
| 277 SkPaint fg_paint; | 259 SkPaint fg_paint; |
| 278 fg_paint.setTypeface(regular_typeface_.get()); | 260 fg_paint.setTypeface(regular_typeface_.get()); |
| 279 fg_paint.setTextSize(16); | 261 fg_paint.setTextSize(16); |
| 280 fg_paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); | 262 fg_paint.setTextEncoding(SkPaint::kUTF32_TextEncoding); |
| 281 | 263 |
| 282 MotermModel::Size size = model_.GetSize(); | 264 MotermModel::Size size = model_.GetSize(); |
| 283 int y = 0; | 265 int y = 0; |
| 284 for (unsigned i = 0; i < size.rows; i++, y += line_height_) { | 266 for (unsigned i = 0; i < size.rows; i++, y += line_height_) { |
| 285 int x = 0; | 267 int x = 0; |
| 286 for (unsigned j = 0; j < size.columns; j++, x += advance_width_) { | 268 for (unsigned j = 0; j < size.columns; j++, x += advance_width_) { |
| 287 MotermModel::CharacterInfo ch = | 269 MotermModel::CharacterInfo ch = |
| 288 model_.GetCharacterInfoAt(MotermModel::Position(i, j)); | 270 model_.GetCharacterInfoAt(MotermModel::Position(i, j)); |
| 289 | 271 |
| 290 // Paint the background. | 272 // Paint the background. |
| 291 bg_paint.setColor(SkColorSetRGB(ch.background_color.red, | 273 bg_paint.setColor(SkColorSetRGB(ch.background_color.red, |
| 292 ch.background_color.green, | 274 ch.background_color.green, |
| 293 ch.background_color.blue)); | 275 ch.background_color.blue)); |
| 294 canvas.drawRect(SkRect::MakeXYWH(x, y, advance_width_, line_height_), | 276 canvas->drawRect(SkRect::MakeXYWH(x, y, advance_width_, line_height_), |
| 295 bg_paint); | 277 bg_paint); |
| 296 | 278 |
| 297 // Paint the foreground. | 279 // Paint the foreground. |
| 298 if (ch.code_point) { | 280 if (ch.code_point) { |
| 299 uint32_t flags = SkPaint::kAntiAlias_Flag; | 281 uint32_t flags = SkPaint::kAntiAlias_Flag; |
| 300 // TODO(vtl): Use real bold font? | 282 // TODO(vtl): Use real bold font? |
| 301 if ((ch.attributes & MotermModel::kAttributesBold)) | 283 if ((ch.attributes & MotermModel::kAttributesBold)) |
| 302 flags |= SkPaint::kFakeBoldText_Flag; | 284 flags |= SkPaint::kFakeBoldText_Flag; |
| 303 if ((ch.attributes & MotermModel::kAttributesUnderline)) | 285 if ((ch.attributes & MotermModel::kAttributesUnderline)) |
| 304 flags |= SkPaint::kUnderlineText_Flag; | 286 flags |= SkPaint::kUnderlineText_Flag; |
| 305 // TODO(vtl): Handle blink, because that's awesome. | 287 // TODO(vtl): Handle blink, because that's awesome. |
| 306 fg_paint.setFlags(flags); | 288 fg_paint.setFlags(flags); |
| 307 fg_paint.setColor(SkColorSetRGB(ch.foreground_color.red, | 289 fg_paint.setColor(SkColorSetRGB(ch.foreground_color.red, |
| 308 ch.foreground_color.green, | 290 ch.foreground_color.green, |
| 309 ch.foreground_color.blue)); | 291 ch.foreground_color.blue)); |
| 310 | 292 |
| 311 canvas.drawText(&ch.code_point, sizeof(ch.code_point), x, y + ascent_, | 293 canvas->drawText(&ch.code_point, sizeof(ch.code_point), x, y + ascent_, |
| 312 fg_paint); | 294 fg_paint); |
| 313 } | 295 } |
| 314 } | 296 } |
| 315 } | 297 } |
| 316 | 298 |
| 317 if (model_.GetCursorVisibility()) { | 299 if (model_.GetCursorVisibility()) { |
| 318 // Draw the cursor. | 300 // Draw the cursor. |
| 319 MotermModel::Position cursor_pos = model_.GetCursorPosition(); | 301 MotermModel::Position cursor_pos = model_.GetCursorPosition(); |
| 320 // Reuse the background paint, but don't just paint over. | 302 // Reuse the background paint, but don't just paint over. |
| 321 // TODO(vtl): Consider doing other things. Maybe make it blink, to be extra | 303 // TODO(vtl): Consider doing other things. Maybe make it blink, to be extra |
| 322 // annoying. | 304 // annoying. |
| 323 // TODO(vtl): Maybe vary how we draw the cursor, depending on if we're | 305 // TODO(vtl): Maybe vary how we draw the cursor, depending on if we're |
| 324 // focused and/or active. | 306 // focused and/or active. |
| 325 bg_paint.setColor(SK_ColorWHITE); | 307 bg_paint.setColor(SK_ColorWHITE); |
| 326 bg_paint.setXfermodeMode(SkXfermode::kDifference_Mode); | 308 bg_paint.setXfermodeMode(SkXfermode::kDifference_Mode); |
| 327 canvas.drawRect(SkRect::MakeXYWH(cursor_pos.column * advance_width_, | 309 canvas->drawRect(SkRect::MakeXYWH(cursor_pos.column * advance_width_, |
| 328 cursor_pos.row * line_height_, | 310 cursor_pos.row * line_height_, |
| 329 advance_width_, line_height_), | 311 advance_width_, line_height_), |
| 330 bg_paint); | 312 bg_paint); |
| 331 } | 313 } |
| 332 | 314 canvas->flush(); |
| 333 canvas.flush(); | |
| 334 | |
| 335 const SkBitmap& bitmap(bitmap_device_->accessBitmap(false)); | |
| 336 // TODO(vtl): Do we need really need to lock/unlock pixels? | |
| 337 SkAutoLockPixels pixel_locker(bitmap); | |
| 338 | |
| 339 gl_helper_.StartFrame(); | |
| 340 // (The texture is already bound.) | |
| 341 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, kTextureFormat, | |
| 342 GL_UNSIGNED_BYTE, bitmap.getPixels()); | |
| 343 gl_helper_.EndFrame(); | |
| 344 frame_pending_ = true; | |
| 345 } | 315 } |
| 346 | 316 |
| 347 void MotermView::OnKeyPressed(const mojo::EventPtr& key_event) { | 317 void MotermView::OnKeyPressed(mojo::EventPtr key_event) { |
| 348 std::string input_sequence = | 318 std::string input_sequence = |
| 349 GetInputSequenceForKeyPressedEvent(*key_event, keypad_application_mode_); | 319 GetInputSequenceForKeyPressedEvent(*key_event, keypad_application_mode_); |
| 350 if (input_sequence.empty()) | 320 if (input_sequence.empty()) |
| 351 return; | 321 return; |
| 352 | 322 |
| 353 if (driver_) | 323 if (driver_) |
| 354 driver_->SendData(input_sequence.data(), input_sequence.size()); | 324 driver_->SendData(input_sequence.data(), input_sequence.size()); |
| 355 } | 325 } |
| OLD | NEW |