Squashed 'external/gainput/' content from commit 2be0a50
git-subtree-dir: external/gainput git-subtree-split: 2be0a50089eafcc6fccb66142180082e48f27f4c
This commit is contained in:
274
lib/source/gainput/pad/GainputInputDevicePad.cpp
Normal file
274
lib/source/gainput/pad/GainputInputDevicePad.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
|
||||
#include <gainput/gainput.h>
|
||||
#include <gainput/GainputDebugRenderer.h>
|
||||
|
||||
#include "GainputInputDevicePadImpl.h"
|
||||
#include <gainput/GainputInputDeltaState.h>
|
||||
#include <gainput/GainputHelpers.h>
|
||||
#include <gainput/GainputLog.h>
|
||||
|
||||
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||
#include "GainputInputDevicePadLinux.h"
|
||||
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||
#include "GainputInputDevicePadWin.h"
|
||||
#elif defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_TVOS)
|
||||
#include "GainputInputDevicePadIos.h"
|
||||
#elif defined(GAINPUT_PLATFORM_MAC)
|
||||
#include "GainputInputDevicePadMac.h"
|
||||
#elif defined(GAINPUT_PLATFORM_ANDROID)
|
||||
#include "GainputInputDevicePadAndroid.h"
|
||||
#endif
|
||||
|
||||
#include "GainputInputDevicePadNull.h"
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
struct DeviceButtonInfo
|
||||
{
|
||||
ButtonType type;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
DeviceButtonInfo deviceButtonInfos[] =
|
||||
{
|
||||
{ BT_FLOAT, "pad_left_stick_x" },
|
||||
{ BT_FLOAT, "pad_left_stick_y" },
|
||||
{ BT_FLOAT, "pad_right_stick_x" },
|
||||
{ BT_FLOAT, "pad_right_stick_y" },
|
||||
{ BT_FLOAT, "pad_axis_4" },
|
||||
{ BT_FLOAT, "pad_axis_5" },
|
||||
{ BT_FLOAT, "pad_axis_6" },
|
||||
{ BT_FLOAT, "pad_axis_7" },
|
||||
{ BT_FLOAT, "pad_axis_8" },
|
||||
{ BT_FLOAT, "pad_axis_9" },
|
||||
{ BT_FLOAT, "pad_axis_10" },
|
||||
{ BT_FLOAT, "pad_axis_11" },
|
||||
{ BT_FLOAT, "pad_axis_12" },
|
||||
{ BT_FLOAT, "pad_axis_13" },
|
||||
{ BT_FLOAT, "pad_axis_14" },
|
||||
{ BT_FLOAT, "pad_axis_15" },
|
||||
{ BT_FLOAT, "pad_axis_16" },
|
||||
{ BT_FLOAT, "pad_axis_17" },
|
||||
{ BT_FLOAT, "pad_axis_18" },
|
||||
{ BT_FLOAT, "pad_axis_19" },
|
||||
{ BT_FLOAT, "pad_axis_20" },
|
||||
{ BT_FLOAT, "pad_axis_21" },
|
||||
{ BT_FLOAT, "pad_axis_22" },
|
||||
{ BT_FLOAT, "pad_axis_23" },
|
||||
{ BT_FLOAT, "pad_axis_24" },
|
||||
{ BT_FLOAT, "pad_axis_25" },
|
||||
{ BT_FLOAT, "pad_axis_26" },
|
||||
{ BT_FLOAT, "pad_axis_27" },
|
||||
{ BT_FLOAT, "pad_axis_28" },
|
||||
{ BT_FLOAT, "pad_axis_29" },
|
||||
{ BT_FLOAT, "pad_axis_30" },
|
||||
{ BT_FLOAT, "pad_axis_31" },
|
||||
{ BT_FLOAT, "pad_acceleration_x" },
|
||||
{ BT_FLOAT, "pad_acceleration_y" },
|
||||
{ BT_FLOAT, "pad_acceleration_z" },
|
||||
{ BT_FLOAT, "pad_gravity_x" },
|
||||
{ BT_FLOAT, "pad_gravity_y" },
|
||||
{ BT_FLOAT, "pad_gravity_z" },
|
||||
{ BT_FLOAT, "pad_gyroscope_x" },
|
||||
{ BT_FLOAT, "pad_gyroscope_y" },
|
||||
{ BT_FLOAT, "pad_gyroscope_z" },
|
||||
{ BT_FLOAT, "pad_magneticfield_x" },
|
||||
{ BT_FLOAT, "pad_magneticfield_y" },
|
||||
{ BT_FLOAT, "pad_magneticfield_z" },
|
||||
{ BT_BOOL, "pad_button_start"},
|
||||
{ BT_BOOL, "pad_button_select"},
|
||||
{ BT_BOOL, "pad_button_left"},
|
||||
{ BT_BOOL, "pad_button_right"},
|
||||
{ BT_BOOL, "pad_button_up"},
|
||||
{ BT_BOOL, "pad_button_down"},
|
||||
{ BT_BOOL, "pad_button_a"},
|
||||
{ BT_BOOL, "pad_button_b"},
|
||||
{ BT_BOOL, "pad_button_x"},
|
||||
{ BT_BOOL, "pad_button_y"},
|
||||
{ BT_BOOL, "pad_button_l1"},
|
||||
{ BT_BOOL, "pad_button_r1"},
|
||||
{ BT_BOOL, "pad_button_l2"},
|
||||
{ BT_BOOL, "pad_button_r2"},
|
||||
{ BT_BOOL, "pad_button_l3"},
|
||||
{ BT_BOOL, "pad_button_r3"},
|
||||
{ BT_BOOL, "pad_button_home"},
|
||||
{ BT_BOOL, "pad_button_17"},
|
||||
{ BT_BOOL, "pad_button_18"},
|
||||
{ BT_BOOL, "pad_button_19"},
|
||||
{ BT_BOOL, "pad_button_20"},
|
||||
{ BT_BOOL, "pad_button_21"},
|
||||
{ BT_BOOL, "pad_button_22"},
|
||||
{ BT_BOOL, "pad_button_23"},
|
||||
{ BT_BOOL, "pad_button_24"},
|
||||
{ BT_BOOL, "pad_button_25"},
|
||||
{ BT_BOOL, "pad_button_26"},
|
||||
{ BT_BOOL, "pad_button_27"},
|
||||
{ BT_BOOL, "pad_button_28"},
|
||||
{ BT_BOOL, "pad_button_29"},
|
||||
{ BT_BOOL, "pad_button_30"},
|
||||
{ BT_BOOL, "pad_button_31"}
|
||||
};
|
||||
|
||||
const unsigned PadButtonCount = PadButtonCount_;
|
||||
const unsigned PadAxisCount = PadButtonAxisCount_;
|
||||
|
||||
}
|
||||
|
||||
|
||||
InputDevicePad::InputDevicePad(InputManager& manager, DeviceId device, unsigned index, DeviceVariant /*variant*/) :
|
||||
InputDevice(manager, device, index == InputDevice::AutoIndex ? manager.GetDeviceCountByType(DT_PAD) : 0),
|
||||
impl_(0)
|
||||
{
|
||||
state_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), PadButtonCount + PadAxisCount);
|
||||
GAINPUT_ASSERT(state_);
|
||||
previousState_ = manager.GetAllocator().New<InputState>(manager.GetAllocator(), PadButtonCount + PadAxisCount);
|
||||
GAINPUT_ASSERT(previousState_);
|
||||
|
||||
#if defined(GAINPUT_PLATFORM_LINUX)
|
||||
impl_ = manager.GetAllocator().New<InputDevicePadImplLinux>(manager, *this, index_, *state_, *previousState_);
|
||||
#elif defined(GAINPUT_PLATFORM_WIN)
|
||||
impl_ = manager.GetAllocator().New<InputDevicePadImplWin>(manager, *this, index_, *state_, *previousState_);
|
||||
#elif defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_TVOS)
|
||||
impl_ = manager.GetAllocator().New<InputDevicePadImplIos>(manager, *this, index_, *state_, *previousState_);
|
||||
#elif defined(GAINPUT_PLATFORM_MAC)
|
||||
impl_ = manager.GetAllocator().New<InputDevicePadImplMac>(manager, *this, index_, *state_, *previousState_);
|
||||
#elif defined(GAINPUT_PLATFORM_ANDROID)
|
||||
impl_ = manager.GetAllocator().New<InputDevicePadImplAndroid>(manager, *this, index_, *state_, *previousState_);
|
||||
#endif
|
||||
|
||||
if (!impl_)
|
||||
{
|
||||
impl_ = manager.GetAllocator().New<InputDevicePadImplNull>(manager, *this, index_, *state_, *previousState_);
|
||||
}
|
||||
|
||||
GAINPUT_ASSERT(impl_);
|
||||
|
||||
SetDeadZone(PadButtonLeftStickX, 0.15f);
|
||||
SetDeadZone(PadButtonLeftStickY, 0.15f);
|
||||
SetDeadZone(PadButtonRightStickX, 0.15f);
|
||||
SetDeadZone(PadButtonRightStickY, 0.15f);
|
||||
}
|
||||
|
||||
InputDevicePad::~InputDevicePad()
|
||||
{
|
||||
manager_.GetAllocator().Delete(state_);
|
||||
manager_.GetAllocator().Delete(previousState_);
|
||||
manager_.GetAllocator().Delete(impl_);
|
||||
}
|
||||
|
||||
void
|
||||
InputDevicePad::InternalUpdate(InputDeltaState* delta)
|
||||
{
|
||||
impl_->Update(delta);
|
||||
|
||||
if ((manager_.IsDebugRenderingEnabled() || IsDebugRenderingEnabled())
|
||||
&& manager_.GetDebugRenderer())
|
||||
{
|
||||
DebugRenderer* debugRenderer = manager_.GetDebugRenderer();
|
||||
InputState* state = GetInputState();
|
||||
char buf[64];
|
||||
float x = 0.4f;
|
||||
float y = 0.2f;
|
||||
for (int i = PadButtonStart; i < PadButtonMax_; ++i)
|
||||
{
|
||||
if (state->GetBool(i))
|
||||
{
|
||||
GetButtonName(i, buf, 64);
|
||||
debugRenderer->DrawText(x, y, buf);
|
||||
y += 0.025f;
|
||||
}
|
||||
}
|
||||
|
||||
x = 0.8f;
|
||||
y = 0.2f;
|
||||
const float circleRadius = 0.1f;
|
||||
debugRenderer->DrawCircle(x, y, 0.01f);
|
||||
debugRenderer->DrawCircle(x, y, circleRadius);
|
||||
float dirX = state->GetFloat(PadButtonLeftStickX) * circleRadius;
|
||||
float dirY = state->GetFloat(PadButtonLeftStickY) * circleRadius;
|
||||
debugRenderer->DrawLine(x, y, x + dirX, y + dirY);
|
||||
|
||||
y = 0.6f;
|
||||
debugRenderer->DrawCircle(x, y, 0.01f);
|
||||
debugRenderer->DrawCircle(x, y, circleRadius);
|
||||
dirX = state->GetFloat(PadButtonRightStickX) * circleRadius;
|
||||
dirY = state->GetFloat(PadButtonRightStickY) * circleRadius;
|
||||
debugRenderer->DrawLine(x, y, x + dirX, y + dirY);
|
||||
}
|
||||
}
|
||||
|
||||
InputDevice::DeviceState
|
||||
InputDevicePad::InternalGetState() const
|
||||
{
|
||||
return impl_->GetState();
|
||||
}
|
||||
|
||||
InputDevice::DeviceVariant
|
||||
InputDevicePad::GetVariant() const
|
||||
{
|
||||
return impl_->GetVariant();
|
||||
}
|
||||
|
||||
bool
|
||||
InputDevicePad::IsValidButtonId(DeviceButtonId deviceButton) const
|
||||
{
|
||||
return impl_->IsValidButton(deviceButton);
|
||||
}
|
||||
|
||||
size_t
|
||||
InputDevicePad::GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const
|
||||
{
|
||||
GAINPUT_ASSERT(outButtons);
|
||||
GAINPUT_ASSERT(maxButtonCount > 0);
|
||||
return CheckAllButtonsDown(outButtons, maxButtonCount, PadButtonLeftStickX, PadButtonMax_);
|
||||
}
|
||||
|
||||
size_t
|
||||
InputDevicePad::GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const
|
||||
{
|
||||
GAINPUT_ASSERT(IsValidButtonId(deviceButton));
|
||||
GAINPUT_ASSERT(buffer);
|
||||
GAINPUT_ASSERT(bufferLength > 0);
|
||||
strncpy(buffer, deviceButtonInfos[deviceButton].name, bufferLength);
|
||||
buffer[bufferLength-1] = 0;
|
||||
const size_t nameLen = strlen(deviceButtonInfos[deviceButton].name);
|
||||
return nameLen >= bufferLength ? bufferLength : nameLen+1;
|
||||
}
|
||||
|
||||
ButtonType
|
||||
InputDevicePad::GetButtonType(DeviceButtonId deviceButton) const
|
||||
{
|
||||
return deviceButtonInfos[deviceButton].type;
|
||||
}
|
||||
|
||||
DeviceButtonId
|
||||
InputDevicePad::GetButtonByName(const char* name) const
|
||||
{
|
||||
GAINPUT_ASSERT(name);
|
||||
for (unsigned i = 0; i < PadButtonCount + PadAxisCount; ++i)
|
||||
{
|
||||
if (strcmp(name, deviceButtonInfos[i].name) == 0)
|
||||
{
|
||||
return DeviceButtonId(i);
|
||||
}
|
||||
}
|
||||
return InvalidDeviceButtonId;
|
||||
}
|
||||
|
||||
InputState*
|
||||
InputDevicePad::GetNextInputState()
|
||||
{
|
||||
return impl_->GetNextInputState();
|
||||
}
|
||||
|
||||
bool
|
||||
InputDevicePad::Vibrate(float leftMotor, float rightMotor)
|
||||
{
|
||||
return impl_->Vibrate(leftMotor, rightMotor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
79
lib/source/gainput/pad/GainputInputDevicePadAndroid.h
Normal file
79
lib/source/gainput/pad/GainputInputDevicePadAndroid.h
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
#ifndef GAINPUTINPUTDEVICEPADANDROID_H_
|
||||
#define GAINPUTINPUTDEVICEPADANDROID_H_
|
||||
|
||||
#include "GainputInputDevicePadImpl.h"
|
||||
#include <gainput/GainputHelpers.h>
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
class InputDevicePadImplAndroid : public InputDevicePadImpl
|
||||
{
|
||||
public:
|
||||
InputDevicePadImplAndroid(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState) :
|
||||
manager_(manager),
|
||||
device_(device),
|
||||
state_(&state),
|
||||
previousState_(&previousState),
|
||||
nextState_(manager.GetAllocator(), PadButtonMax_),
|
||||
delta_(0),
|
||||
index_(index),
|
||||
deviceState_(InputDevice::DS_UNAVAILABLE)
|
||||
{
|
||||
(void)previousState;
|
||||
GAINPUT_ASSERT(index_ < MaxPadCount);
|
||||
}
|
||||
|
||||
~InputDevicePadImplAndroid()
|
||||
{
|
||||
}
|
||||
|
||||
InputDevice::DeviceVariant GetVariant() const
|
||||
{
|
||||
return InputDevice::DV_STANDARD;
|
||||
}
|
||||
|
||||
void Update(InputDeltaState* delta)
|
||||
{
|
||||
delta_ = delta;
|
||||
*state_ = nextState_;
|
||||
}
|
||||
|
||||
InputDevice::DeviceState GetState() const
|
||||
{
|
||||
return deviceState_;
|
||||
}
|
||||
|
||||
void SetState(InputDevice::DeviceState state)
|
||||
{
|
||||
deviceState_ = state;
|
||||
}
|
||||
|
||||
bool IsValidButton(DeviceButtonId deviceButton) const
|
||||
{
|
||||
return deviceButton < PadButtonMax_;
|
||||
}
|
||||
|
||||
bool Vibrate(float /*leftMotor*/, float /*rightMotor*/)
|
||||
{
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
InputState* GetNextInputState() { return &nextState_; }
|
||||
|
||||
private:
|
||||
InputManager& manager_;
|
||||
InputDevice& device_;
|
||||
InputState* state_;
|
||||
InputState* previousState_;
|
||||
InputState nextState_;
|
||||
InputDeltaState* delta_;
|
||||
unsigned index_;
|
||||
InputDevice::DeviceState deviceState_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
23
lib/source/gainput/pad/GainputInputDevicePadImpl.h
Normal file
23
lib/source/gainput/pad/GainputInputDevicePadImpl.h
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
#ifndef GAINPUTINPUTDEVICEPADIMPL_H_
|
||||
#define GAINPUTINPUTDEVICEPADIMPL_H_
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
class InputDevicePadImpl
|
||||
{
|
||||
public:
|
||||
virtual ~InputDevicePadImpl() { }
|
||||
virtual InputDevice::DeviceVariant GetVariant() const = 0;
|
||||
virtual InputDevice::DeviceState GetState() const { return InputDevice::DS_OK; }
|
||||
virtual void Update(InputDeltaState* delta) = 0;
|
||||
virtual bool IsValidButton(DeviceButtonId deviceButton) const = 0;
|
||||
virtual bool Vibrate(float leftMotor, float rightMotor) = 0;
|
||||
virtual InputState* GetNextInputState() { return 0; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
60
lib/source/gainput/pad/GainputInputDevicePadIos.h
Normal file
60
lib/source/gainput/pad/GainputInputDevicePadIos.h
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#ifndef GAINPUTINPUTDEVICEPADIOS_H_
|
||||
#define GAINPUTINPUTDEVICEPADIOS_H_
|
||||
|
||||
#include <gainput/GainputContainers.h>
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
class InputDevicePadImplIos : public InputDevicePadImpl
|
||||
{
|
||||
public:
|
||||
InputDevicePadImplIos(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState);
|
||||
~InputDevicePadImplIos();
|
||||
|
||||
InputDevice::DeviceVariant GetVariant() const
|
||||
{
|
||||
return InputDevice::DV_STANDARD;
|
||||
}
|
||||
|
||||
void Update(InputDeltaState* delta);
|
||||
|
||||
InputDevice::DeviceState GetState() const
|
||||
{
|
||||
return deviceState_;
|
||||
}
|
||||
|
||||
bool IsValidButton(DeviceButtonId deviceButton) const;
|
||||
|
||||
typedef gainput::Array<void *> GlobalControllerList;
|
||||
static GlobalControllerList* mappedControllers_;
|
||||
|
||||
bool Vibrate(float leftMotor, float rightMotor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
InputManager& manager_;
|
||||
InputDevice& device_;
|
||||
unsigned index_;
|
||||
InputState& state_;
|
||||
InputState& previousState_;
|
||||
InputDevice::DeviceState deviceState_;
|
||||
|
||||
bool pausePressed_;
|
||||
bool isMicro_;
|
||||
bool isNormal_;
|
||||
bool isExtended_;
|
||||
bool supportsMotion_;
|
||||
bool isRemote_;
|
||||
void* gcController_;
|
||||
|
||||
void UpdateRemote_(InputDeltaState* delta);
|
||||
void UpdateGamepad_(InputDeltaState* delta);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
364
lib/source/gainput/pad/GainputInputDevicePadIos.mm
Normal file
364
lib/source/gainput/pad/GainputInputDevicePadIos.mm
Normal file
@@ -0,0 +1,364 @@
|
||||
#include <gainput/gainput.h>
|
||||
|
||||
#if defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_TVOS)
|
||||
|
||||
#include "GainputInputDevicePadImpl.h"
|
||||
#include <gainput/GainputInputDeltaState.h>
|
||||
#include <gainput/GainputHelpers.h>
|
||||
#include <gainput/GainputLog.h>
|
||||
|
||||
#include "GainputInputDevicePadIos.h"
|
||||
|
||||
#import <GameController/GameController.h>
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
InputDevicePadImplIos::GlobalControllerList* InputDevicePadImplIos::mappedControllers_;
|
||||
|
||||
namespace
|
||||
{
|
||||
static bool isAppleTvRemote(GCController* controller)
|
||||
{
|
||||
#if defined(GAINPUT_PLATFORM_TVOS)
|
||||
if (!controller)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
GCGamepad* gamepad = [controller gamepad];
|
||||
GCMicroGamepad* microGamepad = [controller microGamepad];
|
||||
GCExtendedGamepad* extgamepad = [controller extendedGamepad];
|
||||
GCMotion* motion = [controller motion];
|
||||
|
||||
return
|
||||
microGamepad != NULL &&
|
||||
motion != NULL &&
|
||||
gamepad == NULL &&
|
||||
extgamepad == NULL;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static GCController* getGcController(void* c)
|
||||
{
|
||||
return static_cast<GCController*>(c);
|
||||
}
|
||||
|
||||
static bool IsValidHardwareController(GCController const * controller)
|
||||
{
|
||||
if (controller == NULL) return false;
|
||||
|
||||
NSArray* controllers = [GCController controllers];
|
||||
const std::size_t controllerCount = [controllers count];
|
||||
|
||||
for (std::size_t i = 0; i < controllerCount; ++i)
|
||||
{
|
||||
GCController * currentController = controllers[i];
|
||||
|
||||
if (currentController == controller)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Removes all invalid controller mappings (controllers that are not available anymore)
|
||||
static void CleanDisconnectedControllersFromMapping()
|
||||
{
|
||||
if (!InputDevicePadImplIos::mappedControllers_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
InputDevicePadImplIos::GlobalControllerList& mapping = *InputDevicePadImplIos::mappedControllers_;
|
||||
for (InputDevicePadImplIos::GlobalControllerList::iterator it = mapping.begin(); it != mapping.end(); )
|
||||
{
|
||||
GCController const* controller = static_cast<GCController*>(*it);
|
||||
if (!IsValidHardwareController(controller))
|
||||
{
|
||||
it = mapping.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if this controller is already mapped to a gainput pad, otherwise false
|
||||
static bool IsMapped(GCController* controller)
|
||||
{
|
||||
if (0 == controller
|
||||
|| !InputDevicePadImplIos::mappedControllers_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
InputDevicePadImplIos::GlobalControllerList& mapping = *InputDevicePadImplIos::mappedControllers_;
|
||||
for(std::size_t index = 0; index < mapping.size(); ++index)
|
||||
{
|
||||
GCController const* mapped_controller = static_cast<GCController*>(mapping[index]);
|
||||
if (controller == mapped_controller)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns the first hardware controller that is not yet mapped
|
||||
static GCController* GetFirstNonMappedController()
|
||||
{
|
||||
NSArray* controllers = [GCController controllers];
|
||||
const std::size_t controllerCount = [controllers count];
|
||||
for (std::size_t i = 0; i < controllerCount; ++i)
|
||||
{
|
||||
GCController* currentController = controllers[i];
|
||||
if (!IsMapped(currentController))
|
||||
{
|
||||
return currentController;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InputDevicePadImplIos::InputDevicePadImplIos(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState) :
|
||||
manager_(manager),
|
||||
device_(device),
|
||||
index_(index),
|
||||
state_(state),
|
||||
previousState_(previousState),
|
||||
deviceState_(InputDevice::DS_UNAVAILABLE),
|
||||
pausePressed_(false),
|
||||
isMicro_(false),
|
||||
isNormal_(false),
|
||||
isExtended_(false),
|
||||
supportsMotion_(false),
|
||||
isRemote_(false),
|
||||
gcController_(0)
|
||||
{
|
||||
(void)&this->manager_;
|
||||
(void)&this->previousState_;
|
||||
|
||||
device_.SetDeadZone(PadButtonGyroscopeX, 0.1);
|
||||
device_.SetDeadZone(PadButtonGyroscopeY, 0.1);
|
||||
device_.SetDeadZone(PadButtonGyroscopeZ, 0.1);
|
||||
|
||||
if (!mappedControllers_)
|
||||
{
|
||||
mappedControllers_ = manager.GetAllocator().New<GlobalControllerList>(manager.GetAllocator());
|
||||
}
|
||||
}
|
||||
|
||||
InputDevicePadImplIos::~InputDevicePadImplIos()
|
||||
{
|
||||
}
|
||||
|
||||
void InputDevicePadImplIos::Update(InputDeltaState* delta)
|
||||
{
|
||||
bool validHardwareController = IsValidHardwareController(getGcController(gcController_));
|
||||
|
||||
if (!validHardwareController)
|
||||
{
|
||||
CleanDisconnectedControllersFromMapping();
|
||||
GCController * firstNonMappedController = GetFirstNonMappedController();
|
||||
|
||||
if (firstNonMappedController)
|
||||
{
|
||||
GCControllerPlayerIndex newIndex = static_cast<GCControllerPlayerIndex>(index_);
|
||||
if (firstNonMappedController.playerIndex != newIndex)
|
||||
{
|
||||
firstNonMappedController.playerIndex = newIndex;
|
||||
}
|
||||
|
||||
// register pause menu button handler
|
||||
__block InputDevicePadImplIos* block_deviceImpl = this;
|
||||
firstNonMappedController.controllerPausedHandler = ^(GCController* controller)
|
||||
{
|
||||
block_deviceImpl->pausePressed_ = true;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
deviceState_ = InputDevice::DS_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
gcController_ = firstNonMappedController;
|
||||
}
|
||||
|
||||
GAINPUT_ASSERT(gcController_);
|
||||
if (!gcController_)
|
||||
{
|
||||
deviceState_ = InputDevice::DS_UNAVAILABLE;
|
||||
isExtended_ = false;
|
||||
supportsMotion_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
deviceState_ = InputDevice::DS_OK;
|
||||
|
||||
GCController* controller = getGcController(gcController_);
|
||||
|
||||
isRemote_ = isAppleTvRemote(controller);
|
||||
isExtended_ = [controller extendedGamepad] != 0;
|
||||
#if defined(GAINPUT_PLATFORM_TVOS)
|
||||
isMicro_ = [controller microGamepad] != 0;
|
||||
#else
|
||||
isMicro_ = false;
|
||||
#endif
|
||||
isNormal_ = [controller gamepad] != 0;
|
||||
supportsMotion_ = [controller motion] != 0;
|
||||
|
||||
if (isRemote_)
|
||||
{
|
||||
UpdateRemote_(delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateGamepad_(delta);
|
||||
}
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonHome, pausePressed_);
|
||||
pausePressed_ = false;
|
||||
}
|
||||
|
||||
void InputDevicePadImplIos::UpdateRemote_(InputDeltaState* delta)
|
||||
{
|
||||
#if defined(GAINPUT_PLATFORM_TVOS)
|
||||
GCController* controller = getGcController(gcController_);
|
||||
|
||||
if (isMicro_)
|
||||
{
|
||||
GCMicroGamepad* gamepad = [controller microGamepad];
|
||||
gamepad.reportsAbsoluteDpadValues = YES;
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonA, gamepad.buttonA.pressed); // Force push on touch area
|
||||
HandleButton(device_, state_, delta, PadButtonX, gamepad.buttonX.pressed); // Play/Pause Button
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonAxis30, gamepad.dpad.xAxis.value); // Touch area X
|
||||
HandleAxis(device_, state_, delta, PadButtonAxis31, gamepad.dpad.yAxis.value); // Touch area Y
|
||||
}
|
||||
|
||||
if (supportsMotion_)
|
||||
{
|
||||
GCMotion* motion = [controller motion];
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonAccelerationX, motion.userAcceleration.x);
|
||||
HandleAxis(device_, state_, delta, PadButtonAccelerationY, motion.userAcceleration.y);
|
||||
HandleAxis(device_, state_, delta, PadButtonAccelerationZ, motion.userAcceleration.z);
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonGravityX, motion.gravity.x);
|
||||
HandleAxis(device_, state_, delta, PadButtonGravityY, motion.gravity.y);
|
||||
HandleAxis(device_, state_, delta, PadButtonGravityZ, motion.gravity.z);
|
||||
|
||||
// The Siri Remote does not have a gyro.
|
||||
HandleAxis(device_, state_, delta, PadButtonGyroscopeX, 0.0f);
|
||||
HandleAxis(device_, state_, delta, PadButtonGyroscopeY, 0.0f);
|
||||
HandleAxis(device_, state_, delta, PadButtonGyroscopeZ, 0.0f);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputDevicePadImplIos::UpdateGamepad_(InputDeltaState* delta)
|
||||
{
|
||||
GCController* controller = getGcController(gcController_);
|
||||
|
||||
if (isExtended_)
|
||||
{
|
||||
GCExtendedGamepad* gamepad = [controller extendedGamepad];
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonL1, gamepad.leftShoulder.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonR1, gamepad.rightShoulder.pressed);
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonLeft, gamepad.dpad.left.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonRight, gamepad.dpad.right.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonUp, gamepad.dpad.up.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonDown, gamepad.dpad.down.pressed);
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonA, gamepad.buttonA.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonB, gamepad.buttonB.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonX, gamepad.buttonX.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonY, gamepad.buttonY.pressed);
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonLeftStickX, gamepad.leftThumbstick.xAxis.value);
|
||||
HandleAxis(device_, state_, delta, PadButtonLeftStickY, gamepad.leftThumbstick.yAxis.value);
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonRightStickX, gamepad.rightThumbstick.xAxis.value);
|
||||
HandleAxis(device_, state_, delta, PadButtonRightStickY, gamepad.rightThumbstick.yAxis.value);
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonL2, gamepad.leftTrigger.pressed);
|
||||
HandleAxis(device_, state_, delta, PadButtonAxis4, gamepad.leftTrigger.value);
|
||||
HandleButton(device_, state_, delta, PadButtonR2, gamepad.rightTrigger.pressed);
|
||||
HandleAxis(device_, state_, delta, PadButtonAxis5, gamepad.rightTrigger.value);
|
||||
}
|
||||
else if (isNormal_)
|
||||
{
|
||||
GCGamepad* gamepad = [controller gamepad];
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonL1, gamepad.leftShoulder.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonR1, gamepad.rightShoulder.pressed);
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonLeft, gamepad.dpad.left.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonRight, gamepad.dpad.right.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonUp, gamepad.dpad.up.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonDown, gamepad.dpad.down.pressed);
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonA, gamepad.buttonA.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonB, gamepad.buttonB.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonX, gamepad.buttonX.pressed);
|
||||
HandleButton(device_, state_, delta, PadButtonY, gamepad.buttonY.pressed);
|
||||
}
|
||||
#if defined(GAINPUT_PLATFORM_TVOS)
|
||||
else if (isMicro_)
|
||||
{
|
||||
GCMicroGamepad * gamepad = [controller microGamepad];
|
||||
gamepad.reportsAbsoluteDpadValues = YES;
|
||||
HandleButton(device_, state_, delta, PadButtonA, gamepad.buttonA.pressed); // Force push on touch area
|
||||
HandleButton(device_, state_, delta, PadButtonX, gamepad.buttonX.pressed); // Play/Pause Button
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonAxis30, gamepad.dpad.xAxis.value); // Touch area X
|
||||
HandleAxis(device_, state_, delta, PadButtonAxis31, gamepad.dpad.yAxis.value); // Touch area Y
|
||||
}
|
||||
#endif
|
||||
|
||||
if (GCMotion* motion = [controller motion])
|
||||
{
|
||||
HandleAxis(device_, state_, delta, PadButtonAccelerationX, motion.userAcceleration.x);
|
||||
HandleAxis(device_, state_, delta, PadButtonAccelerationY, motion.userAcceleration.y);
|
||||
HandleAxis(device_, state_, delta, PadButtonAccelerationZ, motion.userAcceleration.z);
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonGravityX, motion.gravity.x);
|
||||
HandleAxis(device_, state_, delta, PadButtonGravityY, motion.gravity.y);
|
||||
HandleAxis(device_, state_, delta, PadButtonGravityZ, motion.gravity.z);
|
||||
|
||||
const float gyroX = 2.0f * (motion.attitude.x * motion.attitude.z + motion.attitude.w * motion.attitude.y);
|
||||
const float gyroY = 2.0f * (motion.attitude.y * motion.attitude.z - motion.attitude.w * motion.attitude.x);
|
||||
const float gyroZ = 1.0f - 2.0f * (motion.attitude.x * motion.attitude.x + motion.attitude.y * motion.attitude.y);
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonGyroscopeX, gyroX);
|
||||
HandleAxis(device_, state_, delta, PadButtonGyroscopeY, gyroY);
|
||||
HandleAxis(device_, state_, delta, PadButtonGyroscopeZ, gyroZ);
|
||||
}
|
||||
}
|
||||
|
||||
bool InputDevicePadImplIos::IsValidButton(DeviceButtonId deviceButton) const
|
||||
{
|
||||
if (supportsMotion_ && deviceButton >= PadButtonAccelerationX && deviceButton <= PadButtonMagneticFieldZ)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (isExtended_)
|
||||
{
|
||||
return (deviceButton >= PadButtonLeftStickX && deviceButton <= PadButtonAxis5)
|
||||
|| (deviceButton >= PadButtonLeft && deviceButton <= PadButtonR2)
|
||||
|| deviceButton == PadButtonHome;
|
||||
}
|
||||
return (deviceButton >= PadButtonLeft && deviceButton <= PadButtonR1)
|
||||
|| deviceButton == PadButtonHome;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
285
lib/source/gainput/pad/GainputInputDevicePadLinux.h
Normal file
285
lib/source/gainput/pad/GainputInputDevicePadLinux.h
Normal file
@@ -0,0 +1,285 @@
|
||||
|
||||
#ifndef GAINPUTINPUTDEVICEPADLINUX_H_
|
||||
#define GAINPUTINPUTDEVICEPADLINUX_H_
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/joystick.h>
|
||||
#include <errno.h>
|
||||
|
||||
// Cf. http://www.kernel.org/doc/Documentation/input/joystick-api.txt
|
||||
// Cf. http://ps3.jim.sh/sixaxis/usb/
|
||||
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
/// Maximum negative and positive value for an axis.
|
||||
const float MaxAxisValue = 32767.0f;
|
||||
|
||||
static const char* PadDeviceIds[MaxPadCount] =
|
||||
{
|
||||
"/dev/input/js0",
|
||||
"/dev/input/js1",
|
||||
"/dev/input/js2",
|
||||
"/dev/input/js3",
|
||||
"/dev/input/js4",
|
||||
"/dev/input/js5",
|
||||
"/dev/input/js6",
|
||||
"/dev/input/js7",
|
||||
"/dev/input/js8",
|
||||
"/dev/input/js9"
|
||||
};
|
||||
|
||||
class InputDevicePadImplLinux : public InputDevicePadImpl
|
||||
{
|
||||
public:
|
||||
InputDevicePadImplLinux(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState) :
|
||||
manager_(manager),
|
||||
device_(device),
|
||||
state_(state),
|
||||
index_(index),
|
||||
deviceState_(InputDevice::DS_UNAVAILABLE),
|
||||
fd_(-1),
|
||||
buttonDialect_(manager_.GetAllocator())
|
||||
{
|
||||
GAINPUT_ASSERT(index_ < MaxPadCount);
|
||||
CheckForDevice();
|
||||
}
|
||||
|
||||
~InputDevicePadImplLinux()
|
||||
{
|
||||
if (fd_ != -1)
|
||||
{
|
||||
close(fd_);
|
||||
}
|
||||
}
|
||||
|
||||
InputDevice::DeviceVariant GetVariant() const
|
||||
{
|
||||
return InputDevice::DV_STANDARD;
|
||||
}
|
||||
|
||||
void Update(InputDeltaState* delta)
|
||||
{
|
||||
CheckForDevice();
|
||||
|
||||
if (fd_ < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
js_event event;
|
||||
int c;
|
||||
|
||||
while ( (c = read(fd_, &event, sizeof(js_event))) == sizeof(js_event) )
|
||||
{
|
||||
event.type &= ~JS_EVENT_INIT;
|
||||
if (event.type == JS_EVENT_AXIS)
|
||||
{
|
||||
GAINPUT_ASSERT(event.number < PadButtonAxisCount_);
|
||||
DeviceButtonId buttonId = event.number;
|
||||
|
||||
const float value = float(event.value)/MaxAxisValue;
|
||||
|
||||
if (axisDialect_.count(buttonId))
|
||||
{
|
||||
buttonId = axisDialect_[buttonId];
|
||||
}
|
||||
|
||||
if (buttonId == PadButtonUp)
|
||||
{
|
||||
HandleButton(device_, state_, delta, PadButtonUp, value < 0.0f);
|
||||
HandleButton(device_, state_, delta, PadButtonDown, value > 0.0f);
|
||||
}
|
||||
else if (buttonId == PadButtonLeft)
|
||||
{
|
||||
HandleButton(device_, state_, delta, PadButtonLeft, value < 0.0f);
|
||||
HandleButton(device_, state_, delta, PadButtonRight, value > 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleAxis(device_, state_, delta, buttonId, value);
|
||||
}
|
||||
}
|
||||
else if (event.type == JS_EVENT_BUTTON)
|
||||
{
|
||||
GAINPUT_ASSERT(event.number < PadButtonCount_);
|
||||
if (buttonDialect_.count(event.number))
|
||||
{
|
||||
DeviceButtonId buttonId = buttonDialect_[event.number];
|
||||
const bool value(event.value);
|
||||
|
||||
HandleButton(device_, state_, delta, buttonId, value);
|
||||
}
|
||||
#ifdef GAINPUT_DEBUG
|
||||
else
|
||||
{
|
||||
GAINPUT_LOG("Unknown pad button #%d: %d\n", int(event.number), event.value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
GAINPUT_ASSERT(c == -1);
|
||||
|
||||
if (c == -1
|
||||
&& (errno == EBADF || errno == ECONNRESET || errno == ENOTCONN || errno == EIO || errno == ENXIO || errno == ENODEV))
|
||||
{
|
||||
#ifdef GAINPUT_DEBUG
|
||||
GAINPUT_LOG("Pad lost.\n");
|
||||
#endif
|
||||
deviceState_ = InputDevice::DS_UNAVAILABLE;
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
InputDevice::DeviceState GetState() const
|
||||
{
|
||||
return deviceState_;
|
||||
}
|
||||
|
||||
bool IsValidButton(DeviceButtonId deviceButton) const
|
||||
{
|
||||
if (buttonDialect_.empty())
|
||||
{
|
||||
return deviceButton < PadButtonMax_;
|
||||
}
|
||||
|
||||
for (HashMap<unsigned, DeviceButtonId>::const_iterator it = buttonDialect_.begin();
|
||||
it != buttonDialect_.end();
|
||||
++it)
|
||||
{
|
||||
if (it->second == deviceButton)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (HashMap<unsigned, DeviceButtonId>::const_iterator it = axisDialect_.begin();
|
||||
it != axisDialect_.end();
|
||||
++it)
|
||||
{
|
||||
if (it->second == deviceButton)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Vibrate(float /*leftMotor*/, float /*rightMotor*/)
|
||||
{
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
private:
|
||||
InputManager& manager_;
|
||||
InputDevice& device_;
|
||||
InputState& state_;
|
||||
unsigned index_;
|
||||
InputDevice::DeviceState deviceState_;
|
||||
int fd_;
|
||||
HashMap<unsigned, DeviceButtonId> buttonDialect_;
|
||||
HashMap<unsigned, DeviceButtonId> axisDialect_;
|
||||
|
||||
void CheckForDevice()
|
||||
{
|
||||
if (fd_ != -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
deviceState_ = InputDevice::DS_UNAVAILABLE;
|
||||
|
||||
fd_ = open(PadDeviceIds[index_], O_RDONLY | O_NONBLOCK);
|
||||
if (fd_ < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
GAINPUT_ASSERT(fd_ >= 0);
|
||||
|
||||
#ifdef GAINPUT_DEBUG
|
||||
char axesCount;
|
||||
ioctl(fd_, JSIOCGAXES, &axesCount);
|
||||
GAINPUT_LOG("Axes count: %d\n", int(axesCount));
|
||||
|
||||
int driverVersion;
|
||||
ioctl(fd_, JSIOCGVERSION, &driverVersion);
|
||||
GAINPUT_LOG("Driver version: %d\n", driverVersion);
|
||||
#endif
|
||||
|
||||
char name[128] = "";
|
||||
if (ioctl(fd_, JSIOCGNAME(sizeof(name)), name) < 0)
|
||||
{
|
||||
strncpy(name, "Unknown", sizeof(name));
|
||||
}
|
||||
#ifdef GAINPUT_DEBUG
|
||||
GAINPUT_LOG("Name: %s\n", name);
|
||||
#endif
|
||||
|
||||
for (unsigned i = PadButtonLeftStickX; i < PadButtonAxisCount_; ++i)
|
||||
{
|
||||
axisDialect_[i] = i;
|
||||
}
|
||||
|
||||
if (strcmp(name, "Sony PLAYSTATION(R)3 Controller") == 0)
|
||||
{
|
||||
#ifdef GAINPUT_DEBUG
|
||||
GAINPUT_LOG(" --> known controller\n");
|
||||
#endif
|
||||
buttonDialect_[0] = PadButtonSelect;
|
||||
buttonDialect_[1] = PadButtonL3;
|
||||
buttonDialect_[2] = PadButtonR3;
|
||||
buttonDialect_[3] = PadButtonStart;
|
||||
buttonDialect_[4] = PadButtonUp;
|
||||
buttonDialect_[5] = PadButtonRight;
|
||||
buttonDialect_[6] = PadButtonDown;
|
||||
buttonDialect_[7] = PadButtonLeft;
|
||||
buttonDialect_[8] = PadButtonL2;
|
||||
buttonDialect_[9] = PadButtonR2;
|
||||
buttonDialect_[10] = PadButtonL1;
|
||||
buttonDialect_[11] = PadButtonR1;
|
||||
buttonDialect_[12] = PadButtonY;
|
||||
buttonDialect_[13] = PadButtonB;
|
||||
buttonDialect_[14] = PadButtonA;
|
||||
buttonDialect_[15] = PadButtonX;
|
||||
buttonDialect_[16] = PadButtonHome;
|
||||
}
|
||||
else if (strcmp(name, "Microsoft X-Box 360 pad") == 0)
|
||||
{
|
||||
#ifdef GAINPUT_DEBUG
|
||||
GAINPUT_LOG(" --> known controller\n");
|
||||
#endif
|
||||
buttonDialect_[6] = PadButtonSelect;
|
||||
buttonDialect_[9] = PadButtonL3;
|
||||
buttonDialect_[10] = PadButtonR3;
|
||||
buttonDialect_[7] = PadButtonStart;
|
||||
buttonDialect_[4] = PadButtonL1;
|
||||
buttonDialect_[5] = PadButtonR1;
|
||||
buttonDialect_[3] = PadButtonY;
|
||||
buttonDialect_[1] = PadButtonB;
|
||||
buttonDialect_[0] = PadButtonA;
|
||||
buttonDialect_[2] = PadButtonX;
|
||||
buttonDialect_[8] = PadButtonHome;
|
||||
|
||||
axisDialect_[3] = PadButtonRightStickX;
|
||||
axisDialect_[4] = PadButtonRightStickY;
|
||||
axisDialect_[2] = PadButtonAxis4;
|
||||
axisDialect_[5] = PadButtonAxis5;
|
||||
axisDialect_[7] = PadButtonUp;
|
||||
axisDialect_[6] = PadButtonLeft;
|
||||
|
||||
// Dummy entries for IsValidButton
|
||||
axisDialect_[-1] = PadButtonDown;
|
||||
axisDialect_[-2] = PadButtonRight;
|
||||
}
|
||||
|
||||
deviceState_ = InputDevice::DS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
413
lib/source/gainput/pad/GainputInputDevicePadMac.cpp
Normal file
413
lib/source/gainput/pad/GainputInputDevicePadMac.cpp
Normal file
@@ -0,0 +1,413 @@
|
||||
|
||||
#include <gainput/gainput.h>
|
||||
|
||||
#ifdef GAINPUT_PLATFORM_MAC
|
||||
|
||||
#include "GainputInputDevicePadImpl.h"
|
||||
#include <gainput/GainputInputDeltaState.h>
|
||||
#include <gainput/GainputHelpers.h>
|
||||
#include <gainput/GainputLog.h>
|
||||
|
||||
#include "GainputInputDevicePadMac.h"
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <IOKit/hid/IOHIDManager.h>
|
||||
#import <IOKit/hid/IOHIDUsageTables.h>
|
||||
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
extern bool MacIsApplicationKey();
|
||||
|
||||
namespace {
|
||||
|
||||
static const unsigned kMaxPads = 16;
|
||||
static bool usedPadIndices_[kMaxPads] = { false };
|
||||
|
||||
static inline float FixUpAnalog(float analog, const float minAxis, const float maxAxis, bool symmetric)
|
||||
{
|
||||
analog = analog < minAxis ? minAxis : analog > maxAxis ? maxAxis : analog; // clamp
|
||||
analog -= minAxis;
|
||||
analog /= (Abs(minAxis) + Abs(maxAxis))*(symmetric ? 0.5f : 1.0f);
|
||||
if (symmetric)
|
||||
{
|
||||
analog -= 1.0f;
|
||||
}
|
||||
return analog;
|
||||
}
|
||||
|
||||
static void OnDeviceInput(void* inContext, IOReturn inResult, void* inSender, IOHIDValueRef value)
|
||||
{
|
||||
if (!MacIsApplicationKey())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IOHIDElementRef elem = IOHIDValueGetElement(value);
|
||||
|
||||
InputDevicePadImplMac* device = reinterpret_cast<InputDevicePadImplMac*>(inContext);
|
||||
GAINPUT_ASSERT(device);
|
||||
|
||||
uint32_t usagePage = IOHIDElementGetUsagePage(elem);
|
||||
uint32_t usage = IOHIDElementGetUsage(elem);
|
||||
|
||||
if (IOHIDElementGetReportCount(elem) > 1
|
||||
|| (usagePage == kHIDPage_GenericDesktop && usage == kHIDUsage_GD_Pointer) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (usagePage >= kHIDPage_VendorDefinedStart)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InputManager& manager = device->manager_;
|
||||
CFIndex state = (int)IOHIDValueGetIntegerValue(value);
|
||||
float analog = IOHIDValueGetScaledValue(value, kIOHIDValueScaleTypePhysical);
|
||||
|
||||
if (usagePage == kHIDPage_Button && device->buttonDialect_.count(usage))
|
||||
{
|
||||
const DeviceButtonId buttonId = device->buttonDialect_[usage];
|
||||
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, buttonId, state != 0);
|
||||
}
|
||||
else if (usagePage == kHIDPage_GenericDesktop)
|
||||
{
|
||||
if (usage == kHIDUsage_GD_Hatswitch)
|
||||
{
|
||||
int dpadX = 0;
|
||||
int dpadY = 0;
|
||||
switch(state)
|
||||
{
|
||||
case 0: dpadX = 0; dpadY = 1; break;
|
||||
case 1: dpadX = 1; dpadY = 1; break;
|
||||
case 2: dpadX = 1; dpadY = 0; break;
|
||||
case 3: dpadX = 1; dpadY = -1; break;
|
||||
case 4: dpadX = 0; dpadY = -1; break;
|
||||
case 5: dpadX = -1; dpadY = -1; break;
|
||||
case 6: dpadX = -1; dpadY = 0; break;
|
||||
case 7: dpadX = -1; dpadY = 1; break;
|
||||
default: dpadX = 0; dpadY = 0; break;
|
||||
}
|
||||
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, PadButtonLeft, dpadX < 0);
|
||||
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, PadButtonRight, dpadX > 0);
|
||||
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, PadButtonUp, dpadY > 0);
|
||||
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, PadButtonDown, dpadY < 0);
|
||||
}
|
||||
else if (device->axisDialect_.count(usage))
|
||||
{
|
||||
const DeviceButtonId buttonId = device->axisDialect_[usage];
|
||||
if (buttonId == PadButtonAxis4 || buttonId == PadButtonAxis5)
|
||||
{
|
||||
analog = FixUpAnalog(analog, device->minTriggerAxis_, device->maxTriggerAxis_, false);
|
||||
}
|
||||
else if (buttonId == PadButtonLeftStickY || buttonId == PadButtonRightStickY)
|
||||
{
|
||||
analog = -FixUpAnalog(analog, device->minAxis_, device->maxAxis_, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
analog = FixUpAnalog(analog, device->minAxis_, device->maxAxis_, true);
|
||||
}
|
||||
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, buttonId, analog);
|
||||
}
|
||||
else if (device->buttonDialect_.count(usage))
|
||||
{
|
||||
const DeviceButtonId buttonId = device->buttonDialect_[usage];
|
||||
manager.EnqueueConcurrentChange(device->device_, device->nextState_, device->delta_, buttonId, state != 0);
|
||||
}
|
||||
#ifdef GAINPUT_DEBUG
|
||||
else
|
||||
{
|
||||
GAINPUT_LOG("Unmapped button (generic): %d\n", usage);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef GAINPUT_DEBUG
|
||||
else
|
||||
{
|
||||
GAINPUT_LOG("Unmapped button: %d\n", usage);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void OnDeviceConnected(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef)
|
||||
{
|
||||
InputDevicePadImplMac* device = reinterpret_cast<InputDevicePadImplMac*>(inContext);
|
||||
GAINPUT_ASSERT(device);
|
||||
|
||||
if (device->deviceState_ != InputDevice::DS_UNAVAILABLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < device->index_ && i < kMaxPads; ++i)
|
||||
{
|
||||
if (!usedPadIndices_[i])
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (device->index_ < kMaxPads)
|
||||
{
|
||||
usedPadIndices_[device->index_] = true;
|
||||
}
|
||||
device->deviceState_ = InputDevice::DS_OK;
|
||||
|
||||
long vendorId = 0;
|
||||
long productId = 0;
|
||||
|
||||
if (CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey) ))
|
||||
{
|
||||
if (CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef))
|
||||
{
|
||||
CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &vendorId);
|
||||
}
|
||||
}
|
||||
if (CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey) ))
|
||||
{
|
||||
if (CFNumberGetTypeID() == CFGetTypeID(tCFTypeRef))
|
||||
{
|
||||
CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &productId);
|
||||
}
|
||||
}
|
||||
|
||||
if (vendorId == 0x054c && (productId == 0x5c4 || productId == 0x9cc)) // Sony DualShock 4
|
||||
{
|
||||
device->minAxis_ = 0;
|
||||
device->maxAxis_ = 256;
|
||||
device->minTriggerAxis_ = device->minAxis_;
|
||||
device->maxTriggerAxis_ = device->maxAxis_;
|
||||
device->axisDialect_[kHIDUsage_GD_X] = PadButtonLeftStickX;
|
||||
device->axisDialect_[kHIDUsage_GD_Y] = PadButtonLeftStickY;
|
||||
device->axisDialect_[kHIDUsage_GD_Z] = PadButtonRightStickX;
|
||||
device->axisDialect_[kHIDUsage_GD_Rz] = PadButtonRightStickY;
|
||||
device->axisDialect_[kHIDUsage_GD_Rx] = PadButtonAxis4;
|
||||
device->axisDialect_[kHIDUsage_GD_Ry] = PadButtonAxis5;
|
||||
device->buttonDialect_[0x09] = PadButtonSelect;
|
||||
device->buttonDialect_[0x0b] = PadButtonL3;
|
||||
device->buttonDialect_[0x0c] = PadButtonR3;
|
||||
device->buttonDialect_[0x0A] = PadButtonStart;
|
||||
device->buttonDialect_[0xfffffff0] = PadButtonUp;
|
||||
device->buttonDialect_[0xfffffff1] = PadButtonRight;
|
||||
device->buttonDialect_[0xfffffff2] = PadButtonDown;
|
||||
device->buttonDialect_[0xfffffff3] = PadButtonLeft;
|
||||
device->buttonDialect_[0x05] = PadButtonL1;
|
||||
device->buttonDialect_[0x07] = PadButtonL2;
|
||||
device->buttonDialect_[0x06] = PadButtonR1;
|
||||
device->buttonDialect_[0x08] = PadButtonR2;
|
||||
device->buttonDialect_[0x04] = PadButtonY;
|
||||
device->buttonDialect_[0x03] = PadButtonB;
|
||||
device->buttonDialect_[0x02] = PadButtonA;
|
||||
device->buttonDialect_[0x01] = PadButtonX;
|
||||
device->buttonDialect_[0x0d] = PadButtonHome;
|
||||
device->buttonDialect_[0x0e] = PadButton17; // Touch pad
|
||||
}
|
||||
else if (vendorId == 0x054c && productId == 0x268) // Sony DualShock 3
|
||||
{
|
||||
device->minAxis_ = 0;
|
||||
device->maxAxis_ = 256;
|
||||
device->minTriggerAxis_ = device->minAxis_;
|
||||
device->maxTriggerAxis_ = device->maxAxis_;
|
||||
device->axisDialect_[kHIDUsage_GD_X] = PadButtonLeftStickX;
|
||||
device->axisDialect_[kHIDUsage_GD_Y] = PadButtonLeftStickY;
|
||||
device->axisDialect_[kHIDUsage_GD_Z] = PadButtonRightStickX;
|
||||
device->axisDialect_[kHIDUsage_GD_Rz] = PadButtonRightStickY;
|
||||
device->axisDialect_[kHIDUsage_GD_Rx] = PadButtonAxis4;
|
||||
device->axisDialect_[kHIDUsage_GD_Ry] = PadButtonAxis5;
|
||||
//device->buttonDialect_[0] = PadButtonSelect;
|
||||
device->buttonDialect_[2] = PadButtonL3;
|
||||
device->buttonDialect_[3] = PadButtonR3;
|
||||
device->buttonDialect_[4] = PadButtonStart;
|
||||
device->buttonDialect_[5] = PadButtonUp;
|
||||
device->buttonDialect_[6] = PadButtonRight;
|
||||
device->buttonDialect_[7] = PadButtonDown;
|
||||
device->buttonDialect_[8] = PadButtonLeft;
|
||||
device->buttonDialect_[11] = PadButtonL1;
|
||||
device->buttonDialect_[9] = PadButtonL2;
|
||||
device->buttonDialect_[12] = PadButtonR1;
|
||||
device->buttonDialect_[10] = PadButtonR2;
|
||||
device->buttonDialect_[13] = PadButtonY;
|
||||
device->buttonDialect_[14] = PadButtonB;
|
||||
device->buttonDialect_[15] = PadButtonA;
|
||||
device->buttonDialect_[16] = PadButtonX;
|
||||
device->buttonDialect_[17] = PadButtonHome;
|
||||
}
|
||||
else if (vendorId == 0x045e && (productId == 0x028E || productId == 0x028F || productId == 0x02D1)) // Microsoft 360 Controller wired/wireless, Xbox One Controller
|
||||
{
|
||||
device->minAxis_ = -(1<<15);
|
||||
device->maxAxis_ = 1<<15;
|
||||
device->minTriggerAxis_ = 0;
|
||||
device->maxTriggerAxis_ = 255;
|
||||
device->axisDialect_[kHIDUsage_GD_X] = PadButtonLeftStickX;
|
||||
device->axisDialect_[kHIDUsage_GD_Y] = PadButtonLeftStickY;
|
||||
device->axisDialect_[kHIDUsage_GD_Rx] = PadButtonRightStickX;
|
||||
device->axisDialect_[kHIDUsage_GD_Ry] = PadButtonRightStickY;
|
||||
device->axisDialect_[kHIDUsage_GD_Z] = PadButtonAxis4;
|
||||
device->axisDialect_[kHIDUsage_GD_Rz] = PadButtonAxis5;
|
||||
device->buttonDialect_[0x0a] = PadButtonSelect;
|
||||
device->buttonDialect_[0x07] = PadButtonL3;
|
||||
device->buttonDialect_[0x08] = PadButtonR3;
|
||||
device->buttonDialect_[0x09] = PadButtonStart;
|
||||
device->buttonDialect_[0x0c] = PadButtonUp;
|
||||
device->buttonDialect_[0x0f] = PadButtonRight;
|
||||
device->buttonDialect_[0x0d] = PadButtonDown;
|
||||
device->buttonDialect_[0x0e] = PadButtonLeft;
|
||||
device->buttonDialect_[0x05] = PadButtonL1;
|
||||
device->buttonDialect_[0x06] = PadButtonR1;
|
||||
device->buttonDialect_[0x04] = PadButtonY;
|
||||
device->buttonDialect_[0x02] = PadButtonB;
|
||||
device->buttonDialect_[0x01] = PadButtonA;
|
||||
device->buttonDialect_[0x03] = PadButtonX;
|
||||
device->buttonDialect_[0x0b] = PadButtonHome;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnDeviceRemoved(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef)
|
||||
{
|
||||
InputDevicePadImplMac* device = reinterpret_cast<InputDevicePadImplMac*>(inContext);
|
||||
GAINPUT_ASSERT(device);
|
||||
device->deviceState_ = InputDevice::DS_UNAVAILABLE;
|
||||
if (device->index_ < kMaxPads)
|
||||
{
|
||||
usedPadIndices_[device->index_] = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InputDevicePadImplMac::InputDevicePadImplMac(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState) :
|
||||
buttonDialect_(manager.GetAllocator()),
|
||||
axisDialect_(manager.GetAllocator()),
|
||||
minAxis_(-FLT_MAX),
|
||||
maxAxis_(FLT_MAX),
|
||||
minTriggerAxis_(-FLT_MAX),
|
||||
maxTriggerAxis_(FLT_MAX),
|
||||
manager_(manager),
|
||||
device_(device),
|
||||
index_(index),
|
||||
state_(state),
|
||||
previousState_(previousState),
|
||||
nextState_(manager.GetAllocator(), PadButtonCount_ + PadButtonAxisCount_),
|
||||
deviceState_(InputDevice::DS_UNAVAILABLE),
|
||||
ioManager_(0)
|
||||
{
|
||||
IOHIDManagerRef ioManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDManagerOptionNone);
|
||||
|
||||
if (CFGetTypeID(ioManager) != IOHIDManagerGetTypeID())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ioManager_ = ioManager;
|
||||
|
||||
static const unsigned kKeyCount = 2;
|
||||
|
||||
CFStringRef keys[kKeyCount] = {
|
||||
CFSTR(kIOHIDDeviceUsagePageKey),
|
||||
CFSTR(kIOHIDDeviceUsageKey),
|
||||
};
|
||||
|
||||
int usagePage = kHIDPage_GenericDesktop;
|
||||
int usage = kHIDUsage_GD_GamePad;
|
||||
CFNumberRef values[kKeyCount] = {
|
||||
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usagePage),
|
||||
CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usage),
|
||||
};
|
||||
|
||||
CFMutableArrayRef matchingArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||
|
||||
CFDictionaryRef matchingDict = CFDictionaryCreate(kCFAllocatorDefault,
|
||||
(const void **) keys, (const void **) values, kKeyCount,
|
||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFArrayAppendValue(matchingArray, matchingDict);
|
||||
CFRelease(matchingDict);
|
||||
CFRelease(values[1]);
|
||||
|
||||
usage = kHIDUsage_GD_MultiAxisController;
|
||||
values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usage);
|
||||
|
||||
matchingDict = CFDictionaryCreate(kCFAllocatorDefault,
|
||||
(const void **) keys, (const void **) values, kKeyCount,
|
||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFArrayAppendValue(matchingArray, matchingDict);
|
||||
CFRelease(matchingDict);
|
||||
CFRelease(values[1]);
|
||||
|
||||
usage = kHIDUsage_GD_Joystick;
|
||||
values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usage);
|
||||
|
||||
matchingDict = CFDictionaryCreate(kCFAllocatorDefault,
|
||||
(const void **) keys, (const void **) values, kKeyCount,
|
||||
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFArrayAppendValue(matchingArray, matchingDict);
|
||||
CFRelease(matchingDict);
|
||||
|
||||
for (unsigned i = 0; i < kKeyCount; ++i)
|
||||
{
|
||||
CFRelease(keys[i]);
|
||||
CFRelease(values[i]);
|
||||
}
|
||||
|
||||
IOHIDManagerSetDeviceMatchingMultiple(ioManager, matchingArray);
|
||||
CFRelease(matchingArray);
|
||||
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(ioManager, OnDeviceConnected, this);
|
||||
IOHIDManagerRegisterDeviceRemovalCallback(ioManager, OnDeviceRemoved, this);
|
||||
IOHIDManagerRegisterInputValueCallback(ioManager, OnDeviceInput, this);
|
||||
|
||||
IOHIDManagerOpen(ioManager, kIOHIDOptionsTypeNone);
|
||||
|
||||
IOHIDManagerScheduleWithRunLoop(ioManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
}
|
||||
|
||||
InputDevicePadImplMac::~InputDevicePadImplMac()
|
||||
{
|
||||
IOHIDManagerRef ioManager = reinterpret_cast<IOHIDManagerRef>(ioManager_);
|
||||
IOHIDManagerUnscheduleFromRunLoop(ioManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOHIDManagerClose(ioManager, 0);
|
||||
CFRelease(ioManager);
|
||||
}
|
||||
|
||||
void InputDevicePadImplMac::Update(InputDeltaState* delta)
|
||||
{
|
||||
delta_ = delta;
|
||||
state_ = nextState_;
|
||||
}
|
||||
|
||||
bool InputDevicePadImplMac::IsValidButton(DeviceButtonId deviceButton) const
|
||||
{
|
||||
if (buttonDialect_.empty())
|
||||
{
|
||||
return deviceButton < PadButtonMax_;
|
||||
}
|
||||
|
||||
for (HashMap<unsigned, DeviceButtonId>::const_iterator it = buttonDialect_.begin();
|
||||
it != buttonDialect_.end();
|
||||
++it)
|
||||
{
|
||||
if (it->second == deviceButton)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (HashMap<unsigned, DeviceButtonId>::const_iterator it = axisDialect_.begin();
|
||||
it != axisDialect_.end();
|
||||
++it)
|
||||
{
|
||||
if (it->second == deviceButton)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
57
lib/source/gainput/pad/GainputInputDevicePadMac.h
Normal file
57
lib/source/gainput/pad/GainputInputDevicePadMac.h
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
#ifndef GAINPUTINPUTDEVICEPADMAC_H_
|
||||
#define GAINPUTINPUTDEVICEPADMAC_H_
|
||||
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
class InputDevicePadImplMac : public InputDevicePadImpl
|
||||
{
|
||||
public:
|
||||
InputDevicePadImplMac(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState);
|
||||
~InputDevicePadImplMac();
|
||||
|
||||
InputDevice::DeviceVariant GetVariant() const
|
||||
{
|
||||
return InputDevice::DV_STANDARD;
|
||||
}
|
||||
|
||||
void Update(InputDeltaState* delta);
|
||||
|
||||
InputDevice::DeviceState GetState() const
|
||||
{
|
||||
return deviceState_;
|
||||
}
|
||||
|
||||
bool IsValidButton(DeviceButtonId deviceButton) const;
|
||||
|
||||
bool Vibrate(float leftMotor, float rightMotor)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HashMap<unsigned, DeviceButtonId> buttonDialect_;
|
||||
HashMap<unsigned, DeviceButtonId> axisDialect_;
|
||||
float minAxis_;
|
||||
float maxAxis_;
|
||||
float minTriggerAxis_;
|
||||
float maxTriggerAxis_;
|
||||
InputManager& manager_;
|
||||
InputDevice& device_;
|
||||
unsigned index_;
|
||||
InputState& state_;
|
||||
InputState& previousState_;
|
||||
InputState nextState_;
|
||||
InputDeltaState* delta_;
|
||||
InputDevice::DeviceState deviceState_;
|
||||
|
||||
void* ioManager_;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
43
lib/source/gainput/pad/GainputInputDevicePadNull.h
Normal file
43
lib/source/gainput/pad/GainputInputDevicePadNull.h
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
#ifndef GAINPUTINPUTDEVICEPADNULL_H_
|
||||
#define GAINPUTINPUTDEVICEPADNULL_H_
|
||||
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
class InputDevicePadImplNull : public InputDevicePadImpl
|
||||
{
|
||||
public:
|
||||
InputDevicePadImplNull(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState)
|
||||
{
|
||||
}
|
||||
|
||||
InputDevice::DeviceVariant GetVariant() const
|
||||
{
|
||||
return InputDevice::DV_NULL;
|
||||
}
|
||||
|
||||
void Update(InputDeltaState* /*delta*/)
|
||||
{
|
||||
}
|
||||
|
||||
InputDevice::DeviceState GetState() const
|
||||
{
|
||||
return InputDevice::DS_OK;
|
||||
}
|
||||
|
||||
bool IsValidButton(DeviceButtonId /*deviceButton*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Vibrate(float /*leftMotor*/, float /*rightMotor*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
165
lib/source/gainput/pad/GainputInputDevicePadWin.h
Normal file
165
lib/source/gainput/pad/GainputInputDevicePadWin.h
Normal file
@@ -0,0 +1,165 @@
|
||||
|
||||
#ifndef GAINPUTINPUTDEVICEPADWIN_H_
|
||||
#define GAINPUTINPUTDEVICEPADWIN_H_
|
||||
|
||||
// Cf. http://msdn.microsoft.com/en-us/library/windows/desktop/ee417005%28v=vs.85%29.aspx
|
||||
|
||||
#include "../GainputWindows.h"
|
||||
#include <XInput.h>
|
||||
|
||||
namespace gainput
|
||||
{
|
||||
|
||||
|
||||
const float MaxTriggerValue = 255.0f;
|
||||
const float MaxAxisValue = 32767.0f;
|
||||
const float MaxNegativeAxisValue = 32768.0f;
|
||||
const float MaxMotorSpeed = 65535.0f;
|
||||
|
||||
|
||||
class InputDevicePadImplWin : public InputDevicePadImpl
|
||||
{
|
||||
public:
|
||||
InputDevicePadImplWin(InputManager& manager, InputDevice& device, unsigned index, InputState& state, InputState& previousState) :
|
||||
manager_(manager),
|
||||
device_(device),
|
||||
state_(state),
|
||||
previousState_(previousState),
|
||||
deviceState_(InputDevice::DS_UNAVAILABLE),
|
||||
lastPacketNumber_(-1),
|
||||
hasBattery_(false)
|
||||
{
|
||||
padIndex_ = index;
|
||||
GAINPUT_ASSERT(padIndex_ < MaxPadCount);
|
||||
|
||||
#if 0
|
||||
XINPUT_BATTERY_INFORMATION xbattery;
|
||||
DWORD result = XInputGetBatteryInformation(padIndex, BATTERY_DEVTYPE_GAMEPAD, &xbattery);
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
hasBattery = (xbattery.BatteryType == BATTERY_TYPE_ALKALINE
|
||||
|| xbattery.BatteryType == BATTERY_TYPE_NIMH);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
InputDevice::DeviceVariant GetVariant() const
|
||||
{
|
||||
return InputDevice::DV_STANDARD;
|
||||
}
|
||||
|
||||
void Update(InputDeltaState* delta)
|
||||
{
|
||||
XINPUT_STATE xstate;
|
||||
DWORD result = XInputGetState(padIndex_, &xstate);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
deviceState_ = InputDevice::DS_UNAVAILABLE;
|
||||
return;
|
||||
}
|
||||
|
||||
deviceState_ = InputDevice::DS_OK;
|
||||
|
||||
#if 0
|
||||
if (hasBattery)
|
||||
{
|
||||
XINPUT_BATTERY_INFORMATION xbattery;
|
||||
result = XInputGetBatteryInformation(padIndex, BATTERY_DEVTYPE_GAMEPAD, &xbattery);
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
if (xbattery.BatteryType == BATTERY_TYPE_ALKALINE
|
||||
|| xbattery.BatteryType == BATTERY_TYPE_NIMH)
|
||||
{
|
||||
if (xbattery.BatteryLevel == BATTERY_LEVEL_EMPTY
|
||||
|| xbattery.BatteryLevel == BATTERY_LEVEL_LOW)
|
||||
{
|
||||
deviceState = InputDevice::DS_LOW_BATTERY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (xstate.dwPacketNumber == lastPacketNumber_)
|
||||
{
|
||||
// Not changed
|
||||
return;
|
||||
}
|
||||
|
||||
lastPacketNumber_ = xstate.dwPacketNumber;
|
||||
|
||||
HandleButton(device_, state_, delta, PadButtonUp, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonDown, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonLeft, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonRight, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonA, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_A) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonB, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_B) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonX, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_X) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonY, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_Y) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonStart, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_START) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonSelect, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonL3, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonR3, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonL1, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonR1, (xstate.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonL2, xstate.Gamepad.bLeftTrigger != 0);
|
||||
HandleButton(device_, state_, delta, PadButtonR2, xstate.Gamepad.bRightTrigger != 0);
|
||||
|
||||
HandleAxis(device_, state_, delta, PadButtonAxis4, float(xstate.Gamepad.bLeftTrigger)/MaxTriggerValue);
|
||||
HandleAxis(device_, state_, delta, PadButtonAxis5, float(xstate.Gamepad.bRightTrigger)/MaxTriggerValue);
|
||||
HandleAxis(device_, state_, delta, PadButtonLeftStickX, GetAxisValue(xstate.Gamepad.sThumbLX));
|
||||
HandleAxis(device_, state_, delta, PadButtonLeftStickY, GetAxisValue(xstate.Gamepad.sThumbLY));
|
||||
HandleAxis(device_, state_, delta, PadButtonRightStickX, GetAxisValue(xstate.Gamepad.sThumbRX));
|
||||
HandleAxis(device_, state_, delta, PadButtonRightStickY, GetAxisValue(xstate.Gamepad.sThumbRY));
|
||||
}
|
||||
|
||||
InputDevice::DeviceState GetState() const
|
||||
{
|
||||
return deviceState_;
|
||||
}
|
||||
|
||||
bool IsValidButton(DeviceButtonId deviceButton) const
|
||||
{
|
||||
return deviceButton < PadButtonAxis4 || (deviceButton >= PadButtonStart && deviceButton <= PadButtonR3);
|
||||
}
|
||||
|
||||
bool Vibrate(float leftMotor, float rightMotor)
|
||||
{
|
||||
GAINPUT_ASSERT(leftMotor >= 0.0f && leftMotor <= 1.0f);
|
||||
GAINPUT_ASSERT(rightMotor >= 0.0f && rightMotor <= 1.0f);
|
||||
XINPUT_VIBRATION xvibration;
|
||||
xvibration.wLeftMotorSpeed = static_cast<WORD>(leftMotor*MaxMotorSpeed);
|
||||
xvibration.wRightMotorSpeed = static_cast<WORD>(rightMotor*MaxMotorSpeed);
|
||||
DWORD result = XInputSetState(padIndex_, &xvibration);
|
||||
return result == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
private:
|
||||
InputManager& manager_;
|
||||
InputDevice& device_;
|
||||
InputState& state_;
|
||||
InputState& previousState_;
|
||||
InputDevice::DeviceState deviceState_;
|
||||
unsigned padIndex_;
|
||||
DWORD lastPacketNumber_;
|
||||
bool hasBattery_;
|
||||
|
||||
static float GetAxisValue(SHORT value)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
return float(value) / MaxNegativeAxisValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return float(value) / MaxAxisValue;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user