Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ash / accelerators / key_hold_detector.cc
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
5 #include "ash/accelerators/key_hold_detector.h"
6
7 #include <X11/Xlib.h>
8
9 #undef RootWindow
10 #undef Status
11
12 #include "ash/shell.h"
13 #include "base/message_loop/message_loop.h"
14 #include "ui/aura/window_tracker.h"
15 #include "ui/aura/window_tree_host.h"
16 #include "ui/events/event_dispatcher.h"
17 #include "ui/events/event_processor.h"
18
19 namespace ash {
20 namespace {
21
22 void DispatchPressedEvent(const ui::KeyEvent& key_event,
23                           scoped_ptr<aura::WindowTracker> tracker) {
24   // The target window may be gone.
25   if (tracker->windows().empty())
26     return;
27   ui::KeyEvent event(key_event);
28   aura::Window* target = *(tracker->windows().begin());
29   ui::EventDispatchDetails result ALLOW_UNUSED =
30       target->GetHost()->event_processor()->OnEventFromSource(&event);
31 }
32
33 void PostPressedEvent(ui::KeyEvent* event) {
34   // Modify RELEASED event to PRESSED event.
35   const ui::KeyEvent pressed_event(
36       ui::ET_KEY_PRESSED,
37       event->key_code(),
38       event->code(),
39       event->flags() | ui::EF_SHIFT_DOWN | ui::EF_IS_SYNTHESIZED);
40   scoped_ptr<aura::WindowTracker> tracker(new aura::WindowTracker);
41   tracker->Add(static_cast<aura::Window*>(event->target()));
42
43   base::MessageLoopForUI::current()->PostTask(
44       FROM_HERE,
45       base::Bind(&DispatchPressedEvent, pressed_event, base::Passed(&tracker)));
46 }
47
48 }  // namespace
49
50 KeyHoldDetector::KeyHoldDetector(scoped_ptr<Delegate> delegate)
51     : state_(INITIAL),
52       delegate_(delegate.Pass()) {}
53
54 KeyHoldDetector::~KeyHoldDetector() {}
55
56 void KeyHoldDetector::OnKeyEvent(ui::KeyEvent* event) {
57   if (!delegate_->ShouldProcessEvent(event))
58     return;
59
60   if (delegate_->IsStartEvent(event)) {
61     switch (state_) {
62       case INITIAL:
63         // Pass through posted event.
64         if (event->flags() & ui::EF_IS_SYNTHESIZED) {
65           event->set_flags(event->flags() & ~ui::EF_IS_SYNTHESIZED);
66           return;
67         }
68         state_ = PRESSED;
69         // Don't process ET_KEY_PRESSED event yet. The ET_KEY_PRESSED
70         // event will be generated upon ET_KEY_RELEASEED event below.
71         event->StopPropagation();
72         break;
73       case PRESSED:
74         state_ = HOLD;
75         // pass through
76       case HOLD:
77         delegate_->OnKeyHold(event);
78         event->StopPropagation();
79         break;
80       }
81   } else if (event->type() == ui::ET_KEY_RELEASED) {
82     switch (state_) {
83       case INITIAL:
84         break;
85       case PRESSED: {
86         PostPressedEvent(event);
87         event->StopPropagation();
88         break;
89       }
90       case HOLD: {
91         delegate_->OnKeyUnhold(event);
92         event->StopPropagation();
93         break;
94       }
95     }
96     state_ = INITIAL;
97   }
98 }
99
100 }  // namespace ash