131568eaf6414f42c44375293fcf85a584d078a0
[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(XEvent native_event,
23                           scoped_ptr<aura::WindowTracker> tracker) {
24   // The target window may be gone.
25   if (tracker->windows().empty())
26     return;
27   aura::Window* target = *(tracker->windows().begin());
28   ui::KeyEvent event(&native_event);
29   event.set_flags(event.flags() | ui::EF_IS_SYNTHESIZED);
30   ui::EventDispatchDetails result ALLOW_UNUSED =
31       target->GetHost()->event_processor()->OnEventFromSource(&event);
32 }
33
34 void PostPressedEvent(ui::KeyEvent* event) {
35   // Modify RELEASED event to PRESSED event.
36   XEvent xkey = *(event->native_event());
37   xkey.xkey.type = KeyPress;
38   xkey.xkey.state |= ShiftMask;
39   scoped_ptr<aura::WindowTracker> tracker(new aura::WindowTracker);
40   tracker->Add(static_cast<aura::Window*>(event->target()));
41
42   base::MessageLoopForUI::current()->PostTask(
43       FROM_HERE,
44       base::Bind(&DispatchPressedEvent, xkey, base::Passed(&tracker)));
45 }
46
47 }  // namespace
48
49 KeyHoldDetector::KeyHoldDetector(scoped_ptr<Delegate> delegate)
50     : state_(INITIAL),
51       delegate_(delegate.Pass()) {}
52
53 KeyHoldDetector::~KeyHoldDetector() {}
54
55 void KeyHoldDetector::OnKeyEvent(ui::KeyEvent* event) {
56   if (!delegate_->ShouldProcessEvent(event))
57     return;
58
59   if (delegate_->IsStartEvent(event)) {
60     switch (state_) {
61       case INITIAL:
62         // Pass through posted event.
63         if (event->flags() & ui::EF_IS_SYNTHESIZED) {
64           event->set_flags(event->flags() & ~ui::EF_IS_SYNTHESIZED);
65           return;
66         }
67         state_ = PRESSED;
68         // Don't process ET_KEY_PRESSED event yet. The ET_KEY_PRESSED
69         // event will be generated upon ET_KEY_RELEASEED event below.
70         event->StopPropagation();
71         break;
72       case PRESSED:
73         state_ = HOLD;
74         // pass through
75       case HOLD:
76         delegate_->OnKeyHold(event);
77         event->StopPropagation();
78         break;
79       }
80   } else if (event->type() == ui::ET_KEY_RELEASED) {
81     switch (state_) {
82       case INITIAL:
83         break;
84       case PRESSED: {
85         PostPressedEvent(event);
86         event->StopPropagation();
87         break;
88       }
89       case HOLD: {
90         delegate_->OnKeyUnhold(event);
91         event->StopPropagation();
92         break;
93       }
94     }
95     state_ = INITIAL;
96   }
97 }
98
99 }  // namespace ash