How to: Get the Pairing Between Bodies and Users by Using an Event-Driven Approach

This topic shows how to use a reusable class named NuiBodyUserMapping to get the pairing between bodies and users by using an event driven approach.

To get the pairing, do the following:

  1. Cut and paste the entire code block in the Complete Code Listing: NuiBodyUserMapping.h, and save it to a file named NuiBodyUserMapping.h.
  2. In your app, reference NuiBodyUserMapping.h.
  3. In the Initialize function, add the following code to create a NuiBodyUserMapping object named pUserMapping.

    C++

    NuiBodyUserMapping* pUserMapping = new NuiBodyUserMapping();
    pUserMapping->Initialize();  
    
  4. In the Update function, add the following code to keep track of the mapping with pUserMapping.

    C++

    NUI_FRAME frame;
    User^ users[NUI_BODY_COUNT];
    HRESULT hr = NuiStreamGetNextFrame( NUI_STREAM_TYPE_BODY, &frame );
          
    if( SUCCEEDED(hr) )
    {
        const NUI_BODY_FRAME* pBodyFrame = static_cast<const NUI_BODY_FRAME*>( frame.pData );
        for( UINT32 i = 0; i < NUI_BODY_COUNT; i++ )
        {
            if( NUI_BODY_TRACKED == (pBodyFrame->BodyData[i]).TrackingState )
            {
                users[i] = pUserMapping->GetUser( (pBodyFrame->BodyData[i]).TrackingID );
            }
        }
    }  
    
  5. In the Shutdown function, add the following code to release pUserMapping.

    C++

    delete(pUserMapping);  
    

Complete Code Listing: NuiBodyUserMapping.h

C++

  #pragma once
  /************************************************************************
  *                                                                       *
  *   NuiBodyUserMapping.h --                                             *
  *       Implements the body to user mapping helper functions.           *
  *                                                                       *
  *                                                                       *
  *   Copyright (c) Microsoft Corp. All rights reserved.                  *
  *                                                                       *
  ************************************************************************/
  using namespace Windows::Xbox::Input::Nui;
  using namespace Windows::Xbox::System;
  using namespace Windows::Xbox::Input;
  using namespace Windows::Foundation;

  class NuiBodyUserMapping
  {
    private:
    //
    // Defines the structure that contains the body and user pair.
    // On Xbox One, a body is considered as a controller.
    //
    struct NuiBodyUserPair
    {
      UINT64 controllerID;          User^ user;
      NuiBodyUserPair()
      {
        controllerID = NUI_BODY_INVALID_TRACKING_ID;
      }
    };

    NuiBodyUserPair m_Pair[NUI_BODY_COUNT];
    CRITICAL_SECTION m_Lock;

    public:
    NuiBodyUserMapping()
    {
        InitializeCriticalSection( &m_Lock );
    }

    ~NuiBodyUserMapping()
    {
        DeleteCriticalSection( &m_Lock );
    }

    void OnPairingChanged(IController^ controller,
                          User^        user)
    {
        if( controller->Type != L"Windows.Xbox.Input.Nui.Body" )
        {
            return;
        }

        UINT64 controllerID = controller->ControllerId;
        {
            EnterCriticalSection( &m_Lock );
            bool found = false;
            for( UINT32 i = 0; i < NUI_BODY_COUNT; i++ )
            {
                if( m_Pair[i].controllerID == controllerID )
                {
                    if( user != nullptr )
                    {
                        m_Pair[i].user = user;
                    }
                    else
                    {
                        m_Pair[i].controllerID = NUI_BODY_INVALID_TRACKING_ID;
                    }
                    found = true;
                    break;
                }
            }

            if ( !found && user != nullptr )
            {
                for( UINT32 i = 0; i < NUI_BODY_COUNT; i++ )
                {
                    if( m_Pair[i].controllerID == NUI_BODY_INVALID_TRACKING_ID )
                    {
                        m_Pair[i].controllerID = controllerID;
                        m_Pair[i].user = user;
                        break;
                    }
                }
            }
            LeaveCriticalSection( &m_Lock );
        }
    }

    Windows::Xbox::System::User^ GetUser( UINT64 TrackingID )
    {
        EnterCriticalSection( &m_Lock );

        User^ user = nullptr;
        for( INT32 i = 0; i < NUI_BODY_COUNT; i++ )
        {
            if( m_Pair[i].controllerID == TrackingID )
            {
                user = m_Pair[i].user;
                break;
            }
        }

        LeaveCriticalSection( &m_Lock );
        return user;
    }

    void Initialize()
    {
        Controller::ControllerPairingChanged += ref new
            EventHandler< ControllerPairingChangedEventArgs^
            >( [=]( Platform::Object^ , ControllerPairingChangedEventArgs^ args ) 
            { OnPairingChanged(args->Controller, args->User); } );
        Controller::ControllerRemoved += ref new 
            EventHandler< ControllerRemovedEventArgs^ >( [=]( Platform::Object^ , 
            ControllerRemovedEventArgs^ args ) 
            { OnPairingChanged(args->Controller, nullptr); } );

        auto controllers = Controller::GetControllers();

        UINT size = controllers->Size;
        for ( UINT i = 0; i < size; ++i )
        {
            auto controller = controllers->GetAt( i );
            OnPairingChanged( controller, controller->User );
        } 
    }
};  

See Also

Getting Started with the Gamepad API

How to: Activate the Gamepad Impulse Triggers

How to: Detect Whether a Gamepad Button Is Pressed

How to: Activate Controller Vibration

Programming the Xbox One Gamepad Controller

Gamepad Vibration Overview