Home | History | Annotate | Download | only in coding
      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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;t
    112 specifically registered
    113 to handle a MIME type or
    114 aren&#8217;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&#8217;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&#8217;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&amp; 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()) &amp;&amp;
    174       (was_fullscreen_ == view.IsFullscreen()) &amp;&amp; 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&#8217;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&amp; 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 &lt;&lt; &quot;Default (unhandled) event, type=&quot; &lt;&lt; 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