1 .. _view_focus_input_events:
3 ####################################
4 View Change, Focus, and Input Events
5 ####################################
12 This chapter describes view change, focus, and input event handling for a
13 Native Client module. The chapter assumes you are familiar with the
14 material presented in the :doc:`Technical Overview <../../overview>`.
16 There are two examples used in this chapter to illustrate basic
17 programming techniques. The ``input_events`` example is used to
18 illustrate how your module can react to keyboard and mouse input
19 event. The ``mouse_lock`` example is used to illustrate how your module
20 can react to view change events. You can find these examples in the
21 ``/examples/api/input_events`` and ``/examples/api/mouse_lock``
22 directories in the Native Client SDK. There is also the
23 ppapi_simple library that can be used to to implement most of the
24 boiler plate. The ``pi_generator`` example in
25 ``/examples/demo/pi_generator`` uses ppapi_simple to manage view
26 change events and 2D graphics.
32 When a user interacts with the web page using a keyboard, mouse or
33 some other input device, the browser generates input events.
34 In a traditional web application, these input events are
35 passed to and handled in JavaScript, typically through event listeners
36 and event handlers. In a Native Client application, user interaction
37 with an instance of a module (e.g., clicking inside the rectangle
38 managed by a module) also generates input events, which are passed to
39 the module. The browser also passes view change and focus events that
40 affect a module's instance to the module. Native Client modules can
41 override certain functions in the `pp::Instance
42 <https://developers.google.com/native-client/peppercpp/classpp_1_1_instance>`_
43 class to handle input and browser events. These functions are listed in
47 ====================== =============================== ====================
49 ====================== =============================== ====================
50 ``DidChangeView`` Called when the position, An implementation
51 size, or clip rectangle of this function
52 of the module's instance in might check the size
53 the browser has changed. of the module
54 This event also occurs instance's rectangle
55 when browser window is has changed and
56 resized or mouse wheel reallocate the
57 is scrolled. graphics context
61 ``DidChangeFocus`` Called when the module's An implementation
62 instance in the browser of this function
63 has gone in or out of might start or stop
64 focus (usually by an animation or a
65 clicking inside or blinking cursor.
67 instance). Having focus
69 events will be sent to
75 ``HandleDocumentLoad`` Called after This API is only
76 ``pp::Instance::Init()`` applicable when you
77 for a full-frame module are writing an
78 instance that was extension to enhance
79 instantiated based on the abilities of
80 the MIME type of a the Chrome web
81 DOMWindow navigation. browser. For
82 This situation only example, a PDF
83 applies to modules that viewer might
84 are pre-registered to implement this
85 handle certain MIME function to download
86 types. If you haven't and display a PDF
87 specifically registered file.
88 to handle a MIME type or
91 implementation of this
92 function can just return
95 ``HandleInputEvent`` Called when a user An implementation of
96 interacts with the this function
97 module's instance in the examines the input
98 browser using an input event type and
99 device such as a mouse branches accordingly.
100 or keyboard. You must
101 register your module to
104 ``RequestInputEvents()``
106 ``RequestFilteringInputEvents``
108 prior to overriding this
110 ====================== =============================== ====================
113 These interfaces are found in the `pp::Instance class
114 <https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_instance>`_.
115 The sections below provide examples of how to handle these events.
118 Handling browser events
119 =======================
124 In the ``mouse_lock`` example, ``DidChangeView()`` checks the previous size
125 of instance's rectangle versus the new size. It also compares
126 other state such as whether or not the app is running in full screen mode.
127 If none of the state has actually changed, no action is needed.
128 However, if the size of the view or other state has changed, it frees the
129 old graphics context and allocates a new one.
133 void MouseLockInstance::DidChangeView(const pp::View& view) {
134 // DidChangeView can get called for many reasons, so we only want to
135 // rebuild the device context if we really need to.
136 if ((size_ == view.GetRect().size()) &&
137 (was_fullscreen_ == view.IsFullscreen()) && is_context_bound_) {
143 // Reallocate the graphics context.
144 size_ = view.GetRect().size();
145 device_context_ = pp::Graphics2D(this, size_, false);
146 waiting_for_flush_completion_ = false;
148 is_context_bound_ = BindGraphics(device_context_);
151 // Remember if we are fullscreen or not
152 was_fullscreen_ = view.IsFullscreen();
157 For more information about graphics contexts and how to manipulate images, see:
159 * `pp::ImageData class <https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_image_data>`_
160 * `pp::Graphics2D class <https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_graphics2_d>`_
166 ``DidChangeFocus()`` is called when you click inside or outside of a
167 module's instance in the web page. When the instance goes out
168 of focus (click outside of the instance), you might do something
169 like stop an animation. When the instance regains focus, you can
170 restart the animation.
174 void DidChangeFocus(bool focus) {
175 // Do something like stopping animation or a blinking cursor in
180 Handling input events
181 =====================
183 Input events are events that occur when the user interacts with a
184 module instance using the mouse, keyboard, or other input device
185 (e.g., touch screen). This section describes how the ``input_events``
186 example handles input events.
189 Registering a module to accept input events
190 -------------------------------------------
192 Before your module can handle these events, you must register your
193 module to accept input events using ``RequestInputEvents()`` for mouse
194 events and ``RequestFilteringInputEvents()`` for keyboard events. For the
195 ``input_events`` example, this is done in the constructor of the
196 ``InputEventInstance`` class:
200 class InputEventInstance : public pp::Instance {
202 explicit InputEventInstance(PP_Instance instance)
203 : pp::Instance(instance), event_thread_(NULL), callback_factory_(this) {
204 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL |
205 PP_INPUTEVENT_CLASS_TOUCH);
206 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
212 ``RequestInputEvents()`` and ``RequestFilteringInputEvents()`` accept a
213 combination of flags that identify the class of events that the
214 instance is requesting to receive. Input event classes are defined in
215 the `PP_InputEvent_Class
216 <https://developers.google.com/native-client/dev/pepperc/group___enums.html#gafe68e3c1031daa4a6496845ff47649cd>`_
217 enumeration in `ppb_input_event.h
218 <https://developers.google.com/native-client/dev/pepperc/ppb__input__event_8h>`_.
221 Determining and branching on event types
222 ----------------------------------------
224 In a typical implementation, the ``HandleInputEvent()`` function
225 determines the type of each event using the ``GetType()`` function found
226 in the ``InputEvent`` class. The ``HandleInputEvent()`` function then uses a
227 switch statement to branch on the type of input event. Input events
228 are defined in the `PP_InputEvent_Type
229 <https://developers.google.com/native-client/dev/pepperc/group___enums.html#gaca7296cfec99fcb6646b7144d1d6a0c5>`_
230 enumeration in `ppb_input_event.h
231 <https://developers.google.com/native-client/dev/pepperc/ppb__input__event_8h>`_.
235 virtual bool HandleInputEvent(const pp::InputEvent& event) {
236 Event* event_ptr = NULL;
237 switch (event.GetType()) {
238 case PP_INPUTEVENT_TYPE_UNDEFINED:
240 case PP_INPUTEVENT_TYPE_MOUSEDOWN:
241 case PP_INPUTEVENT_TYPE_MOUSEUP:
242 case PP_INPUTEVENT_TYPE_MOUSEMOVE:
243 case PP_INPUTEVENT_TYPE_MOUSEENTER:
244 case PP_INPUTEVENT_TYPE_MOUSELEAVE:
245 case PP_INPUTEVENT_TYPE_CONTEXTMENU: {
246 pp::MouseInputEvent mouse_event(event);
247 PP_InputEvent_MouseButton pp_button = mouse_event.GetButton();
248 MouseEvent::MouseButton mouse_button = MouseEvent::kNone;
250 case PP_INPUTEVENT_MOUSEBUTTON_NONE:
251 mouse_button = MouseEvent::kNone;
253 case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
254 mouse_button = MouseEvent::kLeft;
256 case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE:
257 mouse_button = MouseEvent::kMiddle;
259 case PP_INPUTEVENT_MOUSEBUTTON_RIGHT:
260 mouse_button = MouseEvent::kRight;
264 new MouseEvent(ConvertEventModifier(mouse_event.GetModifiers()),
266 mouse_event.GetPosition().x(),
267 mouse_event.GetPosition().y(),
268 mouse_event.GetClickCount(),
269 mouse_event.GetTimeStamp(),
270 event.GetType() == PP_INPUTEVENT_TYPE_CONTEXTMENU);
272 case PP_INPUTEVENT_TYPE_WHEEL: {
273 pp::WheelInputEvent wheel_event(event);
275 new WheelEvent(ConvertEventModifier(wheel_event.GetModifiers()),
276 wheel_event.GetDelta().x(),
277 wheel_event.GetDelta().y(),
278 wheel_event.GetTicks().x(),
279 wheel_event.GetTicks().y(),
280 wheel_event.GetScrollByPage(),
281 wheel_event.GetTimeStamp());
283 case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
284 case PP_INPUTEVENT_TYPE_KEYDOWN:
285 case PP_INPUTEVENT_TYPE_KEYUP:
286 case PP_INPUTEVENT_TYPE_CHAR: {
287 pp::KeyboardInputEvent key_event(event);
288 event_ptr = new KeyEvent(ConvertEventModifier(key_event.GetModifiers()),
289 key_event.GetKeyCode(),
290 key_event.GetTimeStamp(),
291 key_event.GetCharacterText().DebugString());
294 // For any unhandled events, send a message to the browser
295 // so that the user is aware of these and can investigate.
296 std::stringstream oss;
297 oss << "Default (unhandled) event, type=" << event.GetType();
298 PostMessage(oss.str());
301 event_queue_.Push(event_ptr);
306 Notice that the generic ``InputEvent`` received by ``HandleInputEvent()`` is
307 converted into a specific type after the event type is
308 determined. The event types handled in the example code are
309 ``MouseInputEvent``, ``WheelInputEvent``, and ``KeyboardInputEvent``.
310 There are also ``TouchInputEvents``. For the latest list of event types,
311 see the `InputEvent documentation
312 <https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_input_event>`_.
313 For reference information related to the these event classes, see the
314 following documentation:
316 * `pp::MouseInputEvent class <https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_mouse_input_event>`_
317 * `pp::WheelInputEvent class <https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_wheel_input_event>`_
318 * `pp::KeyboardInputEvent class <https://developers.google.com/native-client/dev/peppercpp/classpp_1_1_keyboard_input_event>`_
321 Threading and blocking
322 ----------------------
324 ``HandleInputEvent()`` in this example runs on the main module thread.
325 However, the bulk of the work happens on a separate worker thread (see
326 ``ProcessEventOnWorkerThread``). ``HandleInputEvent()`` puts events in
327 the ``event_queue_`` and the worker thread takes events from the
328 ``event_queue_``. This processing happens independently of the main
329 thread, so as not to slow down the browser.