blob: a4e4aa7856902b2c08d53b6c628fb4bf78e2e277 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/exo/keyboard.h"
#include "ash/shell.h"
#include "components/exo/keyboard_delegate.h"
#include "components/exo/surface.h"
#include "ui/aura/client/focus_client.h"
#include "ui/aura/window.h"
#include "ui/events/event.h"
namespace exo {
////////////////////////////////////////////////////////////////////////////////
// Keyboard, public:
Keyboard::Keyboard(KeyboardDelegate* delegate)
: delegate_(delegate), focus_(nullptr), modifier_flags_(0) {
ash::Shell::GetInstance()->AddPreTargetHandler(this);
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
->AddObserver(this);
}
Keyboard::~Keyboard() {
delegate_->OnKeyboardDestroying(this);
if (focus_)
focus_->RemoveSurfaceObserver(this);
aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow())
->RemoveObserver(this);
ash::Shell::GetInstance()->RemovePreTargetHandler(this);
}
////////////////////////////////////////////////////////////////////////////////
// ui::EventHandler overrides:
void Keyboard::OnKeyEvent(ui::KeyEvent* event) {
// These modifiers reflect what Wayland is aware of. For example,
// EF_SCROLL_LOCK_ON is missing because Wayland doesn't support scroll lock.
const int kModifierMask = ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN |
ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN |
ui::EF_ALTGR_DOWN | ui::EF_MOD3_DOWN |
ui::EF_NUM_LOCK_ON | ui::EF_CAPS_LOCK_ON;
int modifier_flags = event->flags() & kModifierMask;
if (modifier_flags != modifier_flags_) {
modifier_flags_ = modifier_flags;
if (focus_)
delegate_->OnKeyboardModifiers(modifier_flags_);
}
switch (event->type()) {
case ui::ET_KEY_PRESSED: {
auto it =
std::find(pressed_keys_.begin(), pressed_keys_.end(), event->code());
if (it == pressed_keys_.end()) {
if (focus_)
delegate_->OnKeyboardKey(event->time_stamp(), event->code(), true);
pressed_keys_.push_back(event->code());
}
} break;
case ui::ET_KEY_RELEASED: {
auto it =
std::find(pressed_keys_.begin(), pressed_keys_.end(), event->code());
if (it != pressed_keys_.end()) {
if (focus_)
delegate_->OnKeyboardKey(event->time_stamp(), event->code(), false);
pressed_keys_.erase(it);
}
} break;
default:
NOTREACHED();
break;
}
}
////////////////////////////////////////////////////////////////////////////////
// aura::client::FocusChangeObserver overrides:
void Keyboard::OnWindowFocused(aura::Window* gained_focus,
aura::Window* lost_focus) {
Surface* gained_focus_surface =
gained_focus ? GetEffectiveFocus(gained_focus) : nullptr;
if (gained_focus_surface != focus_) {
if (focus_) {
delegate_->OnKeyboardLeave(focus_);
focus_->RemoveSurfaceObserver(this);
focus_ = nullptr;
}
if (gained_focus_surface) {
delegate_->OnKeyboardModifiers(modifier_flags_);
delegate_->OnKeyboardEnter(gained_focus_surface, pressed_keys_);
focus_ = gained_focus_surface;
focus_->AddSurfaceObserver(this);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// SurfaceObserver overrides:
void Keyboard::OnSurfaceDestroying(Surface* surface) {
DCHECK(surface == focus_);
focus_ = nullptr;
surface->RemoveSurfaceObserver(this);
}
////////////////////////////////////////////////////////////////////////////////
// Keyboard, private:
Surface* Keyboard::GetEffectiveFocus(aura::Window* window) const {
Surface* focus = Surface::AsSurface(window);
if (!focus)
return nullptr;
return delegate_->CanAcceptKeyboardEventsForSurface(focus) ? focus : nullptr;
}
} // namespace exo