1 .. _view_focus_input_events: 2 3 :template: standard_nacl_api 4 5 #################################### 6 View Change, Focus, and Input Events 7 #################################### 8 9 .. contents:: 10 :local: 11 :backlinks: none 12 :depth: 2 13 14 This chapter describes view change, focus, and input event handling for a 15 Native Client module. The chapter assumes you are familiar with the 16 material presented in the :doc:`Technical Overview <../../overview>`. 17 18 There are two examples used in this chapter to illustrate basic 19 programming techniques. The ``input_events`` example is used to 20 illustrate how your module can react to keyboard and mouse input 21 event. The ``mouse_lock`` example is used to illustrate how your module 22 can react to view change events. You can find these examples in the 23 ``/examples/api/input_events`` and ``/examples/api/mouse_lock`` 24 directories in the Native Client SDK. There is also the 25 ppapi_simple library that can be used to to implement most of the 26 boiler plate. The ``pi_generator`` example in 27 ``/examples/demo/pi_generator`` uses ppapi_simple to manage view 28 change events and 2D graphics. 29 30 31 Overview 32 ======== 33 34 When a user interacts with the web page using a keyboard, mouse or some other 35 input device, the browser generates input events. In a traditional web 36 application, these input events are passed to and handled in JavaScript, 37 typically through event listeners and event handlers. In a Native Client 38 application, user interaction with an instance of a module (e.g., clicking 39 inside the rectangle managed by a module) also generates input events, which 40 are passed to the module. The browser also passes view change and focus events 41 that affect a module's instance to the module. Native Client modules can 42 override certain functions in the `pp::Instance 43 </native-client/pepper_stable/cpp/classpp_1_1_instance>`_ class to handle input 44 and browser events. These functions are listed in the table below: 45 46 47 ====================== =============================== ==================== 48 Function Event Use 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 58 when a different 59 size is received. 60 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. 66 outside the module 67 instance). Having focus 68 means that keyboard 69 events will be sent to 70 the module instance. 71 An instance's default 72 condition is that it 73 does not have focus. 74 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 89 aren't positive this 90 applies to you, your 91 implementation of this 92 function can just return 93 false. 94 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 102 accept input events 103 using 104 ``RequestInputEvents()`` 105 for mouse events and 106 ``RequestFilteringInputEvents`` 107 for keyboard events 108 prior to overriding this 109 function. 110 ====================== =============================== ==================== 111 112 113 These interfaces are found in the `pp::Instance class 114 </native-client/pepper_stable/cpp/classpp_1_1_instance>`_. The sections below 115 provide examples of how to handle these events. 116 117 118 Handling browser events 119 ======================= 120 121 DidChangeView() 122 --------------- 123 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. 130 131 .. naclcode:: 132 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_) { 138 return; 139 } 140 141 // ... 142 143 // Reallocate the graphics context. 144 size_ = view.GetRect().size(); 145 device_context_ = pp::Graphics2D(this, size_, false); 146 waiting_for_flush_completion_ = false; 147 148 is_context_bound_ = BindGraphics(device_context_); 149 // ... 150 151 // Remember if we are fullscreen or not 152 was_fullscreen_ = view.IsFullscreen(); 153 // ... 154 } 155 156 157 For more information about graphics contexts and how to manipulate images, see: 158 159 * `pp::ImageData class 160 </native-client/pepper_stable/cpp/classpp_1_1_image_data>`_ 161 * `pp::Graphics2D class 162 </native-client/pepper_stable/cpp/classpp_1_1_graphics2_d>`_ 163 164 165 DidChangeFocus() 166 ---------------- 167 168 ``DidChangeFocus()`` is called when you click inside or outside of a 169 module's instance in the web page. When the instance goes out 170 of focus (click outside of the instance), you might do something 171 like stop an animation. When the instance regains focus, you can 172 restart the animation. 173 174 .. naclcode:: 175 176 void DidChangeFocus(bool focus) { 177 // Do something like stopping animation or a blinking cursor in 178 // the instance. 179 } 180 181 182 Handling input events 183 ===================== 184 185 Input events are events that occur when the user interacts with a 186 module instance using the mouse, keyboard, or other input device 187 (e.g., touch screen). This section describes how the ``input_events`` 188 example handles input events. 189 190 191 Registering a module to accept input events 192 ------------------------------------------- 193 194 Before your module can handle these events, you must register your 195 module to accept input events using ``RequestInputEvents()`` for mouse 196 events and ``RequestFilteringInputEvents()`` for keyboard events. For the 197 ``input_events`` example, this is done in the constructor of the 198 ``InputEventInstance`` class: 199 200 .. naclcode:: 201 202 class InputEventInstance : public pp::Instance { 203 public: 204 explicit InputEventInstance(PP_Instance instance) 205 : pp::Instance(instance), event_thread_(NULL), callback_factory_(this) { 206 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL | 207 PP_INPUTEVENT_CLASS_TOUCH); 208 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); 209 } 210 // ... 211 }; 212 213 214 ``RequestInputEvents()`` and ``RequestFilteringInputEvents()`` accept a 215 combination of flags that identify the class of events that the instance is 216 requesting to receive. Input event classes are defined in the 217 `PP_InputEvent_Class 218 </native-client/pepper_stable/c/group___enums.html#gafe68e3c1031daa4a6496845ff47649cd>`_ 219 enumeration in `ppb_input_event.h 220 </native-client/pepper_stable/c/ppb__input__event_8h>`_. 221 222 223 Determining and branching on event types 224 ---------------------------------------- 225 226 In a typical implementation, the ``HandleInputEvent()`` function determines the 227 type of each event using the ``GetType()`` function found in the ``InputEvent`` 228 class. The ``HandleInputEvent()`` function then uses a switch statement to 229 branch on the type of input event. Input events are defined in the 230 `PP_InputEvent_Type 231 </native-client/pepper_stable/c/group___enums.html#gaca7296cfec99fcb6646b7144d1d6a0c5>`_ 232 enumeration in `ppb_input_event.h 233 </native-client/pepper_stable/c/ppb__input__event_8h>`_. 234 235 .. naclcode:: 236 237 virtual bool HandleInputEvent(const pp::InputEvent& event) { 238 Event* event_ptr = NULL; 239 switch (event.GetType()) { 240 case PP_INPUTEVENT_TYPE_UNDEFINED: 241 break; 242 case PP_INPUTEVENT_TYPE_MOUSEDOWN: 243 case PP_INPUTEVENT_TYPE_MOUSEUP: 244 case PP_INPUTEVENT_TYPE_MOUSEMOVE: 245 case PP_INPUTEVENT_TYPE_MOUSEENTER: 246 case PP_INPUTEVENT_TYPE_MOUSELEAVE: 247 case PP_INPUTEVENT_TYPE_CONTEXTMENU: { 248 pp::MouseInputEvent mouse_event(event); 249 PP_InputEvent_MouseButton pp_button = mouse_event.GetButton(); 250 MouseEvent::MouseButton mouse_button = MouseEvent::kNone; 251 switch (pp_button) { 252 case PP_INPUTEVENT_MOUSEBUTTON_NONE: 253 mouse_button = MouseEvent::kNone; 254 break; 255 case PP_INPUTEVENT_MOUSEBUTTON_LEFT: 256 mouse_button = MouseEvent::kLeft; 257 break; 258 case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE: 259 mouse_button = MouseEvent::kMiddle; 260 break; 261 case PP_INPUTEVENT_MOUSEBUTTON_RIGHT: 262 mouse_button = MouseEvent::kRight; 263 break; 264 } 265 event_ptr = 266 new MouseEvent(ConvertEventModifier(mouse_event.GetModifiers()), 267 mouse_button, 268 mouse_event.GetPosition().x(), 269 mouse_event.GetPosition().y(), 270 mouse_event.GetClickCount(), 271 mouse_event.GetTimeStamp(), 272 event.GetType() == PP_INPUTEVENT_TYPE_CONTEXTMENU); 273 } break; 274 case PP_INPUTEVENT_TYPE_WHEEL: { 275 pp::WheelInputEvent wheel_event(event); 276 event_ptr = 277 new WheelEvent(ConvertEventModifier(wheel_event.GetModifiers()), 278 wheel_event.GetDelta().x(), 279 wheel_event.GetDelta().y(), 280 wheel_event.GetTicks().x(), 281 wheel_event.GetTicks().y(), 282 wheel_event.GetScrollByPage(), 283 wheel_event.GetTimeStamp()); 284 } break; 285 case PP_INPUTEVENT_TYPE_RAWKEYDOWN: 286 case PP_INPUTEVENT_TYPE_KEYDOWN: 287 case PP_INPUTEVENT_TYPE_KEYUP: 288 case PP_INPUTEVENT_TYPE_CHAR: { 289 pp::KeyboardInputEvent key_event(event); 290 event_ptr = new KeyEvent(ConvertEventModifier(key_event.GetModifiers()), 291 key_event.GetKeyCode(), 292 key_event.GetTimeStamp(), 293 key_event.GetCharacterText().DebugString()); 294 } break; 295 default: { 296 // For any unhandled events, send a message to the browser 297 // so that the user is aware of these and can investigate. 298 std::stringstream oss; 299 oss << "Default (unhandled) event, type=" << event.GetType(); 300 PostMessage(oss.str()); 301 } break; 302 } 303 event_queue_.Push(event_ptr); 304 return true; 305 } 306 307 308 Notice that the generic ``InputEvent`` received by ``HandleInputEvent()`` is 309 converted into a specific type after the event type is 310 determined. The event types handled in the example code are 311 ``MouseInputEvent``, ``WheelInputEvent``, and ``KeyboardInputEvent``. 312 There are also ``TouchInputEvents``. For the latest list of event types, 313 see the `InputEvent documentation 314 </native-client/pepper_stable/c/classpp_1_1_input_event>`_. 315 For reference information related to the these event classes, see the 316 following documentation: 317 318 * `pp::MouseInputEvent class 319 </native-client/pepper_stable/c/classpp_1_1_mouse_input_event>`_ 320 * `pp::WheelInputEvent class 321 </native-client/pepper_stable/c/classpp_1_1_wheel_input_event>`_ 322 * `pp::KeyboardInputEvent class 323 </native-client/pepper_stable/c/classpp_1_1_keyboard_input_event>`_ 324 325 326 Threading and blocking 327 ---------------------- 328 329 ``HandleInputEvent()`` in this example runs on the main module thread. 330 However, the bulk of the work happens on a separate worker thread (see 331 ``ProcessEventOnWorkerThread``). ``HandleInputEvent()`` puts events in 332 the ``event_queue_`` and the worker thread takes events from the 333 ``event_queue_``. This processing happens independently of the main 334 thread, so as not to slow down the browser. 335