| {{+bindTo:partials.standard_nacl_api}} |
| |
| <section id="view-change-focus-and-input-events"> |
| <h1 id="view-change-focus-and-input-events">View Change, Focus, and Input Events</h1> |
| <div class="contents local" id="contents" style="display: none"> |
| <ul class="small-gap"> |
| <li><a class="reference internal" href="#overview" id="id2">Overview</a></li> |
| <li><p class="first"><a class="reference internal" href="#handling-browser-events" id="id3">Handling browser events</a></p> |
| <ul class="small-gap"> |
| <li><a class="reference internal" href="#didchangeview" id="id4">DidChangeView()</a></li> |
| <li><a class="reference internal" href="#didchangefocus" id="id5">DidChangeFocus()</a></li> |
| </ul> |
| </li> |
| <li><p class="first"><a class="reference internal" href="#handling-input-events" id="id6">Handling input events</a></p> |
| <ul class="small-gap"> |
| <li><a class="reference internal" href="#registering-a-module-to-accept-input-events" id="id7">Registering a module to accept input events</a></li> |
| <li><a class="reference internal" href="#determining-and-branching-on-event-types" id="id8">Determining and branching on event types</a></li> |
| <li><a class="reference internal" href="#threading-and-blocking" id="id9">Threading and blocking</a></li> |
| </ul> |
| </li> |
| </ul> |
| |
| </div><p>This chapter describes view change, focus, and input event handling for a |
| Native Client module. The chapter assumes you are familiar with the |
| material presented in the <a class="reference internal" href="/native-client/overview.html"><em>Technical Overview</em></a>.</p> |
| <p>There are two examples used in this chapter to illustrate basic |
| programming techniques. The <code>input_events</code> example is used to |
| illustrate how your module can react to keyboard and mouse input |
| event. The <code>mouse_lock</code> example is used to illustrate how your module |
| can react to view change events. You can find these examples in the |
| <code>/examples/api/input_events</code> and <code>/examples/api/mouse_lock</code> |
| directories in the Native Client SDK. There is also the |
| ppapi_simple library that can be used to to implement most of the |
| boiler plate. The <code>pi_generator</code> example in |
| <code>/examples/demo/pi_generator</code> uses ppapi_simple to manage view |
| change events and 2D graphics.</p> |
| <section id="overview"> |
| <h2 id="overview">Overview</h2> |
| <p>When a user interacts with the web page using a keyboard, mouse or some other |
| input device, the browser generates input events. In a traditional web |
| application, these input events are passed to and handled in JavaScript, |
| typically through event listeners and event handlers. In a Native Client |
| application, user interaction with an instance of a module (e.g., clicking |
| inside the rectangle managed by a module) also generates input events, which |
| are passed to the module. The browser also passes view change and focus events |
| that affect a module’s instance to the module. Native Client modules can |
| 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 |
| and browser events. These functions are listed in the table below:</p> |
| <table border="1" class="docutils"> |
| <colgroup> |
| </colgroup> |
| <thead valign="bottom"> |
| <tr class="row-odd"><th class="head">Function</th> |
| <th class="head">Event</th> |
| <th class="head">Use</th> |
| </tr> |
| </thead> |
| <tbody valign="top"> |
| <tr class="row-even"><td><code>DidChangeView</code></td> |
| <td>Called when the position, |
| size, or clip rectangle |
| of the module’s instance in |
| the browser has changed. |
| This event also occurs |
| when browser window is |
| resized or mouse wheel |
| is scrolled.</td> |
| <td>An implementation |
| of this function |
| might check the size |
| of the module |
| instance’s rectangle |
| has changed and |
| reallocate the |
| graphics context |
| when a different |
| size is received.</td> |
| </tr> |
| <tr class="row-odd"><td><code>DidChangeFocus</code></td> |
| <td>Called when the module’s |
| instance in the browser |
| has gone in or out of |
| focus (usually by |
| clicking inside or |
| outside the module |
| instance). Having focus |
| means that keyboard |
| events will be sent to |
| the module instance. |
| An instance’s default |
| condition is that it |
| does not have focus.</td> |
| <td>An implementation |
| of this function |
| might start or stop |
| an animation or a |
| blinking cursor.</td> |
| </tr> |
| <tr class="row-even"><td><code>HandleDocumentLoad</code></td> |
| <td>Called after |
| <code>pp::Instance::Init()</code> |
| for a full-frame module |
| instance that was |
| instantiated based on |
| the MIME type of a |
| DOMWindow navigation. |
| This situation only |
| applies to modules that |
| are pre-registered to |
| handle certain MIME |
| types. If you haven’t |
| specifically registered |
| to handle a MIME type or |
| aren’t positive this |
| applies to you, your |
| implementation of this |
| function can just return |
| false.</td> |
| <td>This API is only |
| applicable when you |
| are writing an |
| extension to enhance |
| the abilities of |
| the Chrome web |
| browser. For |
| example, a PDF |
| viewer might |
| implement this |
| function to download |
| and display a PDF |
| file.</td> |
| </tr> |
| <tr class="row-odd"><td><code>HandleInputEvent</code></td> |
| <td>Called when a user |
| interacts with the |
| module’s instance in the |
| browser using an input |
| device such as a mouse |
| or keyboard. You must |
| register your module to |
| accept input events |
| using |
| <code>RequestInputEvents()</code> |
| for mouse events and |
| <code>RequestFilteringInputEvents</code> |
| for keyboard events |
| prior to overriding this |
| function.</td> |
| <td>An implementation of |
| this function |
| examines the input |
| event type and |
| branches accordingly.</td> |
| </tr> |
| </tbody> |
| </table> |
| <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 |
| provide examples of how to handle these events.</p> |
| </section><section id="handling-browser-events"> |
| <h2 id="handling-browser-events">Handling browser events</h2> |
| <section id="didchangeview"> |
| <h3 id="didchangeview">DidChangeView()</h3> |
| <p>In the <code>mouse_lock</code> example, <code>DidChangeView()</code> checks the previous size |
| of instance’s rectangle versus the new size. It also compares |
| other state such as whether or not the app is running in full screen mode. |
| If none of the state has actually changed, no action is needed. |
| However, if the size of the view or other state has changed, it frees the |
| old graphics context and allocates a new one.</p> |
| <pre class="prettyprint"> |
| void MouseLockInstance::DidChangeView(const pp::View& view) { |
| // DidChangeView can get called for many reasons, so we only want to |
| // rebuild the device context if we really need to. |
| if ((size_ == view.GetRect().size()) && |
| (was_fullscreen_ == view.IsFullscreen()) && is_context_bound_) { |
| return; |
| } |
| |
| // ... |
| |
| // Reallocate the graphics context. |
| size_ = view.GetRect().size(); |
| device_context_ = pp::Graphics2D(this, size_, false); |
| waiting_for_flush_completion_ = false; |
| |
| is_context_bound_ = BindGraphics(device_context_); |
| // ... |
| |
| // Remember if we are fullscreen or not |
| was_fullscreen_ = view.IsFullscreen(); |
| // ... |
| } |
| </pre> |
| <p>For more information about graphics contexts and how to manipulate images, see:</p> |
| <ul class="small-gap"> |
| <li><a class="reference external" href="/native-client/pepper_stable/cpp/classpp_1_1_image_data">pp::ImageData class</a></li> |
| <li><a class="reference external" href="/native-client/pepper_stable/cpp/classpp_1_1_graphics2_d">pp::Graphics2D class</a></li> |
| </ul> |
| </section><section id="didchangefocus"> |
| <h3 id="didchangefocus">DidChangeFocus()</h3> |
| <p><code>DidChangeFocus()</code> is called when you click inside or outside of a |
| module’s instance in the web page. When the instance goes out |
| of focus (click outside of the instance), you might do something |
| like stop an animation. When the instance regains focus, you can |
| restart the animation.</p> |
| <pre class="prettyprint"> |
| void DidChangeFocus(bool focus) { |
| // Do something like stopping animation or a blinking cursor in |
| // the instance. |
| } |
| </pre> |
| </section></section><section id="handling-input-events"> |
| <h2 id="handling-input-events">Handling input events</h2> |
| <p>Input events are events that occur when the user interacts with a |
| module instance using the mouse, keyboard, or other input device |
| (e.g., touch screen). This section describes how the <code>input_events</code> |
| example handles input events.</p> |
| <section id="registering-a-module-to-accept-input-events"> |
| <h3 id="registering-a-module-to-accept-input-events">Registering a module to accept input events</h3> |
| <p>Before your module can handle these events, you must register your |
| module to accept input events using <code>RequestInputEvents()</code> for mouse |
| events and <code>RequestFilteringInputEvents()</code> for keyboard events. For the |
| <code>input_events</code> example, this is done in the constructor of the |
| <code>InputEventInstance</code> class:</p> |
| <pre class="prettyprint"> |
| class InputEventInstance : public pp::Instance { |
| public: |
| explicit InputEventInstance(PP_Instance instance) |
| : pp::Instance(instance), event_thread_(NULL), callback_factory_(this) { |
| RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL | |
| PP_INPUTEVENT_CLASS_TOUCH); |
| RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD); |
| } |
| // ... |
| }; |
| </pre> |
| <p><code>RequestInputEvents()</code> and <code>RequestFilteringInputEvents()</code> accept a |
| combination of flags that identify the class of events that the instance is |
| requesting to receive. Input event classes are defined in the |
| <a class="reference external" href="/native-client/pepper_stable/c/group___enums.html#gafe68e3c1031daa4a6496845ff47649cd">PP_InputEvent_Class</a> |
| enumeration in <a class="reference external" href="/native-client/pepper_stable/c/ppb__input__event_8h">ppb_input_event.h</a>.</p> |
| </section><section id="determining-and-branching-on-event-types"> |
| <h3 id="determining-and-branching-on-event-types">Determining and branching on event types</h3> |
| <p>In a typical implementation, the <code>HandleInputEvent()</code> function determines the |
| type of each event using the <code>GetType()</code> function found in the <code>InputEvent</code> |
| class. The <code>HandleInputEvent()</code> function then uses a switch statement to |
| branch on the type of input event. Input events are defined in the |
| <a class="reference external" href="/native-client/pepper_stable/c/group___enums.html#gaca7296cfec99fcb6646b7144d1d6a0c5">PP_InputEvent_Type</a> |
| enumeration in <a class="reference external" href="/native-client/pepper_stable/c/ppb__input__event_8h">ppb_input_event.h</a>.</p> |
| <pre class="prettyprint"> |
| virtual bool HandleInputEvent(const pp::InputEvent& event) { |
| Event* event_ptr = NULL; |
| switch (event.GetType()) { |
| case PP_INPUTEVENT_TYPE_UNDEFINED: |
| break; |
| case PP_INPUTEVENT_TYPE_MOUSEDOWN: |
| case PP_INPUTEVENT_TYPE_MOUSEUP: |
| case PP_INPUTEVENT_TYPE_MOUSEMOVE: |
| case PP_INPUTEVENT_TYPE_MOUSEENTER: |
| case PP_INPUTEVENT_TYPE_MOUSELEAVE: |
| case PP_INPUTEVENT_TYPE_CONTEXTMENU: { |
| pp::MouseInputEvent mouse_event(event); |
| PP_InputEvent_MouseButton pp_button = mouse_event.GetButton(); |
| MouseEvent::MouseButton mouse_button = MouseEvent::kNone; |
| switch (pp_button) { |
| case PP_INPUTEVENT_MOUSEBUTTON_NONE: |
| mouse_button = MouseEvent::kNone; |
| break; |
| case PP_INPUTEVENT_MOUSEBUTTON_LEFT: |
| mouse_button = MouseEvent::kLeft; |
| break; |
| case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE: |
| mouse_button = MouseEvent::kMiddle; |
| break; |
| case PP_INPUTEVENT_MOUSEBUTTON_RIGHT: |
| mouse_button = MouseEvent::kRight; |
| break; |
| } |
| event_ptr = |
| new MouseEvent(ConvertEventModifier(mouse_event.GetModifiers()), |
| mouse_button, |
| mouse_event.GetPosition().x(), |
| mouse_event.GetPosition().y(), |
| mouse_event.GetClickCount(), |
| mouse_event.GetTimeStamp(), |
| event.GetType() == PP_INPUTEVENT_TYPE_CONTEXTMENU); |
| } break; |
| case PP_INPUTEVENT_TYPE_WHEEL: { |
| pp::WheelInputEvent wheel_event(event); |
| event_ptr = |
| new WheelEvent(ConvertEventModifier(wheel_event.GetModifiers()), |
| wheel_event.GetDelta().x(), |
| wheel_event.GetDelta().y(), |
| wheel_event.GetTicks().x(), |
| wheel_event.GetTicks().y(), |
| wheel_event.GetScrollByPage(), |
| wheel_event.GetTimeStamp()); |
| } break; |
| case PP_INPUTEVENT_TYPE_RAWKEYDOWN: |
| case PP_INPUTEVENT_TYPE_KEYDOWN: |
| case PP_INPUTEVENT_TYPE_KEYUP: |
| case PP_INPUTEVENT_TYPE_CHAR: { |
| pp::KeyboardInputEvent key_event(event); |
| event_ptr = new KeyEvent(ConvertEventModifier(key_event.GetModifiers()), |
| key_event.GetKeyCode(), |
| key_event.GetTimeStamp(), |
| key_event.GetCharacterText().DebugString()); |
| } break; |
| default: { |
| // For any unhandled events, send a message to the browser |
| // so that the user is aware of these and can investigate. |
| std::stringstream oss; |
| oss << "Default (unhandled) event, type=" << event.GetType(); |
| PostMessage(oss.str()); |
| } break; |
| } |
| event_queue_.Push(event_ptr); |
| return true; |
| } |
| </pre> |
| <p>Notice that the generic <code>InputEvent</code> received by <code>HandleInputEvent()</code> is |
| converted into a specific type after the event type is |
| determined. The event types handled in the example code are |
| <code>MouseInputEvent</code>, <code>WheelInputEvent</code>, and <code>KeyboardInputEvent</code>. |
| There are also <code>TouchInputEvents</code>. For the latest list of event types, |
| see the <a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_input_event">InputEvent documentation</a>. |
| For reference information related to the these event classes, see the |
| following documentation:</p> |
| <ul class="small-gap"> |
| <li><a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_mouse_input_event">pp::MouseInputEvent class</a></li> |
| <li><a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_wheel_input_event">pp::WheelInputEvent class</a></li> |
| <li><a class="reference external" href="/native-client/pepper_stable/c/classpp_1_1_keyboard_input_event">pp::KeyboardInputEvent class</a></li> |
| </ul> |
| </section><section id="threading-and-blocking"> |
| <h3 id="threading-and-blocking">Threading and blocking</h3> |
| <p><code>HandleInputEvent()</code> in this example runs on the main module thread. |
| However, the bulk of the work happens on a separate worker thread (see |
| <code>ProcessEventOnWorkerThread</code>). <code>HandleInputEvent()</code> puts events in |
| the <code>event_queue_</code> and the worker thread takes events from the |
| <code>event_queue_</code>. This processing happens independently of the main |
| thread, so as not to slow down the browser.</p> |
| </section></section></section> |
| |
| {{/partials.standard_nacl_api}} |