Home | History | Annotate | Download | only in accelerators
      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, false);
     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
    100