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