#ifdef _WIN32
#ifndef IPV6STRICT
#define IPV6STRICT
#endif
#include <winsock2.h>
#include <windows.h>
#include <XInput.h>
#pragma comment(lib, "XInput.lib")
#endif // _WIN32
#include <maya/MFnPlugin.h>
#include <maya/MTypeId.h>
#include <api_macros.h>
#include <maya/MIOStream.h>
#include <maya/MPlug.h>
#include <maya/MDataBlock.h>
#include <maya/MFnNumericAttribute.h>
#include <maya/MPxThreadedDeviceNode.h>
{
public:
                        gameInputDeviceNode();
    virtual             ~gameInputDeviceNode();
    
    static void*        creator();
public:
    
    
    
private:
};
MTypeId gameInputDeviceNode::id( 0x00081053 );
 
MObject gameInputDeviceNode::outputTranslate;
 
MObject gameInputDeviceNode::outputTranslateX;
 
MObject gameInputDeviceNode::outputTranslateY;
 
MObject gameInputDeviceNode::outputTranslateZ;
 
MObject gameInputDeviceNode::updateTranslateXZ;
 
gameInputDeviceNode::gameInputDeviceNode() 
{}
gameInputDeviceNode::~gameInputDeviceNode()
{
    destroyMemoryPools();
}
void gameInputDeviceNode::postConstructor()
{
    attrArray.
append( gameInputDeviceNode::outputTranslate );
    setRefreshOutputAttributes( attrArray );
    
    createMemoryPools( 24, 3, sizeof(double));
}
#ifdef _WIN32
bool checkController(XINPUT_STATE& state)
{
    DWORD dwResult;
    ZeroMemory( &state, sizeof(XINPUT_STATE) );
    dwResult = XInputGetState( 0, &state );
    if( dwResult == ERROR_SUCCESS )
    {
        return true;
    }
    return false;
}
#endif
void gameInputDeviceNode::threadHandler()
{
#ifdef _WIN32
    setDone( false );
    while ( ! isDone() )
    {
        if ( ! isLive() )
            continue;
        status = acquireDataStorage(buffer);
        if ( ! status )
            continue;
        XINPUT_STATE state;
        if ( ! checkController( state ) )
        {
            releaseDataStorage(buffer);
            continue;
        }
        beginThreadLoop();
        {
            float changeX = 0.0, changeY = 0.0;
            
            
            float leftThumbX = state.Gamepad.sThumbLX;
            float leftThumbY = state.Gamepad.sThumbLY;
            if ( leftThumbX > +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  ) changeX = +1;
            if ( leftThumbX < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  ) changeX = -1;
            if ( leftThumbY > +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  ) changeY = +1;
            if ( leftThumbY < -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  ) changeY = -1;
            double* doubleData = 
reinterpret_cast<double*
>(buffer.
ptr());
 
            doubleData[0] = changeX ; doubleData[1] = changeY; doubleData[2] = 0.0;
            pushThreadData( buffer );
        }
        endThreadLoop();
    }
#endif // _WIN32
    setDone( true );
}
void gameInputDeviceNode::threadShutdownHandler()
{
    setDone( true );
}
void* gameInputDeviceNode::creator()
{
    return new gameInputDeviceNode;
}
MStatus gameInputDeviceNode::initialize()
 
{
    MCHECKERROR(status, "create outputTranslateX");
    MCHECKERROR(status, "create outputTranslateY");
    MCHECKERROR(status, "create outputTranslateZ");
    outputTranslate = numAttr.
create(
"outputTranslate", 
"ot", outputTranslateX, outputTranslateY, 
                                     outputTranslateZ, &status);
    MCHECKERROR(status, "create outputTranslate");
    ADD_ATTRIBUTE(outputTranslate);
    ADD_ATTRIBUTE(updateTranslateXZ);
    ATTRIBUTE_AFFECTS( live, outputTranslate);
    ATTRIBUTE_AFFECTS( frameRate, outputTranslate);
    ATTRIBUTE_AFFECTS( updateTranslateXZ, outputTranslate);
}
{
    if( plug == outputTranslate || plug == outputTranslateX ||
        plug == outputTranslateY || plug == outputTranslateZ )
    {
        
        
        if ( popThreadData(buffer) )
        {
            
            double* doubleData = 
reinterpret_cast<double*
>(buffer.
ptr());
 
            MCHECKERROR(status, "Error in block.outputValue for outputTranslate");
            double3& outputTranslate = outputTranslateHandle.
asDouble3();
            if ( xzUpdate ) 
            {
                
                outputTranslate[0] += doubleData[0];
                outputTranslate[1] += doubleData[2];
                outputTranslate[2] -= doubleData[1];
            }
            else
            {
                
                outputTranslate[0] += doubleData[0];
                outputTranslate[1] += doubleData[1];
                outputTranslate[2] += doubleData[2];
            }
            releaseDataStorage(buffer);
        }
        else
        {
        }
    }
}
{
    MFnPlugin plugin(obj, PLUGIN_COMPANY, 
"3.0", 
"Any");
 
    status = plugin.registerNode( "gameInputDevice", 
                                  gameInputDeviceNode::id,
                                  gameInputDeviceNode::creator,
                                  gameInputDeviceNode::initialize,
    if( !status ) {
        status.
perror(
"failed to registerNode gameInputDeviceNode");
    }
    return status;
}
{
    status = plugin.deregisterNode( gameInputDeviceNode::id );
    if( !status ) {
        status.
perror(
"failed to deregisterNode gameInputDeviceNode");
    }
    return status;
}