Handle events

Connect and disconnect events

After calling discoverControllers(), the Gamepad application enters its event loop. The event loop calls two functions: update() to process events and refresh the application's state and render() to change the display. The update() function calls handleEvents() which determines the type of event, either navigator or screen. The events we're interested in, related to game controllers, are processed in handleScreenEvent().

When a device is connected or disconnected, the BlackBerry Platform Services library generates an event of type SCREEN_EVENT_DEVICE. You can query several properties for this event type:
  • SCREEN_PROPERTY_ATTACHED: This property specifies whether this is a connection or disconnection event.
  • SCREEN_PROPERTY_TYPE: This property specifies whether the attached device is a gamepad, joystick, or other type of device. This property is only available on connection events.
  • SCREEN_PROPERTY_DEVICE: This property specifies a device handle. For a connection event, this handle is assigned to one of our GameController structs in _controllers[]. For a disconnection event, the GameController struct in _controllers[] with a matching device handle is disabled.
Here's how the SCREEN_EVENT_DEVICE event type is processed in handleScreenEvent():
case SCREEN_EVENT_DEVICE:
{
    // A device was attached or removed.
    screen_device_t device;
    int attached;
    int type;

    SCREEN_API(screen_get_event_property_pv(screen_event,
		SCREEN_PROPERTY_DEVICE, (void**)&device),
		"SCREEN_PROPERTY_DEVICE");
	SCREEN_API(screen_get_event_property_iv(screen_event,
		SCREEN_PROPERTY_ATTACHED, &attached),
		"SCREEN_PROPERTY_ATTACHED");

	if (attached) {
		SCREEN_API(screen_get_device_property_iv(device,
			SCREEN_PROPERTY_TYPE, &type),
			"SCREEN_PROPERTY_TYPE");
	}

	int i;
	if (attached && (type == SCREEN_EVENT_GAMEPAD || 
		type == SCREEN_EVENT_JOYSTICK)) {

		for (i = 0; i < MAX_CONTROLLERS; ++i) {
			if (!_controllers[i].handle) {
				_controllers[i].handle = device;
	            loadController(&_controllers[i]);
	            break;
	        }
	    }
	} else {
		for (i = 0; i < MAX_CONTROLLERS; ++i) {
			if (device == _controllers[i].handle) {
				initController(&_controllers[i], i);
				break;
	        }
	    }
	}

	break;
}
When a new controller is attached, we look for an available slot in _controllers[] and assign it the new screen_device_t handle. We then call loadController() to get the ID strings and button count of the controller. When a device is disconnected, we look for its handle in _controllers[] and, if a match is found, the slot is cleared so it can be reused.

Game controller input events

With the discovery code and handling of connection and disconnection events completed, our application now knows about any controller that's connected to the BlackBerry 10 device. This means we can process the input events that trigger when the controllers are used.

The application receives a SCREEN_EVENT_GAMEPAD or SCREEN_EVENT_JOYSTICK event any time a button is pressed, released, or the value of an analog stick changes. The following functions are used to decode what happened:
  • screen_get_context_property_pv(): This function gets the device handle to determine which device triggered the event. This handle is used to search the _controllers[] array to find a matching handle.
  • screen_get_context_property_iv(): This function queries the state of the controller's buttons and analog sticks. We get information about the controller's analog sticks based on the number of sticks stored in the analogCount member of the GameController struct.
This information about the device is stored in the appropriate slot of the _controllers[] array.
case SCREEN_EVENT_GAMEPAD:
case SCREEN_EVENT_JOYSTICK:
{              
    if (!_polling) {                  
        // Determine which controller this is.                  
        screen_device_t device;                  
        SCREEN_API(screen_get_event_property_pv(screen_event,
            SCREEN_PROPERTY_DEVICE, (void**)&device),
			"SCREEN_PROPERTY_DEVICE");                      
        GameController* controller = NULL;                  
        int i;                  
        for (i = 0; i < MAX_CONTROLLERS; ++i) {
            if (device == _controllers[i].handle) {
                controller = &_controllers[i];
                break;
            }                  
        }
                   
        if (!controller) {
            break;                  
        }
     
        // Store the controller's new state.                  
        SCREEN_API(screen_get_event_property_iv(screen_event,
            SCREEN_PROPERTY_BUTTONS, &controller->buttons),
			"SCREEN_PROPERTY_BUTTONS");                      

        if (controller->analogCount > 0) {                  
            SCREEN_API(screen_get_event_property_iv(screen_event,
                SCREEN_PROPERTY_ANALOG0, controller->analog0),
				"SCREEN_PROPERTY_ANALOG0");                  
        } 
                     
        if (controller->analogCount == 2) {
            SCREEN_API(screen_get_event_property_iv(screen_event,
                SCREEN_PROPERTY_ANALOG1, controller->analog1),
				"SCREEN_PROPERTY_ANALOG1");                  
        }              
      }              
      break;
    }

Polling for the controller's state

You can query devices for their state rather than waiting for triggered events. This approach lets you control when information is obtained rather than relying on the underlying event handling mechanism. It's possible to miss events using this approach, however, as a button could be pressed and released in between calls to your polling function, which results in your app not detecting the button press. To poll for state, you use the screen_get_device_property_iv() function.

Tapping the Polling button at the bottom of the Gamepad application causes it to ignore events of type SCREEN_EVENT_GAMEPAD and SCREEN_EVENT_JOYSTICK and instead use the pollDevices() function to retrieve the same data.
static void pollDevices()
{
    int i;
    for (i = 0; i < MAX_CONTROLLERS; i++) {
        GameController* controller = &_controllers[i];

        if (controller->handle) {
            // Get the current state of a gamepad device.
            SCREEN_API(screen_get_device_property_iv(
                    controller->handle,
                    SCREEN_PROPERTY_BUTTONS, 
                    &controller->buttons), 
                "SCREEN_PROPERTY_BUTTONS");

            if (controller->analogCount > 0) {
            	SCREEN_API(screen_get_device_property_iv(
                        controller->handle, 
                	    SCREEN_PROPERTY_ANALOG0, 
                        controller->analog0), 
                    "SCREEN_PROPERTY_ANALOG0");
	        }

	        if (controller->analogCount == 2) {
                SCREEN_API(screen_get_device_property_iv(
                        controller->handle, 
                        SCREEN_PROPERTY_ANALOG1, 
                        controller->analog1), 
                    "SCREEN_PROPERTY_ANALOG1");
	        }
	    }
	}
}
Chances are that you won't notice a difference in application behavior, but you can use the debugger in the Momentics IDE for BlackBerry to verify that this code is executing.

Screen showing the UI of the Gamepad sample app when polling is enabled.

Last modified: 2014-05-14



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus