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

Side by Side Diff: native_client_sdk/src/examples/api/input_event/input_events.cc

Issue 14607005: [NaCl SDK] Cleanup examples. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: feedback Created 7 years, 7 months 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 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 // C headers
6 #include <cassert>
7 #include <cstdio>
8
9 // C++ headers
10 #include <sstream>
11 #include <string>
12
13 // PPAPI headers
14 #include "ppapi/cpp/completion_callback.h"
15 #include "ppapi/cpp/input_event.h"
16 #include "ppapi/cpp/instance.h"
17 #include "ppapi/cpp/module.h"
18 #include "ppapi/cpp/point.h"
19 #include "ppapi/cpp/var.h"
20 #include "ppapi/utility/completion_callback_factory.h"
21
22 #include "custom_events.h"
23 #include "shared_queue.h"
24
25 #ifdef PostMessage
26 #undef PostMessage
27 #endif
28
29 namespace event_queue {
30 const char* const kDidChangeView = "DidChangeView\n";
31 const char* const kHandleInputEvent = "DidHandleInputEvent\n";
32 const char* const kDidChangeFocus = "DidChangeFocus\n";
33 const char* const kHaveFocus = "HaveFocus\n";
34 const char* const kDontHaveFocus = "DontHaveFocus\n";
35 const char* const kCancelMessage = "CANCEL";
36
37 // Convert a pepper inputevent modifier value into a
38 // custom event modifier.
39 unsigned int ConvertEventModifier(uint32_t pp_modifier) {
40 unsigned int custom_modifier = 0;
41 if (pp_modifier & PP_INPUTEVENT_MODIFIER_SHIFTKEY) {
42 custom_modifier |= kShiftKeyModifier;
43 }
44 if (pp_modifier & PP_INPUTEVENT_MODIFIER_CONTROLKEY) {
45 custom_modifier |= kControlKeyModifier;
46 }
47 if (pp_modifier & PP_INPUTEVENT_MODIFIER_ALTKEY) {
48 custom_modifier |= kAltKeyModifier;
49 }
50 if (pp_modifier & PP_INPUTEVENT_MODIFIER_METAKEY) {
51 custom_modifier |= kMetaKeyModifer;
52 }
53 if (pp_modifier & PP_INPUTEVENT_MODIFIER_ISKEYPAD) {
54 custom_modifier |= kKeyPadModifier;
55 }
56 if (pp_modifier & PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT) {
57 custom_modifier |= kAutoRepeatModifier;
58 }
59 if (pp_modifier & PP_INPUTEVENT_MODIFIER_LEFTBUTTONDOWN) {
60 custom_modifier |= kLeftButtonModifier;
61 }
62 if (pp_modifier & PP_INPUTEVENT_MODIFIER_MIDDLEBUTTONDOWN) {
63 custom_modifier |= kMiddleButtonModifier;
64 }
65 if (pp_modifier & PP_INPUTEVENT_MODIFIER_RIGHTBUTTONDOWN) {
66 custom_modifier |= kRightButtonModifier;
67 }
68 if (pp_modifier & PP_INPUTEVENT_MODIFIER_CAPSLOCKKEY) {
69 custom_modifier |= kCapsLockModifier;
70 }
71 if (pp_modifier & PP_INPUTEVENT_MODIFIER_NUMLOCKKEY) {
72 custom_modifier |= kNumLockModifier;
73 }
74 return custom_modifier;
75 }
76
77 class EventInstance : public pp::Instance {
78 public:
79 explicit EventInstance(PP_Instance instance)
80 : pp::Instance(instance), event_thread_(NULL), callback_factory_(this) {
81 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL |
82 PP_INPUTEVENT_CLASS_TOUCH);
83 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
84 }
85
86 // Not guaranteed to be called in Pepper, but a good idea to cancel the
87 // queue and signal to workers to die if it is called.
88 virtual ~EventInstance() { CancelQueueAndWaitForWorker(); }
89
90 // Create the 'worker thread'.
91 bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
92 event_thread_ = new pthread_t;
93 pthread_create(event_thread_, NULL, ProcessEventOnWorkerThread, this);
94 return true;
95 }
96
97 /// Clicking outside of the instance's bounding box
98 /// will create a DidChangeFocus event (the NaCl instance is
99 /// out of focus). Clicking back inside the instance's
100 /// bounding box will create another DidChangeFocus event
101 /// (the NaCl instance is back in focus). The default is
102 /// that the instance is out of focus.
103 void DidChangeFocus(bool focus) {
104 PostMessage(pp::Var(kDidChangeFocus));
105 if (focus == true) {
106 PostMessage(pp::Var(kHaveFocus));
107 } else {
108 PostMessage(pp::Var(kDontHaveFocus));
109 }
110 }
111
112 /// Scrolling the mouse wheel causes a DidChangeView event.
113 void DidChangeView(const pp::View& view) {
114 PostMessage(pp::Var(kDidChangeView));
115 }
116
117 /// Called by the browser to handle the postMessage() call in Javascript.
118 /// Detects which method is being called from the message contents, and
119 /// calls the appropriate function. Posts the result back to the browser
120 /// asynchronously.
121 /// @param[in] var_message The message posted by the browser. The only
122 /// supported message is |kCancelMessage|. If we receive this, we
123 /// cancel the shared queue.
124 virtual void HandleMessage(const pp::Var& var_message) {
125 std::string message = var_message.AsString();
126 if (kCancelMessage == message) {
127 std::string reply =
128 "Received cancel : only Focus events will be "
129 "displayed. Worker thread for mouse/wheel/keyboard will exit.";
130 PostMessage(pp::Var(reply));
131 printf("Calling cancel queue\n");
132 CancelQueueAndWaitForWorker();
133 }
134 }
135
136 // HandleInputEvent operates on the main Pepper thread. Here we
137 // illustrate copying the Pepper input event to our own custom event type.
138 // Since we need to use Pepper API calls to convert it, we must do the
139 // conversion on the main thread. Once we have converted it to our own
140 // event type, we push that into a thread-safe queue and quickly return.
141 // The worker thread can process the custom event and do whatever
142 // (possibly slow) things it wants to do without making the browser
143 // become unresponsive.
144 // We dynamically allocate a sub-class of our custom event (Event)
145 // so that the queue can contain an Event*.
146 virtual bool HandleInputEvent(const pp::InputEvent& event) {
147 Event* event_ptr = NULL;
148 switch (event.GetType()) {
149 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_START:
150 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_UPDATE:
151 case PP_INPUTEVENT_TYPE_IME_COMPOSITION_END:
152 case PP_INPUTEVENT_TYPE_IME_TEXT:
153 // these cases are not handled...fall through below...
154 case PP_INPUTEVENT_TYPE_UNDEFINED:
155 break;
156 case PP_INPUTEVENT_TYPE_MOUSEDOWN:
157 case PP_INPUTEVENT_TYPE_MOUSEUP:
158 case PP_INPUTEVENT_TYPE_MOUSEMOVE:
159 case PP_INPUTEVENT_TYPE_MOUSEENTER:
160 case PP_INPUTEVENT_TYPE_MOUSELEAVE: {
161 pp::MouseInputEvent mouse_event(event);
162 PP_InputEvent_MouseButton pp_button = mouse_event.GetButton();
163 MouseEvent::MouseButton mouse_button = MouseEvent::kNone;
164 switch (pp_button) {
165 case PP_INPUTEVENT_MOUSEBUTTON_NONE:
166 mouse_button = MouseEvent::kNone;
167 break;
168 case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
169 mouse_button = MouseEvent::kLeft;
170 break;
171 case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE:
172 mouse_button = MouseEvent::kMiddle;
173 break;
174 case PP_INPUTEVENT_MOUSEBUTTON_RIGHT:
175 mouse_button = MouseEvent::kRight;
176 break;
177 }
178 event_ptr =
179 new MouseEvent(ConvertEventModifier(mouse_event.GetModifiers()),
180 mouse_button,
181 mouse_event.GetPosition().x(),
182 mouse_event.GetPosition().y(),
183 mouse_event.GetClickCount(),
184 mouse_event.GetTimeStamp());
185 } break;
186 case PP_INPUTEVENT_TYPE_WHEEL: {
187 pp::WheelInputEvent wheel_event(event);
188 event_ptr =
189 new WheelEvent(ConvertEventModifier(wheel_event.GetModifiers()),
190 wheel_event.GetDelta().x(),
191 wheel_event.GetDelta().y(),
192 wheel_event.GetTicks().x(),
193 wheel_event.GetTicks().y(),
194 wheel_event.GetScrollByPage(),
195 wheel_event.GetTimeStamp());
196 } break;
197 case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
198 case PP_INPUTEVENT_TYPE_KEYDOWN:
199 case PP_INPUTEVENT_TYPE_KEYUP:
200 case PP_INPUTEVENT_TYPE_CHAR:
201 case PP_INPUTEVENT_TYPE_CONTEXTMENU: {
202 pp::KeyboardInputEvent key_event(event);
203 event_ptr = new KeyEvent(ConvertEventModifier(key_event.GetModifiers()),
204 key_event.GetKeyCode(),
205 key_event.GetTimeStamp(),
206 key_event.GetCharacterText().DebugString());
207 } break;
208 case PP_INPUTEVENT_TYPE_TOUCHSTART:
209 case PP_INPUTEVENT_TYPE_TOUCHMOVE:
210 case PP_INPUTEVENT_TYPE_TOUCHEND:
211 case PP_INPUTEVENT_TYPE_TOUCHCANCEL: {
212 pp::TouchInputEvent touch_event(event);
213
214 TouchEvent::Kind touch_kind = TouchEvent::kNone;
215 if (event.GetType() == PP_INPUTEVENT_TYPE_TOUCHSTART)
216 touch_kind = TouchEvent::kStart;
217 else if (event.GetType() == PP_INPUTEVENT_TYPE_TOUCHMOVE)
218 touch_kind = TouchEvent::kMove;
219 else if (event.GetType() == PP_INPUTEVENT_TYPE_TOUCHEND)
220 touch_kind = TouchEvent::kEnd;
221 else if (event.GetType() == PP_INPUTEVENT_TYPE_TOUCHCANCEL)
222 touch_kind = TouchEvent::kCancel;
223
224 TouchEvent* touch_event_ptr =
225 new TouchEvent(ConvertEventModifier(touch_event.GetModifiers()),
226 touch_kind,
227 touch_event.GetTimeStamp());
228 event_ptr = touch_event_ptr;
229
230 uint32_t touch_count =
231 touch_event.GetTouchCount(PP_TOUCHLIST_TYPE_CHANGEDTOUCHES);
232 for (uint32_t i = 0; i < touch_count; ++i) {
233 pp::TouchPoint point =
234 touch_event.GetTouchByIndex(PP_TOUCHLIST_TYPE_CHANGEDTOUCHES, i);
235 touch_event_ptr->AddTouch(point.id(),
236 point.position().x(),
237 point.position().y(),
238 point.radii().x(),
239 point.radii().y(),
240 point.rotation_angle(),
241 point.pressure());
242 }
243 } break;
244 default: {
245 // For any unhandled events, send a message to the browser
246 // so that the user is aware of these and can investigate.
247 std::stringstream oss;
248 oss << "Default (unhandled) event, type=" << event.GetType();
249 PostMessage(oss.str());
250 } break;
251 }
252 event_queue_.Push(event_ptr);
253 return true;
254 }
255
256 // Return an event from the thread-safe queue, waiting for a new event
257 // to occur if the queue is empty. Set |was_queue_cancelled| to indicate
258 // whether the queue was cancelled. If it was cancelled, then the
259 // Event* will be NULL.
260 const Event* GetEventFromQueue(bool* was_queue_cancelled) {
261 Event* event = NULL;
262 QueueGetResult result = event_queue_.GetItem(&event, kWait);
263 if (result == kQueueWasCancelled) {
264 *was_queue_cancelled = true;
265 return NULL;
266 }
267 *was_queue_cancelled = false;
268 return event;
269 }
270
271 // This method is called from the worker thread using CallOnMainThread.
272 // It is not static, and allows PostMessage to be called.
273 void* PostStringToBrowser(int32_t result, std::string data_to_send) {
274 PostMessage(pp::Var(data_to_send));
275 return 0;
276 }
277
278 // |ProcessEventOnWorkerThread| is a static method that is run
279 // by a thread. It pulls events from the queue, converts
280 // them to a string, and calls CallOnMainThread so that
281 // PostStringToBrowser will be called, which will call PostMessage
282 // to send the converted event back to the browser.
283 static void* ProcessEventOnWorkerThread(void* param) {
284 EventInstance* event_instance = static_cast<EventInstance*>(param);
285 while (1) {
286 // Grab a generic Event* so that down below we can call
287 // event->ToString(), which will use the correct virtual method
288 // to convert the event to a string. This 'conversion' is
289 // the 'work' being done on the worker thread. In an application
290 // the work might involve changing application state based on
291 // the event that was processed.
292 bool queue_cancelled;
293 const Event* event = event_instance->GetEventFromQueue(&queue_cancelled);
294 if (queue_cancelled) {
295 printf("Queue was cancelled, worker thread exiting\n");
296 pthread_exit(NULL);
297 }
298 std::string event_string = event->ToString();
299 delete event;
300 // Need to invoke callback on main thread.
301 pp::Module::Get()->core()->CallOnMainThread(
302 0,
303 event_instance->callback_factory()
304 .NewCallback(&EventInstance::PostStringToBrowser, event_string));
305 } // end of while loop.
306 return 0;
307 }
308
309 // Return the callback factory.
310 // Allows the static method (ProcessEventOnWorkerThread) to use
311 // the |event_instance| pointer to get the factory.
312 pp::CompletionCallbackFactory<EventInstance>& callback_factory() {
313 return callback_factory_;
314 }
315
316 private:
317 // Cancels the queue (which will cause the thread to exit).
318 // Wait for the thread. Set |event_thread_| to NULL so we only
319 // execute the body once.
320 void CancelQueueAndWaitForWorker() {
321 if (event_thread_) {
322 event_queue_.CancelQueue();
323 pthread_join(*event_thread_, NULL);
324 delete event_thread_;
325 event_thread_ = NULL;
326 }
327 }
328 pthread_t* event_thread_;
329 LockingQueue<Event*> event_queue_;
330 pp::CompletionCallbackFactory<EventInstance> callback_factory_;
331 };
332
333 // The EventModule provides an implementation of pp::Module that creates
334 // EventInstance objects when invoked. This is part of the glue code that makes
335 // our example accessible to ppapi.
336 class EventModule : public pp::Module {
337 public:
338 EventModule() : pp::Module() {}
339 virtual ~EventModule() {}
340
341 virtual pp::Instance* CreateInstance(PP_Instance instance) {
342 return new EventInstance(instance);
343 }
344 };
345
346 } // namespace
347
348 // Implement the required pp::CreateModule function that creates our specific
349 // kind of Module (in this case, EventModule). This is part of the glue code
350 // that makes our example accessible to ppapi.
351 namespace pp {
352 Module* CreateModule() { return new event_queue::EventModule(); }
353 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698