key_hold_detector.cc 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  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. #include "ash/accelerators/key_hold_detector.h"
  5. #include <tuple>
  6. #include <utility>
  7. #include "ash/shell.h"
  8. #include "base/bind.h"
  9. #include "base/threading/thread_task_runner_handle.h"
  10. #include "ui/aura/window_tracker.h"
  11. #include "ui/aura/window_tree_host.h"
  12. #include "ui/events/event_dispatcher.h"
  13. #include "ui/events/event_sink.h"
  14. namespace ash {
  15. namespace {
  16. void DispatchPressedEvent(const ui::KeyEvent& key_event,
  17. std::unique_ptr<aura::WindowTracker> tracker) {
  18. // The target window may be gone.
  19. if (tracker->windows().empty())
  20. return;
  21. ui::KeyEvent event(key_event);
  22. aura::Window* target = *(tracker->windows().begin());
  23. std::ignore = target->GetHost()->GetEventSink()->OnEventFromSource(&event);
  24. }
  25. void PostPressedEvent(ui::KeyEvent* event) {
  26. // Modify RELEASED event to PRESSED event.
  27. const ui::KeyEvent pressed_event(
  28. ui::ET_KEY_PRESSED, event->key_code(), event->code(),
  29. event->flags() | ui::EF_SHIFT_DOWN | ui::EF_IS_SYNTHESIZED);
  30. std::unique_ptr<aura::WindowTracker> tracker(new aura::WindowTracker);
  31. tracker->Add(static_cast<aura::Window*>(event->target()));
  32. base::ThreadTaskRunnerHandle::Get()->PostTask(
  33. FROM_HERE,
  34. base::BindOnce(&DispatchPressedEvent, pressed_event, std::move(tracker)));
  35. }
  36. } // namespace
  37. KeyHoldDetector::KeyHoldDetector(std::unique_ptr<Delegate> delegate)
  38. : state_(INITIAL), delegate_(std::move(delegate)) {}
  39. KeyHoldDetector::~KeyHoldDetector() = default;
  40. void KeyHoldDetector::OnKeyEvent(ui::KeyEvent* event) {
  41. if (!delegate_->ShouldProcessEvent(event))
  42. return;
  43. if (delegate_->IsStartEvent(event)) {
  44. switch (state_) {
  45. case INITIAL:
  46. // Pass through posted event.
  47. if (event->flags() & ui::EF_IS_SYNTHESIZED) {
  48. event->set_flags(event->flags() & ~ui::EF_IS_SYNTHESIZED);
  49. return;
  50. }
  51. state_ = PRESSED;
  52. if (delegate_->ShouldStopEventPropagation()) {
  53. // Don't process ET_KEY_PRESSED event yet. The ET_KEY_PRESSED
  54. // event will be generated upon ET_KEY_RELEASEED event below.
  55. event->StopPropagation();
  56. }
  57. break;
  58. case PRESSED:
  59. state_ = HOLD;
  60. [[fallthrough]];
  61. case HOLD:
  62. delegate_->OnKeyHold(event);
  63. if (delegate_->ShouldStopEventPropagation())
  64. event->StopPropagation();
  65. break;
  66. }
  67. } else if (event->type() == ui::ET_KEY_RELEASED) {
  68. switch (state_) {
  69. case INITIAL:
  70. break;
  71. case PRESSED: {
  72. if (delegate_->ShouldStopEventPropagation()) {
  73. PostPressedEvent(event);
  74. event->StopPropagation();
  75. }
  76. break;
  77. }
  78. case HOLD: {
  79. delegate_->OnKeyUnhold(event);
  80. if (delegate_->ShouldStopEventPropagation())
  81. event->StopPropagation();
  82. break;
  83. }
  84. }
  85. state_ = INITIAL;
  86. }
  87. }
  88. } // namespace ash