#include "ash/accelerators/accelerator_capslock_state_machine.h"
#include "base/containers/fixed_flat_set.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/events/event.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/events/types/event_type.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
namespace ash {
constexpr auto kMetaKeys =
base::MakeFixedFlatSet<ui::KeyboardCode>({ui::VKEY_LWIN, ui::VKEY_RWIN});
constexpr auto kAltKeys =
base::MakeFixedFlatSet<ui::KeyboardCode>({ui::VKEY_MENU});
AcceleratorCapslockStateMachine::AcceleratorCapslockStateMachine(
ui::InputController* input_controller)
: input_controller_(input_controller) {}
AcceleratorCapslockStateMachine::~AcceleratorCapslockStateMachine() = default;
void AcceleratorCapslockStateMachine::OnKeyEvent(ui::KeyEvent* event) {
if (event->type() != ui::EventType::kKeyReleased &&
event->type() != ui::EventType::kKeyPressed) {
return;
}
switch (current_state_) {
case CapslockState::kStart:
if (event->type() == ui::EventType::kKeyReleased) {
break;
}
if (kMetaKeys.contains(event->key_code())) {
current_state_ = CapslockState::kWaitingAlt;
break;
}
if (kAltKeys.contains(event->key_code())) {
current_state_ = CapslockState::kWaitingSearch;
break;
}
current_state_ = CapslockState::kSuppress;
break;
case CapslockState::kTriggerAlt:
case CapslockState::kWaitingAlt: {
const bool is_meta_key = kMetaKeys.contains(event->key_code());
const bool is_alt_key = kAltKeys.contains(event->key_code());
if (event->type() == ui::EventType::kKeyReleased) {
if (is_meta_key) {
current_state_ = CapslockState::kStart;
break;
}
current_state_ = CapslockState::kSuppress;
break;
}
if (is_alt_key) {
current_state_ = CapslockState::kPrimed;
break;
}
if (is_meta_key) {
current_state_ = CapslockState::kWaitingAlt;
break;
}
current_state_ = CapslockState::kSuppress;
break;
}
case CapslockState::kTriggerSearch:
case CapslockState::kWaitingSearch: {
const bool is_meta_key = kMetaKeys.contains(event->key_code());
const bool is_alt_key = kAltKeys.contains(event->key_code());
if (event->type() == ui::EventType::kKeyReleased) {
if (is_alt_key) {
current_state_ = CapslockState::kStart;
break;
}
current_state_ = CapslockState::kSuppress;
break;
}
if (is_meta_key) {
current_state_ = CapslockState::kPrimed;
break;
}
if (is_alt_key) {
current_state_ = CapslockState::kWaitingSearch;
break;
}
current_state_ = CapslockState::kSuppress;
break;
}
case CapslockState::kSuppress:
if (!ui::OzonePlatform::GetInstance()
->GetInputController()
->AreAnyKeysPressed()) {
current_state_ = CapslockState::kStart;
}
break;
case CapslockState::kPrimed:
const bool is_meta = kMetaKeys.contains(event->key_code());
const bool is_alt = kAltKeys.contains(event->key_code());
if (!is_alt && !is_meta) {
current_state_ = CapslockState::kSuppress;
break;
}
if (event->type() == ui::EventType::kKeyPressed) {
break;
}
if (is_meta) {
current_state_ = CapslockState::kTriggerSearch;
break;
}
current_state_ = CapslockState::kTriggerAlt;
break;
}
}
void AcceleratorCapslockStateMachine::OnMouseEvent(ui::MouseEvent* event) {
if (event->type() != ui::EventType::kMousePressed &&
event->type() != ui::EventType::kMouseReleased) {
return;
}
switch (current_state_) {
case CapslockState::kStart:
case CapslockState::kWaitingAlt:
case CapslockState::kWaitingSearch:
case CapslockState::kTriggerAlt:
case CapslockState::kTriggerSearch:
case CapslockState::kPrimed:
if (event->type() == ui::EventType::kMousePressed) {
current_state_ = CapslockState::kSuppress;
}
break;
case CapslockState::kSuppress:
if (event->type() == ui::EventType::kMouseReleased &&
!ui::OzonePlatform::GetInstance()
->GetInputController()
->AreAnyKeysPressed()) {
current_state_ = CapslockState::kStart;
}
break;
}
}
void AcceleratorCapslockStateMachine::SetCanHandleCapsLockForTesting(
bool can_handle) {
current_state_ =
can_handle ? CapslockState::kTriggerAlt : CapslockState::kStart;
}
}