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