[Merge to M-73] Fix the bug that toggle CapsLock shortcut does not work after using
handwriting input

Handwriting/voice input or emoji generates fake pressing/releasing
key events. But pressing/releasing key events use different key code.
As result, the accelerator history fails to remove the fake pressing
event after receiving the fake releasing event.

In fact, key events with key code of ui::VKEY_PROCESSKEY have no effect
on accelerator processing. So in this CL, stop tracking those key events
in the accelerator history. Meanwhile, refactor the accelerator history
code.

TBR=sky@chromium.org

Test: ash_unittests
Bug: 918317
Change-Id: Iafdc5658c93fc029942dbdc20571558ed84a3eb3
Reviewed-on: https://chromium-review.googlesource.com/c/1427439
Commit-Queue: Andrew Xu <andrewxu@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#626832}(cherry picked from commit e1c534a395a54afc1ea6aa50a18531a80781b6ab)
Reviewed-on: https://chromium-review.googlesource.com/c/1443715
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/branch-heads/3683@{#101}
Cr-Branched-From: e51029943e0a38dd794b73caaf6373d5496ae783-refs/heads/master@{#625896}
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 3a81b1d..37192bae 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -945,7 +945,7 @@
 
 namespace {
 
-// Tests the four combinations of the TOGGLE_CAPS_LOCK accelerator.
+// Tests the TOGGLE_CAPS_LOCK accelerator.
 TEST_F(AcceleratorControllerTest, ToggleCapsLockAccelerators) {
   ImeController* controller = Shell::Get()->ime_controller();
 
@@ -1043,6 +1043,20 @@
     EXPECT_TRUE(controller->IsCapsLockEnabled());
     controller->UpdateCapsLockState(false);
   }
+
+  // 7. Toggle CapsLock shortcut should still work after fake events generated.
+  // (https://crbug.com/918317).
+  generator->PressKey(ui::VKEY_PROCESSKEY, ui::EF_IME_FABRICATED_KEY);
+  generator->ReleaseKey(ui::VKEY_UNKNOWN, ui::EF_IME_FABRICATED_KEY);
+
+  // Press Search, Press Alt, Release Search, Release Alt. CapsLock should be
+  // triggered.
+  EXPECT_FALSE(ProcessInController(press_search_then_alt));
+  EXPECT_TRUE(ProcessInController(release_search_before_alt));
+  controller->FlushMojoForTesting();
+  EXPECT_EQ(6, client.set_caps_lock_count_);
+  EXPECT_TRUE(controller->IsCapsLockEnabled());
+  controller->UpdateCapsLockState(false);
 }
 
 class PreferredReservedAcceleratorsTest : public AshTestBase {
diff --git a/ash/utility/screenshot_controller.cc b/ash/utility/screenshot_controller.cc
index ef07130..7941420 100644
--- a/ash/utility/screenshot_controller.cc
+++ b/ash/utility/screenshot_controller.cc
@@ -24,6 +24,7 @@
 #include "ui/events/event_handler.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/widget/widget.h"
+#include "ui/wm/core/accelerator_filter.h"
 #include "ui/wm/core/cursor_manager.h"
 
 namespace ash {
@@ -464,8 +465,7 @@
 
   // Key event is blocked. So have to record current accelerator here.
   if (event->stopped_propagation()) {
-    // Filter accelerators in the same way with AcceleratorFilter::OnKeyEvent.
-    if (event->is_char() || !event->target())
+    if (::wm::AcceleratorFilter::ShouldFilter(event))
       return;
 
     ui::Accelerator accelerator(*event);
diff --git a/ui/wm/core/accelerator_filter.cc b/ui/wm/core/accelerator_filter.cc
index 21f10d5..598b141 100644
--- a/ui/wm/core/accelerator_filter.cc
+++ b/ui/wm/core/accelerator_filter.cc
@@ -28,16 +28,29 @@
 AcceleratorFilter::~AcceleratorFilter() {
 }
 
+bool AcceleratorFilter::ShouldFilter(ui::KeyEvent* event) {
+  const ui::EventType type = event->type();
+  if (!event->target() ||
+      (type != ui::ET_KEY_PRESSED && type != ui::ET_KEY_RELEASED) ||
+      event->is_char() || !event->target() ||
+      // Key events with key code of VKEY_PROCESSKEY, usually created by virtual
+      // keyboard (like handwriting input), have no effect on accelerator and
+      // they may disturb the accelerator history. So filter them out. (see
+      // https://crbug.com/918317)
+      event->key_code() == ui::VKEY_PROCESSKEY) {
+    return true;
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // AcceleratorFilter, EventFilter implementation:
 
 void AcceleratorFilter::OnKeyEvent(ui::KeyEvent* event) {
-  const ui::EventType type = event->type();
   DCHECK(event->target());
-  if ((type != ui::ET_KEY_PRESSED && type != ui::ET_KEY_RELEASED) ||
-      event->is_char() || !event->target()) {
+  if (ShouldFilter(event))
     return;
-  }
 
   ui::Accelerator accelerator(*event);
   accelerator_history_->StoreCurrentAccelerator(accelerator);
diff --git a/ui/wm/core/accelerator_filter.h b/ui/wm/core/accelerator_filter.h
index 86bdf77..18f27645 100644
--- a/ui/wm/core/accelerator_filter.h
+++ b/ui/wm/core/accelerator_filter.h
@@ -28,6 +28,9 @@
                     ui::AcceleratorHistory* accelerator_history);
   ~AcceleratorFilter() override;
 
+  // If the return value is true, |event| should be filtered out.
+  static bool ShouldFilter(ui::KeyEvent* event);
+
   // Overridden from ui::EventHandler:
   void OnKeyEvent(ui::KeyEvent* event) override;
   void OnMouseEvent(ui::MouseEvent* event) override;