1 {{+bindTo:partials.standard_nacl_api}} 2 3 <section id="view-change-focus-and-input-events"> 4 <h1 id="view-change-focus-and-input-events">View Change, Focus, and Input Events</h1> 5 <div class="contents local" id="contents" style="display: none"> 6 <ul class="small-gap"> 7 <li><a class="reference internal" href="#overview" id="id2">Overview</a></li> 8 <li><p class="first"><a class="reference internal" href="#handling-browser-events" id="id3">Handling browser events</a></p> 9 <ul class="small-gap"> 10 <li><a class="reference internal" href="#didchangeview" id="id4">DidChangeView()</a></li> 11 <li><a class="reference internal" href="#didchangefocus" id="id5">DidChangeFocus()</a></li> 12 </ul> 13 </li> 14 <li><p class="first"><a class="reference internal" href="#handling-input-events" id="id6">Handling input events</a></p> 15 <ul class="small-gap"> 16 <li><a class="reference internal" href="#registering-a-module-to-accept-input-events" id="id7">Registering a module to accept input events</a></li> 17 <li><a class="reference internal" href="#determining-and-branching-on-event-types" id="id8">Determining and branching on event types</a></li> 18 <li><a class="reference internal" href="#threading-and-blocking" id="id9">Threading and blocking</a></li> 19 </ul> 20 </li> 21 </ul> 22 23 </div><p>This chapter describes view change, focus, and input event handling for a 24 Native Client module. The chapter assumes you are familiar with the 25 material presented in the <a class="reference internal" href="/native-client/overview.html"><em>Technical Overview</em></a>.</p> 26 <p>There are two examples used in this chapter to illustrate basic 27 programming techniques. The <code>input_events</code> example is used to 28 illustrate how your module can react to keyboard and mouse input 29 event. The <code>mouse_lock</code> example is used to illustrate how your module 30 can react to view change events. You can find these examples in the 31 <code>/examples/api/input_events</code> and <code>/examples/api/mouse_lock</code> 32 directories in the Native Client SDK. There is also the 33 ppapi_simple library that can be used to to implement most of the 34 boiler plate. The <code>pi_generator</code> example in 35 <code>/examples/demo/pi_generator</code> uses ppapi_simple to manage view 36 change events and 2D graphics.</p> 37 <section id="overview"> 38 <h2 id="overview">Overview</h2> 39 <p>When a user interacts with the web page using a keyboard, mouse or some other 40 input device, the browser generates input events. In a traditional web 41 application, these input events are passed to and handled in JavaScript, 42 typically through event listeners and event handlers. In a Native Client 43 application, user interaction with an instance of a module (e.g., clicking 44 inside the rectangle managed by a module) also generates input events, which 45 are passed to the module. The browser also passes view change and focus events 46 that affect a module’s instance to the module. Native Client modules can 47 override certain functions in the <a class="reference external" href="/native-client/pepper_stable/cpp/classpp_1_1_instance">pp::Instance</a> class to handle input 48 and browser events. These functions are listed in the table below:</p> 49 <table border="1" class="docutils"> 50 <colgroup> 51 </colgroup> 52 <thead valign="bottom"> 53 <tr class="row-odd"><th class="head">Function</th> 54 <th class="head">Event</th> 55 <th class="head">Use</th> 56 </tr> 57 </thead> 58 <tbody valign="top"> 59 <tr class="row-even"><td><code>DidChangeView</code></td> 60 <td>Called when the position, 61 size, or clip rectangle 62 of the module’s instance in 63 the browser has changed. 64 This event also occurs 65 when browser window is 66 resized or mouse wheel 67 is scrolled.</td> 68 <td>An implementation 69 of this function 70 might check the size 71 of the module 72 instance’s rectangle 73 has changed and 74 reallocate the 75 graphics context 76 when a different 77 size is received.</td> 78 </tr> 79 <tr class="row-odd"><td><code>DidChangeFocus</code></td> 80 <td>Called when the module’s 81 instance in the browser 82 has gone in or out of 83 focus (usually by 84 clicking inside or 85 outside the module 86 instance). Having focus 87 means that keyboard 88 events will be sent to 89 the module instance. 90 An instance’s default 91 condition is that it 92 does not have focus.</td> 93 <td>An implementation 94 of this function 95 might start or stop 96 an animation or a 97 blinking cursor.</td> 98 </tr> 99 <tr class="row-even"><td><code>HandleDocumentLoad</code></td> 100 <td>Called after 101 <code>pp::Instance::Init()</code> 102 for a full-frame module 103 instance that was 104 instantiated based on 105 the MIME type of a 106 DOMWindow navigation. 107 This situation only 108 applies to modules that 109 are pre-registered to 110 handle certain MIME 111 types. If you haven’t 112 specifically registered 113 to handle a MIME type or 114 aren’t positive this 115 applies to you, your 116 implementation of this 117 function can just return 118 false.</td> 119 <td>This API is only 120 applicable when you 121 are writing an 122 extension to enhance 123 the abilities of 124 the Chrome web 125 browser. For 126 example, a PDF 127 viewer might 128 implement this 129 function to download 130 and display a PDF 131 file.</td> 132 </tr> 133 <tr class="row-odd"><td><code>HandleInputEvent</code></td> 134 <td>Called when a user 135 interacts with the 136 module’s instance in the 137 browser using an input 138 device such as a mouse 139 or keyboard. You must 140 register your module to 141 accept input events 142 using 143 <code>RequestInputEvents()</code> 144 for mouse events and 145 <code>RequestFilteringInputEvents</code> 146 for keyboard events 147 prior to overriding this 148 function.</td> 149 <td>An implementation of 150 this function 151 examines the input 152 event type and 153 branches accordingly.</td> 154 </tr> 155 </tbody> 156 </table> 157 <p>These interfaces are found in the <a class="reference external" href="/native-client/pepper_stable/cpp/classpp_1_1_instance">pp::Instance class</a>. The sections below 158 provide examples of how to handle these events.</p> 159 </section><section id="handling-browser-events"> 160 <h2 id="handling-browser-events">Handling browser events</h2> 161 <section id="didchangeview"> 162 <h3 id="didchangeview">DidChangeView()</h3> 163 <p>In the <code>mouse_lock</code> example, <code>DidChangeView()</code> checks the previous size 164 of instance’s rectangle versus the new size. It also compares 165 other state such as whether or not the app is running in full screen mode. 166 If none of the state has actually changed, no action is needed. 167 However, if the size of the view or other state has changed, it frees the 168 old graphics context and allocates a new one.</p> 169 <pre class="prettyprint"> 170 void MouseLockInstance::DidChangeView(const pp::View& view) { 171 // DidChangeView can get called for many reasons, so we only want to 172 // rebuild the device context if we really need to. 173 if ((size_ == view.GetRect().size()) && 174 (was_fullscreen_ == view.IsFullscreen()) && is_context_bound_) { 175 return; 176 } 177 178 // ... 179 180 // Reallocate the graphics context. 181 size_ = view.GetRect().size(); 182 device_context_ = pp::Graphics2D(this, size_, false); 183 waiting_for_flush_completion_ = false; 184 185 is_context_bound_ = BindGraphics(device_context_); 186 // ... 187 188 // Remember if we are fullscreen or not 189 was_fullscreen_ = view.IsFullscreen(); 190 // ... 191 } 192 </pre> 193 <p>For more information about graphics contexts and how to manipulate images, see:</p> 194 <ul class="small-gap"> 195 <li><a class="reference external" href="/native-client/pepper_stable/cpp/classpp_1_1_image_data">pp::ImageData class</a></li> 196 <li><a class="reference external" href="/native-client/pepper_stable/cpp/classpp_1_1_graphics2_d">pp::Graphics2D class</a></li> 197 </ul> 198 </section><section id="didchangefocus"> 199 <h3 id="didchangefocus">DidChangeFocus()</h3> 200 <p><code>DidChangeFocus()</code> is called when you click inside or outside of a 201 module’s instance in the web page. When the instance goes out 202 of focus (click outside of the instance), you might do something 203 like stop an animation. When the instance regains focus, you can 204 restart the animation.</p> 205 <pre class="prettyprint"> 206 void DidChangeFocus(bool focus) { 207 // Do something like stopping animation or a blinking cursor in 208 // the instance. 209 } 210 </pre> 211 </section></section><section id="handling-input-events"> 212 <h2 id="handling-input-events">Handling input events</h2> 213 <p>Input events are events that occur when the user interacts with a 214 module instance using the mouse, keyboard, or other input device 215 (e.g., touch screen). This section describes how the <code>input_events</code> 216 example handles input events.</p> 217 <section id="registering-a-module-to-accept-input-events"> 218 <h3 id="registering-a-module-to-accept-input-events">Registering a module to accept input events</h3> 219 <p>Before your module can handle these events, you must register your 220 module to accept input events using <code>RequestInputEvents()</code> for mouse 221 events and <code>RequestFilteringInputEvents()</code> for keyboard events. For the 222 <code>input_events</code> example, this is done in the constructor of the 223 <code>InputEventInstance</code> class:</p> 224 <pre class="prettyprint"> 225 class InputEventInstance : public pp::Instance { 226 public: 227 explicit InputEventInstance(PP_Instance instance) 228 : pp::Instance(instance), event_thread_(NULL), callback_factory_(this) { 229 RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL | 230 PP_INPUTEVENT_CLASS_TOUCH); 231 RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); 232 } 233 // ... 234 }; 235 </pre> 236 <p><code>RequestInputEvents()</code> and <code>RequestFilteringInputEvents()</code> accept a 237 combination of flags that identify the class of events that the instance is 238 requesting to receive. Input event classes are defined in the 239 <a class="reference external" href="/native-client/pepper_stable/c/group___enums.html#gafe68e3c1031daa4a6496845ff47649cd">PP_InputEvent_Class</a> 240 enumeration in <a class="reference external" href="/native-client/pepper_stable/c/ppb__input__event_8h">ppb_input_event.h</a>.</p> 241 </section><section id="determining-and-branching-on-event-types"> 242 <h3 id="determining-and-branching-on-event-types">Determining and branching on event types</h3> 243 <p>In a typical implementation, the <code>HandleInputEvent()</code> function determines the 244 type of each event using the <code>GetType()</code> function found in the <code>InputEvent</code> 245 class. The <code>HandleInputEvent()</code> function then uses a switch statement to 246 branch on the type of input event. Input events are defined in the 247 <a class="reference external" href="/native-client/pepper_stable/c/group___enums.html#gaca7296cfec99fcb6646b7144d1d6a0c5">PP_InputEvent_Type</a> 248 enumeration in <a class="reference external" href="/native-client/pepper_stable/c/ppb__input__event_8h">ppb_input_event.h</a>.</p> 249 <pre class="prettyprint"> 250 virtual bool HandleInputEvent(const pp::InputEvent& event) { 251 Event* event_ptr = NULL; 252 switch (event.GetType()) { 253 case PP_INPUTEVENT_TYPE_UNDEFINED: 254 break; 255 case PP_INPUTEVENT_TYPE_MOUSEDOWN: 256 case PP_INPUTEVENT_TYPE_MOUSEUP: 257 case PP_INPUTEVENT_TYPE_MOUSEMOVE: 258 case PP_INPUTEVENT_TYPE_MOUSEENTER: 259 case PP_INPUTEVENT_TYPE_MOUSELEAVE: 260 case PP_INPUTEVENT_TYPE_CONTEXTMENU: { 261 pp::MouseInputEvent mouse_event(event); 262 PP_InputEvent_MouseButton pp_button = mouse_event.GetButton(); 263 MouseEvent::MouseButton mouse_button = MouseEvent::kNone; 264 switch (pp_button) { 265 case PP_INPUTEVENT_MOUSEBUTTON_NONE: 266 mouse_button = MouseEvent::kNone; 267 break; 268 case PP_INPUTEVENT_MOUSEBUTTON_LEFT: 269 mouse_button = MouseEvent::kLeft; 270 break; 271 case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE: 272 mouse_button = MouseEvent::kMiddle; 273 break; 274 case PP_INPUTEVENT_MOUSEBUTTON_RIGHT: 275 mouse_button = MouseEvent::kRight; 276 break; 277 } 278 event_ptr = 279 new MouseEvent(ConvertEventModifier(mouse_event.GetModifiers()), 280 mouse_button, 281 mouse_event.GetPosition().x(), 282 mouse_event.GetPosition().y(), 283 mouse_event.GetClickCount(), 284 mouse_event.GetTimeStamp(), 285 event.GetType() == PP_INPUTEVENT_TYPE_CONTEXTMENU); 286 } break; 287 case PP_INPUTEVENT_TYPE_WHEEL: { 288 pp::WheelInputEvent wheel_event(event); 289 event_ptr = 290 new WheelEvent(ConvertEventModifier(wheel_event.GetModifiers()), 291 wheel_event.GetDelta().x(), 292 wheel_event.GetDelta().y(), 293 wheel_event.GetTicks().x(), 294 wheel_event.GetTicks().y(), 295 wheel_event.GetScrollByPage(), 296 wheel_event.GetTimeStamp()); 297 } break; 298 case PP_INPUTEVENT_TYPE_RAWKEYDOWN: 299 case PP_INPUTEVENT_TYPE_KEYDOWN: 300 case PP_INPUTEVENT_TYPE_KEYUP: 301 case PP_INPUTEVENT_TYPE_CHAR: { 302 pp::KeyboardInputEvent key_event(event); 303 event_ptr = new KeyEvent(ConvertEventModifier(key_event.GetModifiers()), 304 key_event.GetKeyCode(), 305 key_event.GetTimeStamp(), 306 key_event.GetCharacterText().DebugString()); 307 } break; 308 default: { 309 // For any unhandled events, send a message to the browser 310 // so that the user is aware of these and can investigate. 311 std::stringstream oss; 312 oss << "Default (unhandled) event, type=" << event.GetType(); 313 PostMessage(oss.str()); 314 } break; 315 } 316 event_queue_.Push(event_ptr); 317 return true; 318 } 319 </pre> 320 <p>Notice that the generic <code>InputEvent</code> received by <code>HandleInputEvent()</code> is 321 converted into a specific type after the event type is 322 determined. The event types handled in the example code are 323 <code>MouseInputEvent</code>, <code>WheelInputEvent</code>, and <code>KeyboardInputEvent</code>. 324 There are also <code>TouchInputEvents</code>. For the latest list of event types, 325 see the <a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_input_event">InputEvent documentation</a>. 326 For reference information related to the these event classes, see the 327 following documentation:</p> 328 <ul class="small-gap"> 329 <li><a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_mouse_input_event">pp::MouseInputEvent class</a></li> 330 <li><a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_wheel_input_event">pp::WheelInputEvent class</a></li> 331 <li><a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_keyboard_input_event">pp::KeyboardInputEvent class</a></li> 332 </ul> 333 </section><section id="threading-and-blocking"> 334 <h3 id="threading-and-blocking">Threading and blocking</h3> 335 <p><code>HandleInputEvent()</code> in this example runs on the main module thread. 336 However, the bulk of the work happens on a separate worker thread (see 337 <code>ProcessEventOnWorkerThread</code>). <code>HandleInputEvent()</code> puts events in 338 the <code>event_queue_</code> and the worker thread takes events from the 339 <code>event_queue_</code>. This processing happens independently of the main 340 thread, so as not to slow down the browser.</p> 341 </section></section></section> 342 343 {{/partials.standard_nacl_api}} 344