Home | History | Annotate | Download | only in coding
      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_&lt;version&gt;/examples/api/input_event</code> and
     32 <code>/pepper_&lt;version&gt;/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_&lt;version&gt;/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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;t specifically registered to
    100 handle a MIME type or aren&#8217;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&#8217;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&#8217;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&amp; 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()) &amp;&amp;
    149       (was_fullscreen_ == view.IsFullscreen()) &amp;&amp; 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&#8217;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&amp; 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 &lt;&lt; &quot;Default (unhandled) event, type=&quot; &lt;&lt; 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