Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: ash/wm/sticky_keys.cc

Issue 118543002: Move sticky keys files to their own directory and rename to StickyKeysController. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: update ash.gyp Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ash/wm/sticky_keys.h ('k') | ash/wm/sticky_keys_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 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/wm/sticky_keys.h"
6
7 #if defined(USE_X11)
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xlib.h>
10 #undef RootWindow
11 #endif
12
13 #include "base/basictypes.h"
14 #include "base/debug/stack_trace.h"
15 #include "ui/aura/root_window.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_tracker.h"
18 #include "ui/events/event.h"
19 #include "ui/events/keycodes/keyboard_code_conversion.h"
20
21 namespace ash {
22
23 namespace {
24
25 // Returns true if the type of mouse event should be modified by sticky keys.
26 bool ShouldModifyMouseEvent(ui::MouseEvent* event) {
27 ui::EventType type = event->type();
28 return type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED ||
29 type == ui::ET_MOUSEWHEEL;
30 }
31
32 // An implementation of StickyKeysHandler::StickyKeysHandlerDelegate.
33 class StickyKeysHandlerDelegateImpl :
34 public StickyKeysHandler::StickyKeysHandlerDelegate {
35 public:
36 StickyKeysHandlerDelegateImpl();
37 virtual ~StickyKeysHandlerDelegateImpl();
38
39 // StickyKeysHandlerDelegate overrides.
40 virtual void DispatchKeyEvent(ui::KeyEvent* event,
41 aura::Window* target) OVERRIDE;
42
43 virtual void DispatchMouseEvent(ui::MouseEvent* event,
44 aura::Window* target) OVERRIDE;
45
46 virtual void DispatchScrollEvent(ui::ScrollEvent* event,
47 aura::Window* target) OVERRIDE;
48 private:
49 DISALLOW_COPY_AND_ASSIGN(StickyKeysHandlerDelegateImpl);
50 };
51
52 StickyKeysHandlerDelegateImpl::StickyKeysHandlerDelegateImpl() {
53 }
54
55 StickyKeysHandlerDelegateImpl::~StickyKeysHandlerDelegateImpl() {
56 }
57
58 void StickyKeysHandlerDelegateImpl::DispatchKeyEvent(ui::KeyEvent* event,
59 aura::Window* target) {
60 DCHECK(target);
61 target->GetDispatcher()->AsRootWindowHostDelegate()->OnHostKeyEvent(event);
62 }
63
64 void StickyKeysHandlerDelegateImpl::DispatchMouseEvent(ui::MouseEvent* event,
65 aura::Window* target) {
66 DCHECK(target);
67 // We need to send a new, untransformed mouse event to the host.
68 if (event->IsMouseWheelEvent()) {
69 ui::MouseWheelEvent new_event(*static_cast<ui::MouseWheelEvent*>(event));
70 target->GetDispatcher()->AsRootWindowHostDelegate()
71 ->OnHostMouseEvent(&new_event);
72 } else {
73 ui::MouseEvent new_event(*event, target, target->GetRootWindow());
74 target->GetDispatcher()->AsRootWindowHostDelegate()
75 ->OnHostMouseEvent(&new_event);
76 }
77 }
78
79 void StickyKeysHandlerDelegateImpl::DispatchScrollEvent(
80 ui::ScrollEvent* event,
81 aura::Window* target) {
82 DCHECK(target);
83 target->GetDispatcher()->AsRootWindowHostDelegate()
84 ->OnHostScrollEvent(event);
85 }
86
87 } // namespace
88
89 ///////////////////////////////////////////////////////////////////////////////
90 // StickyKeys
91 StickyKeys::StickyKeys()
92 : enabled_(false),
93 shift_sticky_key_(
94 new StickyKeysHandler(ui::EF_SHIFT_DOWN,
95 new StickyKeysHandlerDelegateImpl())),
96 alt_sticky_key_(
97 new StickyKeysHandler(ui::EF_ALT_DOWN,
98 new StickyKeysHandlerDelegateImpl())),
99 ctrl_sticky_key_(
100 new StickyKeysHandler(ui::EF_CONTROL_DOWN,
101 new StickyKeysHandlerDelegateImpl())) {
102 }
103
104 StickyKeys::~StickyKeys() {
105 }
106
107 void StickyKeys::Enable(bool enabled) {
108 if (enabled_ != enabled) {
109 enabled_ = enabled;
110
111 // Reset key handlers when activating sticky keys to ensure all
112 // the handlers' states are reset.
113 if (enabled_) {
114 shift_sticky_key_.reset(
115 new StickyKeysHandler(ui::EF_SHIFT_DOWN,
116 new StickyKeysHandlerDelegateImpl()));
117 alt_sticky_key_.reset(
118 new StickyKeysHandler(ui::EF_ALT_DOWN,
119 new StickyKeysHandlerDelegateImpl()));
120 ctrl_sticky_key_.reset(
121 new StickyKeysHandler(ui::EF_CONTROL_DOWN,
122 new StickyKeysHandlerDelegateImpl()));
123 }
124 }
125 }
126
127 bool StickyKeys::HandleKeyEvent(ui::KeyEvent* event) {
128 return shift_sticky_key_->HandleKeyEvent(event) ||
129 alt_sticky_key_->HandleKeyEvent(event) ||
130 ctrl_sticky_key_->HandleKeyEvent(event);
131 return ctrl_sticky_key_->HandleKeyEvent(event);
132 }
133
134 bool StickyKeys::HandleMouseEvent(ui::MouseEvent* event) {
135 return shift_sticky_key_->HandleMouseEvent(event) ||
136 alt_sticky_key_->HandleMouseEvent(event) ||
137 ctrl_sticky_key_->HandleMouseEvent(event);
138 }
139
140 bool StickyKeys::HandleScrollEvent(ui::ScrollEvent* event) {
141 return shift_sticky_key_->HandleScrollEvent(event) ||
142 alt_sticky_key_->HandleScrollEvent(event) ||
143 ctrl_sticky_key_->HandleScrollEvent(event);
144 }
145
146 void StickyKeys::OnKeyEvent(ui::KeyEvent* event) {
147 // Do not consume a translated key event which is generated by an IME.
148 if (event->type() == ui::ET_TRANSLATED_KEY_PRESS ||
149 event->type() == ui::ET_TRANSLATED_KEY_RELEASE) {
150 return;
151 }
152
153 if (enabled_ && HandleKeyEvent(event))
154 event->StopPropagation();
155 }
156
157 void StickyKeys::OnMouseEvent(ui::MouseEvent* event) {
158 if (enabled_ && HandleMouseEvent(event))
159 event->StopPropagation();
160 }
161
162 void StickyKeys::OnScrollEvent(ui::ScrollEvent* event) {
163 if (enabled_ && HandleScrollEvent(event))
164 event->StopPropagation();
165 }
166
167 ///////////////////////////////////////////////////////////////////////////////
168 // StickyKeysHandler
169 StickyKeysHandler::StickyKeysHandler(ui::EventFlags target_modifier_flag,
170 StickyKeysHandlerDelegate* delegate)
171 : modifier_flag_(target_modifier_flag),
172 current_state_(DISABLED),
173 event_from_myself_(false),
174 preparing_to_enable_(false),
175 scroll_delta_(0),
176 delegate_(delegate) {
177 }
178
179 StickyKeysHandler::~StickyKeysHandler() {
180 }
181
182 StickyKeysHandler::StickyKeysHandlerDelegate::StickyKeysHandlerDelegate() {
183 }
184
185 StickyKeysHandler::StickyKeysHandlerDelegate::~StickyKeysHandlerDelegate() {
186 }
187
188 bool StickyKeysHandler::HandleKeyEvent(ui::KeyEvent* event) {
189 if (event_from_myself_)
190 return false; // Do not handle self-generated key event.
191 switch (current_state_) {
192 case DISABLED:
193 return HandleDisabledState(event);
194 case ENABLED:
195 return HandleEnabledState(event);
196 case LOCKED:
197 return HandleLockedState(event);
198 }
199 NOTREACHED();
200 return false;
201 }
202
203 bool StickyKeysHandler::HandleMouseEvent(ui::MouseEvent* event) {
204 preparing_to_enable_ = false;
205 if (event_from_myself_ || current_state_ == DISABLED
206 || !ShouldModifyMouseEvent(event)) {
207 return false;
208 }
209 DCHECK(current_state_ == ENABLED || current_state_ == LOCKED);
210
211 AppendModifier(event);
212 // Only disable on the mouse released event in normal, non-locked mode.
213 if (current_state_ == ENABLED && event->type() != ui::ET_MOUSE_PRESSED) {
214 current_state_ = DISABLED;
215 DispatchEventAndReleaseModifier(event);
216 return true;
217 }
218
219 return false;
220 }
221
222 bool StickyKeysHandler::HandleScrollEvent(ui::ScrollEvent* event) {
223 preparing_to_enable_ = false;
224 if (event_from_myself_ || current_state_ == DISABLED)
225 return false;
226 DCHECK(current_state_ == ENABLED || current_state_ == LOCKED);
227
228 // We detect a direction change if the current |scroll_delta_| is assigned
229 // and the offset of the current scroll event has the opposing sign.
230 bool direction_changed = false;
231 if (current_state_ == ENABLED && event->type() == ui::ET_SCROLL) {
232 int offset = event->y_offset();
233 if (scroll_delta_)
234 direction_changed = offset * scroll_delta_ <= 0;
235 scroll_delta_ = offset;
236 }
237
238 if (!direction_changed)
239 AppendModifier(event);
240
241 // We want to modify all the scroll events in the scroll sequence, which ends
242 // with a fling start event. We also stop when the scroll sequence changes
243 // direction.
244 if (current_state_ == ENABLED &&
245 (event->type() == ui::ET_SCROLL_FLING_START || direction_changed)) {
246 current_state_ = DISABLED;
247 scroll_delta_ = 0;
248 DispatchEventAndReleaseModifier(event);
249 return true;
250 }
251
252 return false;
253 }
254
255 StickyKeysHandler::KeyEventType
256 StickyKeysHandler::TranslateKeyEvent(ui::KeyEvent* event) {
257 bool is_target_key = false;
258 if (event->key_code() == ui::VKEY_SHIFT ||
259 event->key_code() == ui::VKEY_LSHIFT ||
260 event->key_code() == ui::VKEY_RSHIFT) {
261 is_target_key = (modifier_flag_ == ui::EF_SHIFT_DOWN);
262 } else if (event->key_code() == ui::VKEY_CONTROL ||
263 event->key_code() == ui::VKEY_LCONTROL ||
264 event->key_code() == ui::VKEY_RCONTROL) {
265 is_target_key = (modifier_flag_ == ui::EF_CONTROL_DOWN);
266 } else if (event->key_code() == ui::VKEY_MENU ||
267 event->key_code() == ui::VKEY_LMENU ||
268 event->key_code() == ui::VKEY_RMENU) {
269 is_target_key = (modifier_flag_ == ui::EF_ALT_DOWN);
270 } else {
271 return event->type() == ui::ET_KEY_PRESSED ?
272 NORMAL_KEY_DOWN : NORMAL_KEY_UP;
273 }
274
275 if (is_target_key) {
276 return event->type() == ui::ET_KEY_PRESSED ?
277 TARGET_MODIFIER_DOWN : TARGET_MODIFIER_UP;
278 }
279 return event->type() == ui::ET_KEY_PRESSED ?
280 OTHER_MODIFIER_DOWN : OTHER_MODIFIER_UP;
281 }
282
283 bool StickyKeysHandler::HandleDisabledState(ui::KeyEvent* event) {
284 switch (TranslateKeyEvent(event)) {
285 case TARGET_MODIFIER_UP:
286 if (preparing_to_enable_) {
287 preparing_to_enable_ = false;
288 scroll_delta_ = 0;
289 current_state_ = ENABLED;
290 modifier_up_event_.reset(new ui::KeyEvent(*event));
291 return true;
292 }
293 return false;
294 case TARGET_MODIFIER_DOWN:
295 preparing_to_enable_ = true;
296 return false;
297 case NORMAL_KEY_DOWN:
298 preparing_to_enable_ = false;
299 return false;
300 case NORMAL_KEY_UP:
301 case OTHER_MODIFIER_DOWN:
302 case OTHER_MODIFIER_UP:
303 return false;
304 }
305 NOTREACHED();
306 return false;
307 }
308
309 bool StickyKeysHandler::HandleEnabledState(ui::KeyEvent* event) {
310 switch (TranslateKeyEvent(event)) {
311 case NORMAL_KEY_UP:
312 case TARGET_MODIFIER_DOWN:
313 return true;
314 case TARGET_MODIFIER_UP:
315 current_state_ = LOCKED;
316 modifier_up_event_.reset();
317 return true;
318 case NORMAL_KEY_DOWN: {
319 current_state_ = DISABLED;
320 AppendModifier(event);
321 DispatchEventAndReleaseModifier(event);
322 return true;
323 }
324 case OTHER_MODIFIER_DOWN:
325 case OTHER_MODIFIER_UP:
326 return false;
327 }
328 NOTREACHED();
329 return false;
330 }
331
332 bool StickyKeysHandler::HandleLockedState(ui::KeyEvent* event) {
333 switch (TranslateKeyEvent(event)) {
334 case TARGET_MODIFIER_DOWN:
335 return true;
336 case TARGET_MODIFIER_UP:
337 current_state_ = DISABLED;
338 return false;
339 case NORMAL_KEY_DOWN:
340 case NORMAL_KEY_UP:
341 AppendModifier(event);
342 return false;
343 case OTHER_MODIFIER_DOWN:
344 case OTHER_MODIFIER_UP:
345 return false;
346 }
347 NOTREACHED();
348 return false;
349 }
350
351 void StickyKeysHandler::DispatchEventAndReleaseModifier(ui::Event* event) {
352 DCHECK(event->IsKeyEvent() ||
353 event->IsMouseEvent() ||
354 event->IsScrollEvent());
355 DCHECK(modifier_up_event_.get());
356 aura::Window* target = static_cast<aura::Window*>(event->target());
357 DCHECK(target);
358 aura::Window* root_window = target->GetRootWindow();
359 DCHECK(root_window);
360
361 aura::WindowTracker window_tracker;
362 window_tracker.Add(target);
363
364 event_from_myself_ = true;
365 if (event->IsKeyEvent()) {
366 delegate_->DispatchKeyEvent(static_cast<ui::KeyEvent*>(event), target);
367 } else if (event->IsMouseEvent()) {
368 delegate_->DispatchMouseEvent(static_cast<ui::MouseEvent*>(event), target);
369 } else {
370 delegate_->DispatchScrollEvent(
371 static_cast<ui::ScrollEvent*>(event), target);
372 }
373
374 // The action triggered above may have destroyed the event target, in which
375 // case we will dispatch the modifier up event to the root window instead.
376 aura::Window* modifier_up_target =
377 window_tracker.Contains(target) ? target : root_window;
378 delegate_->DispatchKeyEvent(modifier_up_event_.get(), modifier_up_target);
379 event_from_myself_ = false;
380 }
381
382 void StickyKeysHandler::AppendNativeEventMask(unsigned int* state) {
383 unsigned int& state_ref = *state;
384 switch (modifier_flag_) {
385 case ui::EF_CONTROL_DOWN:
386 state_ref |= ControlMask;
387 break;
388 case ui::EF_ALT_DOWN:
389 state_ref |= Mod1Mask;
390 break;
391 case ui::EF_SHIFT_DOWN:
392 state_ref |= ShiftMask;
393 break;
394 default:
395 NOTREACHED();
396 }
397 }
398
399 void StickyKeysHandler::AppendModifier(ui::KeyEvent* event) {
400 #if defined(USE_X11)
401 XEvent* xev = event->native_event();
402 if (xev) {
403 XKeyEvent* xkey = &(xev->xkey);
404 AppendNativeEventMask(&xkey->state);
405 }
406 #elif defined(USE_OZONE)
407 NOTIMPLEMENTED() << "Modifier key is not handled";
408 #endif
409 event->set_flags(event->flags() | modifier_flag_);
410 event->set_character(ui::GetCharacterFromKeyCode(event->key_code(),
411 event->flags()));
412 event->NormalizeFlags();
413 }
414
415 void StickyKeysHandler::AppendModifier(ui::MouseEvent* event) {
416 #if defined(USE_X11)
417 XEvent* xev = event->native_event();
418 if (xev) {
419 XButtonEvent* xkey = &(xev->xbutton);
420 AppendNativeEventMask(&xkey->state);
421 }
422 #elif defined(USE_OZONE)
423 NOTIMPLEMENTED() << "Modifier key is not handled";
424 #endif
425 event->set_flags(event->flags() | modifier_flag_);
426 }
427
428 void StickyKeysHandler::AppendModifier(ui::ScrollEvent* event) {
429 #if defined(USE_X11)
430 XEvent* xev = event->native_event();
431 if (xev) {
432 XIDeviceEvent* xievent =
433 static_cast<XIDeviceEvent*>(xev->xcookie.data);
434 if (xievent) {
435 AppendNativeEventMask(reinterpret_cast<unsigned int*>(
436 &xievent->mods.effective));
437 }
438 }
439 #elif defined(USE_OZONE)
440 NOTIMPLEMENTED() << "Modifier key is not handled";
441 #endif
442 event->set_flags(event->flags() | modifier_flag_);
443 }
444
445 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/sticky_keys.h ('k') | ash/wm/sticky_keys_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698