Input Events in C++


This topic describes the "Input Events in C++" sample application implementation.


Related Info


Samples


This tutorial describes how to implement a simple input-handling Native Client (NaCl) application in C++. The NaCl module waits for input events in the space inside the blue rectangle. When it receives mouse or keyboard events, they are interpreted and logged in the "NaCl messages:" field.

Figure 1. Input events in C++ application

For information on how to access the sample application cheat sheet and run the application, see Sample-based Tutorials.

To implement input event handling:

  1. In the main instance constructor, enable the events you want to capture:

    • The RequestInputEvents() function enables the mouse and mouse wheel input events.
    • The RequestFilteringInputEvents() function enables keyboard input events.
  2. To add a prefix to the logged messages, initialize the static Logger class, which is a wrapper for the PostMessage() function. The Logger class is implemented in the "logger.cc" file.

    explicit InputEventsInstance(PP_Instance instance)
        : pp::Instance(instance) {
      RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL);
      RequestFilteringInputEvents(PP_INPUTEVENT_CLASS_KEYBOARD);
      Logger::InitializeInstance(this);
    }
    
  3. To react to specific input events, overload the HandleInputEvent() function.

    The HandleInputEvent() function takes a const reference to pp::InputEvent as a parameter. To extract the event type, use the GetType() function on it. This returns an enumeration value that can be used as a parameter for the switch expression. You can handle as many input event types as you want.

    In each case statement, the pp::InputEvent object is casted to the class that corresponds to its type. For example, for the PP_INPUTEVENT_TYPE_KEYDOWN event, the pp::InputEvent object is casted to pp::KeyboardInputEvent. This allows you to call event-specific functions that can provide additional information, such as the mouse position or the clicked key code.

    For each event, interpret the input data, create a reply message describing the event, and send the message to the browser using the Logger class:

      virtual bool HandleInputEvent(const pp::InputEvent& event) {
        switch (event.GetType()) {
          case PP_INPUTEVENT_TYPE_UNDEFINED: break;
          // Mouse button pressed while hovering over the embed element
          case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
            pp::MouseInputEvent mouse_event(event);
            switch (mouse_event.GetButton()) {
              case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
                Logger::Log("Left mouse button down");
                break;
              case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE:
                Logger::Log("Middle mouse button down");
                break;
              case PP_INPUTEVENT_MOUSEBUTTON_RIGHT:
                Logger::Log("Right mouse button down");
                break;
              default:
                break;
            }
          } break;
          // Mouse button released while embed element has focus 
          case PP_INPUTEVENT_TYPE_MOUSEUP:  {
            pp::MouseInputEvent mouse_event(event);
            switch (mouse_event.GetButton()) {
              case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
                Logger::Log("Left mouse button up");
                break;
              case PP_INPUTEVENT_MOUSEBUTTON_MIDDLE:
                Logger::Log("Middle mouse button up");
                break;
              case PP_INPUTEVENT_MOUSEBUTTON_RIGHT:
                Logger::Log("Right mouse button up");
                break;
              default:
                break;
            }
          } break;
          // Left mouse button is pressed while hovering over the embed element, or while the embed element has focus 
          case PP_INPUTEVENT_TYPE_MOUSEMOVE: {
            pp::MouseInputEvent mouse_event(event);
            pp::Point pos = mouse_event.GetPosition();
            Logger::Log("Mouse moved to position: (%d, %d)", pos.x(), pos.y());
            } break;
          case PP_INPUTEVENT_TYPE_MOUSEENTER: break;
          case PP_INPUTEVENT_TYPE_MOUSELEAVE: break;
          case PP_INPUTEVENT_TYPE_CONTEXTMENU: break;
          // Mouse wheel rotated while hovering over the embed element
          case PP_INPUTEVENT_TYPE_WHEEL: {
            pp::WheelInputEvent wheel_event(event);
            pp::FloatPoint delta = wheel_event.GetDelta();
            Logger::Log("Wheel move delta: (%f, %f)", delta.x(), delta.y());
            } break;
          case PP_INPUTEVENT_TYPE_RAWKEYDOWN: break;
          // Keyboard key is pressed while embed element has focus
          case PP_INPUTEVENT_TYPE_KEYDOWN: {
            pp::KeyboardInputEvent key_event(event);
            Logger::Log("Keyboard stroke code: %u", key_event.GetKeyCode());
            } break;
          case PP_INPUTEVENT_TYPE_KEYUP: break;
          // Keyboard key representing a printable character is pressed while embed element has focus
          case PP_INPUTEVENT_TYPE_CHAR: {
            pp::KeyboardInputEvent key_event(event);
            pp::Var key_name = key_event.GetCharacterText();
            Logger::Log("Keyboard stroke char: \"%s\"", key_name.AsString().c_str());
            } break;
          default: break;
        }
        return true;
      }
    
  4. To show the log messages on the Web page, in the JavaScript application component, receive the NaCl messages:

    function handleNaclMessage(message_event) {
      var message = message_event.data;
      if (printIfLog(message)) { 
        return;   // This was a log or error message; finish handling
      }
    }
    
  5. Check whether the message starts with any of the predefined prefixes. If it does, append it to the "NaCl messages" HTML object on the Web page:

    function printIfLog(message) {
      if ((typeof message == "string") && (uses_logging == true) && 
      (startsWith(message, kLogPrefix) || startsWith(message, kErrorPrefix)
      || startsWith(message, kDebugPrefix))) {
        logs.value += message;
        logs.scrollTop = logs.scrollHeight;
        return true;
      }
      return false;
    }