Native Client

View Change, Focus, and Input Events

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 Technical Overview.

There are two examples used in this chapter to illustrate basic programming techniques. The input_events example is used to illustrate how your module can react to keyboard and mouse input event. The pi_generator example is used to illustrate how your module can react view change events. You can find these examples in the /examples/input_events and /examples/pi_generator directories starting with the pepper_15 bundle in the Native Client SDK.

Glossary

instance
The rectangle on the web page that is managed by the Native Client module. (The rectangle can have width=0 and height=0, which means that nothing is drawn on the page.) Currently, there is one instance per Native Client module.
module
Short for "Native Client module," which is the code that is compiled into an executable file. The file extension for the module is .nexe.
progress events
Events generated by the Native Client runtime system during the module loading process.
message events
Events used to pass data between JavaScript and the Native Client module (see the Messaging System chapter).
view change events
Events that occur when a change in the browser affects the module instance (such as resizing the browser window or going to and from fullscreen mode).
focus events
Events that indicate whether certain parts of a web page are in our out of focus.
input events
Events that occur when an input device (such as keyboard or mouse) is used to interact with a module instance.

Overview

When a user provides input with an 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 instance to the module. Native Client modules can override certain functions in the pp::Instance class to handle input and browser events. These functions are listed in the table below.:

Function Event Use
DidChangeView() Called when the position, size, or clip rectangle of the module instance in the browser has changed. This event also occurs when browser window is resized or mouse wheel is scrolled. 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.
DidChangeFocus() Called when the module 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. An implementation of this function might start or stop an animation or a blinking cursor.
HandleDocumentLoad() Called after Init() 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. 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.
HandleInputEvent() Called when a user interacts with the module instance in the browser using a input device such as a mouse or keyboard. You must register your module to accept input events using RequestInputEvents() for mouse events and RequestFilteringInputEvents() for keyboard events prior to overriding this function. An implementation of this function examines the input event type and branches accordingly.

These interfaces are found in the pp::Instance class. The sections below provide examples of how to handle these events.

Handling browser events

DidChangeView()

In the pi_generator example, DidChangeView() checks the size of module instance's rectangle and reallocates the graphics context when a different size is received.

void PiGenerator::DidChangeView(const pp::Rect& position,
                              const pp::Rect& clip) {

  if (position.size().width() == width() &&
    position.size().height() == height())
    return;  // Size didn't change, no need to update anything.
    
  // Create a new device context with the new size. The context is what you need to draw. Pointer to actual
  // device/screen. 
  // ImageData is data. Got to have device context to create ImageData.
  DestroyContext();
  CreateContext(position.size());
  // Delete the old pixel buffer and create a new one. Defined here.
  ScopedMutexLock scoped_mutex(&pixel_buffer_mutex_);
  delete pixel_buffer_;
  pixel_buffer_ = NULL;
  if (graphics_2d_context_ != NULL) {
    pixel_buffer_ = new pp::ImageData(this,
                                      PP_IMAGEDATAFORMAT_BGRA_PREMUL,
                                      graphics_2d_context_->size(),
                                      false);
  }
}

DidChangeFocus()

DidChangeFocus() is called when you click inside or outside a module instance or outside the module instance. When the module instance goes out of focus (click outside of a module instance), you might do something like stopping an animation.

void DidChangeFocus(bool focus) {
  // Do something like stopping animation or a blinking cursor in the instance.	
}
For more information about how to manipulate images, see:

Handling input events

Input events are events that occur when the user interacts with a module instance using the mouse or keyboard. This section describes how the input_events example handles input events.

Registering a module to accept input events

Before your module can handle these events, you must register your module to accept input events using RequestInputEvents() for mouse events and RequestFilteringInputEvents() for keyboard events. For the input_events example, this is done in the constructor for the EventInstance class:/p>

explicit EventInstance(PP_Instance instance)
  : pp::Instance(instance) {
  RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL);
  RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
}

RequestInputEvents() and RequestFilteringInputEvents() 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 PP_InputEvent_Class enumeration in ppb_input_event.h.

Determining and branching on event types

In a typical implementation, the HandleInputEvent() function determines the type of each event using the GetType() function found in the InputEvent class. The HandleInputEvent() function then uses a switch statement to branch on the type of input event. Input events are defined in the PP_InputEvent_Type enumeration in ppb_input_event.h.

// Handle an incoming input event by switching on type and dispatching
// to the appropriate subtype handler.
virtual bool HandleInputEvent(const pp::InputEvent& event) {
  ...	
  switch (event.GetType()) {
    case PP_INPUTEVENT_TYPE_UNDEFINED:
      break;
    case PP_INPUTEVENT_TYPE_MOUSEDOWN:
      GotMouseEvent(pp::MouseInputEvent(event), "Down");
      break;
    case PP_INPUTEVENT_TYPE_MOUSEUP:
      GotMouseEvent(pp::MouseInputEvent(event), "Up");
      break;
    case PP_INPUTEVENT_TYPE_MOUSEMOVE:
      GotMouseEvent(pp::MouseInputEvent(event), "Move");
      break;
    case PP_INPUTEVENT_TYPE_MOUSEENTER:
      GotMouseEvent(pp::MouseInputEvent(event), "Enter");
      break;
    case PP_INPUTEVENT_TYPE_MOUSELEAVE:
      GotMouseEvent(pp::MouseInputEvent(event), "Leave");
      break;
    case PP_INPUTEVENT_TYPE_WHEEL:
      GotWheelEvent(pp::WheelInputEvent(event));
      break;
    case PP_INPUTEVENT_TYPE_RAWKEYDOWN:
      GotKeyEvent(pp::KeyboardInputEvent(event), "RawKeyDown");
      break;
    case PP_INPUTEVENT_TYPE_KEYDOWN:
      GotKeyEvent(pp::KeyboardInputEvent(event), "Down");
      break;
    case PP_INPUTEVENT_TYPE_KEYUP:
      GotKeyEvent(pp::KeyboardInputEvent(event), "Up");
      break;
    case PP_INPUTEVENT_TYPE_CHAR:
      GotKeyEvent(pp::KeyboardInputEvent(event), "Character");
      break;
    default:
      assert(false);
      return false;
  }
  return true;
}

Notice that the generic InputEvent received by HandleInputEvent() is converted into a specific type (either a MouseInputEvent, WheelInputEvent, or KeyboardInputEvent) after the event type is determined. For reference information related to the these event classes, see the following documentation:

HandleInputEvent() in this example operates on the main module thread. In large real-world applications, you'll want to create a separate thread that puts events in a queue and handles them independently of the main thread, so as not to slow down the browser.

Authentication required

You need to be signed in with Google+ to do that.

Signing you in...

Google Developers needs your permission to do that.