view-focus-input-events.html revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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 24Native Client module. The chapter assumes you are familiar with the 25material 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 27programming techniques. The <code>input_events</code> example is used to 28illustrate how your module can react to keyboard and mouse input 29event. The <code>mouse_lock</code> example is used to illustrate how your module 30can 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> 32directories in the Native Client SDK. There is also the 33ppapi_simple library that can be used to to implement most of the 34boiler plate. The <code>pi_generator</code> example in 35<code>/examples/demo/pi_generator</code> uses ppapi_simple to manage view 36change 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 40input device, the browser generates input events. In a traditional web 41application, these input events are passed to and handled in JavaScript, 42typically through event listeners and event handlers. In a Native Client 43application, user interaction with an instance of a module (e.g., clicking 44inside the rectangle managed by a module) also generates input events, which 45are passed to the module. The browser also passes view change and focus events 46that affect a module’s instance to the module. Native Client modules can 47override 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 48and 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, 61size, or clip rectangle 62of the module’s instance in 63the browser has changed. 64This event also occurs 65when browser window is 66resized or mouse wheel 67is scrolled.</td> 68<td>An implementation 69of this function 70might check the size 71of the module 72instance’s rectangle 73has changed and 74reallocate the 75graphics context 76when a different 77size is received.</td> 78</tr> 79<tr class="row-odd"><td><code>DidChangeFocus</code></td> 80<td>Called when the module’s 81instance in the browser 82has gone in or out of 83focus (usually by 84clicking inside or 85outside the module 86instance). Having focus 87means that keyboard 88events will be sent to 89the module instance. 90An instance’s default 91condition is that it 92does not have focus.</td> 93<td>An implementation 94of this function 95might start or stop 96an animation or a 97blinking cursor.</td> 98</tr> 99<tr class="row-even"><td><code>HandleDocumentLoad</code></td> 100<td>Called after 101<code>pp::Instance::Init()</code> 102for a full-frame module 103instance that was 104instantiated based on 105the MIME type of a 106DOMWindow navigation. 107This situation only 108applies to modules that 109are pre-registered to 110handle certain MIME 111types. If you haven’t 112specifically registered 113to handle a MIME type or 114aren’t positive this 115applies to you, your 116implementation of this 117function can just return 118false.</td> 119<td>This API is only 120applicable when you 121are writing an 122extension to enhance 123the abilities of 124the Chrome web 125browser. For 126example, a PDF 127viewer might 128implement this 129function to download 130and display a PDF 131file.</td> 132</tr> 133<tr class="row-odd"><td><code>HandleInputEvent</code></td> 134<td>Called when a user 135interacts with the 136module’s instance in the 137browser using an input 138device such as a mouse 139or keyboard. You must 140register your module to 141accept input events 142using 143<code>RequestInputEvents()</code> 144for mouse events and 145<code>RequestFilteringInputEvents</code> 146for keyboard events 147prior to overriding this 148function.</td> 149<td>An implementation of 150this function 151examines the input 152event type and 153branches 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 158provide 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 164of instance’s rectangle versus the new size. It also compares 165other state such as whether or not the app is running in full screen mode. 166If none of the state has actually changed, no action is needed. 167However, if the size of the view or other state has changed, it frees the 168old graphics context and allocates a new one.</p> 169<pre class="prettyprint"> 170void 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 201module’s instance in the web page. When the instance goes out 202of focus (click outside of the instance), you might do something 203like stop an animation. When the instance regains focus, you can 204restart the animation.</p> 205<pre class="prettyprint"> 206void 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 214module instance using the mouse, keyboard, or other input device 215(e.g., touch screen). This section describes how the <code>input_events</code> 216example 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 220module to accept input events using <code>RequestInputEvents()</code> for mouse 221events 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"> 225class 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 237combination of flags that identify the class of events that the instance is 238requesting 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> 240enumeration 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 244type of each event using the <code>GetType()</code> function found in the <code>InputEvent</code> 245class. The <code>HandleInputEvent()</code> function then uses a switch statement to 246branch 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> 248enumeration 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"> 250virtual 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 321converted into a specific type after the event type is 322determined. The event types handled in the example code are 323<code>MouseInputEvent</code>, <code>WheelInputEvent</code>, and <code>KeyboardInputEvent</code>. 324There are also <code>TouchInputEvents</code>. For the latest list of event types, 325see the <a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_input_event">InputEvent documentation</a>. 326For reference information related to the these event classes, see the 327following 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. 336However, the bulk of the work happens on a separate worker thread (see 337<code>ProcessEventOnWorkerThread</code>). <code>HandleInputEvent()</code> puts events in 338the <code>event_queue_</code> and the worker thread takes events from the 339<code>event_queue_</code>. This processing happens independently of the main 340thread, so as not to slow down the browser.</p> 341</section></section></section> 342 343{{/partials.standard_nacl_api}} 344