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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;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&#8217;t
112specifically registered
113to handle a MIME type or
114aren&#8217;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&#8217;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&#8217;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&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
201module&#8217;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&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
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