OLD | NEW |
---|---|
(Empty) | |
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 "ui/chromeos/touch_exploration_controller.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "ui/aura/client/cursor_client.h" | |
9 #include "ui/aura/window.h" | |
10 #include "ui/aura/window_tree_host.h" | |
11 #include "ui/events/event.h" | |
12 | |
13 namespace ui { | |
14 | |
15 TouchExplorationController::TouchExplorationController( | |
16 aura::Window* root_window) | |
17 : root_window_(root_window) { | |
18 CHECK(root_window); | |
19 root_window->GetHost()->GetEventSource()->AddEventRewriter(this); | |
20 } | |
21 | |
22 TouchExplorationController::~TouchExplorationController() { | |
23 root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this); | |
24 } | |
25 | |
26 ui::EventRewriteStatus TouchExplorationController::RewriteEvent( | |
27 const ui::Event& event, | |
28 scoped_ptr<ui::Event>* rewritten_event) { | |
29 if (!event.IsTouchEvent()) | |
30 return ui::EVENT_REWRITE_CONTINUE; | |
31 | |
32 const ui::TouchEvent& touch_event = | |
33 static_cast<const ui::TouchEvent&>(event); | |
34 const ui::EventType type = touch_event.type(); | |
35 const gfx::Point location = touch_event.location(); | |
sadrul
2014/04/30 18:51:15
Use location_f() instead?
mfomitchev
2014/04/30 21:33:53
Done.
| |
36 const int touch_id = touch_event.touch_id(); | |
37 const int flags = touch_event.flags(); | |
38 | |
39 if (type == ui::ET_TOUCH_PRESSED) { | |
40 touch_ids_.push_back(touch_id); | |
41 touch_locations_.insert(std::pair<int, gfx::Point>(touch_id, location)); | |
42 // If this is the first and only finger touching - rewrite the touch as a | |
43 // mouse move. Otherwise let the it go through as is. | |
44 if (touch_ids_.size() == 1) { | |
45 rewritten_event->reset(CreateMouseMoveEvent(location, flags)); | |
46 EnterTouchToMouseMode(); | |
47 return ui::EVENT_REWRITE_REWRITTEN; | |
48 } else { | |
49 return ui::EVENT_REWRITE_CONTINUE; | |
50 } | |
51 } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) { | |
52 std::vector<int>::iterator it = | |
53 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); | |
54 // We may fail to find the finger if the exploration mode was turned on | |
55 // while the user had some fingers touching the screen. We simply ignore | |
56 // those fingers for the purposes of event transformation. | |
57 if (it == touch_ids_.end()) | |
58 return ui::EVENT_REWRITE_CONTINUE; | |
59 const bool first_finger_released = it == touch_ids_.begin(); | |
60 touch_ids_.erase(it); | |
61 int num_erased = touch_locations_.erase(touch_id); | |
62 DCHECK_EQ(num_erased, 1); | |
63 const int num_fingers_remaining = touch_ids_.size(); | |
64 | |
65 if (num_fingers_remaining == 0) { | |
66 rewritten_event->reset(CreateMouseMoveEvent(location, flags)); | |
67 return ui::EVENT_REWRITE_REWRITTEN; | |
68 } | |
69 | |
70 // If we are left with one finger - enter the mouse move mode. | |
71 const bool enter_mouse_move_mode = num_fingers_remaining == 1; | |
72 | |
73 if (!enter_mouse_move_mode && !first_finger_released) { | |
74 // No special handling needed. | |
75 return ui::EVENT_REWRITE_CONTINUE; | |
76 } | |
77 | |
78 // If the finger which was released was the first one, - we need to rewrite | |
79 // the release event as a release of the was second / now first finger. | |
80 // This is the finger which will now be getting "substracted". | |
81 if (first_finger_released) { | |
82 int rewritten_release_id = touch_ids_[0]; | |
83 gfx::Point rewritten_release_location = | |
84 touch_locations_[rewritten_release_id]; | |
85 ui::TouchEvent* rewritten_release_event = new ui::TouchEvent( | |
86 ui::ET_TOUCH_RELEASED, | |
87 rewritten_release_location, | |
88 rewritten_release_id, | |
89 event.time_stamp()); | |
90 rewritten_event->reset(rewritten_release_event); | |
91 } else if (enter_mouse_move_mode) { | |
92 // Dispatch the release event as is. | |
93 // TODO(mfomitchev): We can get rid of this clause once we have | |
94 // EVENT_REWRITE_DISPATCH_ANOTHER working without having to set | |
95 // rewritten_event. | |
96 rewritten_event->reset(new ui::TouchEvent(touch_event)); | |
97 } | |
98 | |
99 if (enter_mouse_move_mode) { | |
100 // Since we are entering the mouse move mode - also dispatch a mouse move | |
101 // event at the location of the one remaining finger. (num_fingers == 1) | |
102 gfx::Point mouse_move_location = touch_locations_[touch_ids_[0]]; | |
103 next_dispatch_event_.reset( | |
104 CreateMouseMoveEvent(mouse_move_location, flags)); | |
sadrul
2014/04/30 18:51:15
return DISPATCH_ANOTHER from here?
mfomitchev
2014/04/30 21:33:53
Done.
| |
105 } | |
106 | |
107 if (enter_mouse_move_mode) { | |
108 return ui::EVENT_REWRITE_DISPATCH_ANOTHER; | |
109 } else { // first_finger_released == true | |
110 return ui::EVENT_REWRITE_REWRITTEN; | |
111 } | |
112 } else if (type == ui::ET_TOUCH_MOVED) { | |
113 std::vector<int>::iterator it = | |
114 std::find(touch_ids_.begin(), touch_ids_.end(), touch_id); | |
115 // We may fail to find the finger if the exploration mode was turned on | |
116 // while the user had some fingers touching the screen. We simply ignore | |
117 // those fingers for the purposes of event transformation. | |
118 if (it == touch_ids_.end()) | |
119 return ui::EVENT_REWRITE_CONTINUE; | |
120 touch_locations_[*it] = location; | |
121 if (touch_ids_.size() == 1) { | |
122 // Touch moves are rewritten as mouse moves when there's only one finger | |
123 // touching the screen. | |
124 rewritten_event->reset(CreateMouseMoveEvent(location, flags)); | |
125 return ui::EVENT_REWRITE_REWRITTEN; | |
126 } else if (touch_id == touch_ids_.front()) { | |
127 // Touch moves of the first finger are discarded when there's more than | |
128 // one finger touching. | |
129 return ui::EVENT_REWRITE_DISCARD; | |
130 } else { | |
131 return ui::EVENT_REWRITE_CONTINUE; | |
132 } | |
133 } else if (type == ui::ET_TOUCH_STATIONARY) { | |
134 if (touch_id == touch_ids_.front()) | |
135 return ui::EVENT_REWRITE_DISCARD; | |
136 else | |
137 return ui::EVENT_REWRITE_CONTINUE; | |
138 } | |
139 NOTREACHED(); | |
140 return ui::EVENT_REWRITE_CONTINUE; | |
141 } | |
142 | |
143 ui::EventRewriteStatus TouchExplorationController::NextDispatchEvent( | |
144 const ui::Event& last_event, | |
145 scoped_ptr<ui::Event>* new_event) { | |
146 CHECK(next_dispatch_event_); | |
147 *new_event = next_dispatch_event_.Pass(); | |
148 // Enter the mouse move mode if needed | |
149 if ((*new_event)->IsMouseEvent()) | |
sadrul
2014/04/30 18:51:15
Should you also check if last_event.IsTouchEvent()
mfomitchev
2014/04/30 21:33:53
Hmm.. As it stands, RewriteEvent() returns EVENT_R
| |
150 EnterTouchToMouseMode(); | |
151 return ui::EVENT_REWRITE_REWRITTEN; | |
152 } | |
153 | |
154 ui::Event* TouchExplorationController::CreateMouseMoveEvent(gfx::Point location, | |
155 int flags) { | |
156 return new ui::MouseEvent(ui::ET_MOUSE_MOVED, | |
157 location, | |
158 location, | |
159 flags | ui::EF_IS_SYNTHESIZED | ui::EF_FROM_TOUCH, | |
160 0); | |
161 } | |
162 | |
163 void TouchExplorationController::EnterTouchToMouseMode() { | |
164 aura::client::CursorClient* cursor_client = | |
165 aura::client::GetCursorClient(root_window_); | |
166 if (cursor_client && !cursor_client->IsMouseEventsEnabled()) | |
167 cursor_client->EnableMouseEvents(); | |
168 if (cursor_client && cursor_client->IsCursorVisible()) | |
169 cursor_client->HideCursor(); | |
170 } | |
171 | |
172 } // namespace ui | |
OLD | NEW |