Squashed 'external/gainput/' content from commit 2be0a50

git-subtree-dir: external/gainput
git-subtree-split: 2be0a50089eafcc6fccb66142180082e48f27f4c
This commit is contained in:
Simone
2024-01-22 08:51:55 +01:00
commit 4e42229bdd
170 changed files with 31921 additions and 0 deletions

View File

@@ -0,0 +1,228 @@
#ifndef GAINPUTALLOCATOR_H_
#define GAINPUTALLOCATOR_H_
namespace gainput
{
/// Interface used to pass custom allocators to the library.
/**
* If you want the library to use your custom allocator you should implement this interface.
* Specifically, you should provide implementations for the Allocate() and Deallocate()
* functions. All other (template) member functions are simply based on those two functions.
*
* \sa DefaultAllocator
*/
class GAINPUT_LIBEXPORT Allocator
{
public:
enum { DefaultAlign = 0 };
/// Allocates a number of bytes and returns a pointer to the allocated memory.
/**
* \param size The number of bytes to allocate.
* \return A memory block encompassing at least size bytes.
*/
virtual void* Allocate(size_t size, size_t align = DefaultAlign) = 0;
/// Deallocates the given memory.
/**
* \param ptr The memory block to deallocate.
*/
virtual void Deallocate(void* ptr) = 0;
/// An operator new-like function that allocates memory and calls T's constructor.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T>
T* New()
{
return new (Allocate(sizeof(T))) T();
}
/// An operator new-like function that allocates memory and calls T's constructor with one parameter.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0>
T* New(P0& p0)
{
return new (Allocate(sizeof(T))) T(p0);
}
/// An operator new-like function that allocates memory and calls T's constructor with one parameter.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0>
T* New(const P0& p0)
{
return new (Allocate(sizeof(T))) T(p0);
}
/// An operator new-like function that allocates memory and calls T's constructor with two parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1>
T* New(P0& p0, P1& p1)
{
return new (Allocate(sizeof(T))) T(p0, p1);
}
/// An operator new-like function that allocates memory and calls T's constructor with two parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1>
T* New(const P0& p0, P1& p1)
{
return new (Allocate(sizeof(T))) T(p0, p1);
}
/// An operator new-like function that allocates memory and calls T's constructor with two parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1>
T* New(P0& p0, const P1& p1)
{
return new (Allocate(sizeof(T))) T(p0, p1);
}
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1, class P2>
T* New(P0& p0, const P1& p1, const P2& p2)
{
return new (Allocate(sizeof(T))) T(p0, p1, p2);
}
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1, class P2>
T* New(P0& p0, const P1& p1, P2& p2)
{
return new (Allocate(sizeof(T))) T(p0, p1, p2);
}
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1, class P2, class P3>
T* New(P0& p0, P1& p1, P2& p2, P3& p3)
{
return new (Allocate(sizeof(T))) T(p0, p1, p2, p3);
}
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1, class P2, class P3>
T* New(P0& p0, const P1& p1, P2& p2, P3& p3)
{
return new (Allocate(sizeof(T))) T(p0, p1, p2, p3);
}
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1, class P2, class P3, class P4>
T* New(P0& p0, P1& p1, P2& p2, P3& p3, P4& p4)
{
return new (Allocate(sizeof(T))) T(p0, p1, p2, p3, p4);
}
/// An operator new-like function that allocates memory and calls T's constructor with the given parameters.
/**
* \return A pointer to an initialized instance of T.
*/
template <class T, class P0, class P1, class P2, class P3, class P4>
T* New(P0& p0, const P1& p1, P2& p2, P3& p3, P4& p4)
{
return new (Allocate(sizeof(T))) T(p0, p1, p2, p3, p4);
}
/// An operator delete-like function that calls ptr's constructor and deallocates the memory.
/**
* \param ptr The object to destruct and deallocate.
*/
template <class T>
void Delete(T* ptr)
{
if (ptr)
{
ptr->~T();
Deallocate(ptr);
}
}
};
/// The default allocator used by the library.
/**
* Any allocation/deallocation calls are simply forwarded to \c malloc and \c free. Any
* requested alignment is ignored.
*/
class GAINPUT_LIBEXPORT DefaultAllocator : public Allocator
{
public:
void* Allocate(size_t size, size_t /*align*/)
{
return malloc(size);
}
void Deallocate(void* ptr)
{
free(ptr);
}
};
/// Returns the default instance of the default allocator.
/**
* \sa DefaultAllocator
*/
GAINPUT_LIBEXPORT DefaultAllocator& GetDefaultAllocator();
template<class K, class V>
class GAINPUT_LIBEXPORT HashMap;
/// An allocator that tracks an allocations that were done
/**
* Any allocation/deallocation calls are simply forwarded to \c malloc and \c free. Any
* requested alignment is ignored.
*/
class GAINPUT_LIBEXPORT TrackingAllocator : public Allocator
{
public:
TrackingAllocator(Allocator& backingAllocator, Allocator& internalAllocator = GetDefaultAllocator());
~TrackingAllocator();
void* Allocate(size_t size, size_t align = DefaultAlign);
void Deallocate(void* ptr);
size_t GetAllocateCount() const { return allocateCount_; }
size_t GetDeallocateCount() const { return deallocateCount_; }
size_t GetAllocatedMemory() const { return allocatedMemory_; }
private:
Allocator& backingAllocator_;
Allocator& internalAllocator_;
HashMap<void*, size_t>* allocations_;
size_t allocateCount_;
size_t deallocateCount_;
size_t allocatedMemory_;
};
}
#endif

View File

@@ -0,0 +1,508 @@
#ifndef GAINPUTCONTAINERS_H_
#define GAINPUTCONTAINERS_H_
namespace gainput
{
// -- MurmurHash3 begin --
// http://code.google.com/p/smhasher/wiki/MurmurHash3
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
inline uint32_t rotl32(uint32_t x, int8_t r)
{
return (x << r) | (x >> (32 - r));
}
inline uint32_t getblock(const uint32_t * p, int i)
{
return p[i];
}
inline uint32_t fmix(uint32_t h)
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
/// Calculates MurmurHash3 for the given key.
/**
* \param key The key to calculate the hash of.
* \param len Length of the key in bytes.
* \param seed Seed for the hash.
* \param[out] out The hash value, a uint32_t in this case.
*/
inline void MurmurHash3_x86_32(const void * key, int len, uint32_t seed, void * out)
{
const uint8_t * data = (const uint8_t*)key;
const int nblocks = len / 4;
uint32_t h1 = seed;
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
for(int i = -nblocks; i; i++)
{
uint32_t k1 = getblock(blocks,i);
k1 *= c1;
k1 = rotl32(k1,15);
k1 *= c2;
h1 ^= k1;
h1 = rotl32(h1,13);
h1 = h1*5+0xe6546b64;
}
const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
uint32_t k1 = 0;
switch(len & 3)
{
case 3: k1 ^= tail[2] << 16;
case 2: k1 ^= tail[1] << 8;
case 1: k1 ^= tail[0];
k1 *= c1; k1 = rotl32(k1,15); k1 *= c2; h1 ^= k1;
};
h1 ^= len;
h1 = fmix(h1);
*(uint32_t*)out = h1;
}
// -- MurmurHash3 end --
/// A std::vector-like data container for POD-types.
/**
* \tparam T A POD-type to hold in this container.
*/
template<class T>
class GAINPUT_LIBEXPORT Array
{
public:
static const size_t DefaultCapacity = 8;
typedef T* iterator;
typedef const T* const_iterator;
typedef T value_type;
Array(Allocator& allocator, size_t capacity = DefaultCapacity) :
allocator_(allocator),
size_(0),
capacity_(capacity)
{
data_ = static_cast<T*>(allocator_.Allocate(sizeof(T)*capacity_));
}
~Array()
{
allocator_.Delete(data_);
}
iterator begin() { return data_; }
const_iterator begin() const { return data_; }
iterator end() { return data_ + size_; }
const_iterator end() const { return data_ + size_; }
T& operator[] (size_t i)
{
GAINPUT_ASSERT(i < size_);
return data_[i];
}
const T& operator[] (size_t i) const
{
GAINPUT_ASSERT(i < size_);
return data_[i];
}
void push_back(const value_type& val)
{
if (size_ + 1 > capacity_)
{
reserve(size_ + 1);
}
data_[size_++] = val;
}
void pop_back()
{
if (size_ > 0)
--size_;
}
void reserve(size_t capacity)
{
if (capacity <= capacity_)
return;
capacity = (capacity_*2) < capacity ? capacity : (capacity_*2);
T* newData = static_cast<T*>(allocator_.Allocate(sizeof(T)*capacity));
memcpy(newData, data_, sizeof(T)*capacity_);
allocator_.Deallocate(data_);
data_ = newData;
capacity_ = capacity;
}
void swap(Array<T>& x)
{
GAINPUT_ASSERT(&allocator_ == &x.allocator_);
const size_t thisSize = size_;
const size_t capacity = capacity_;
T* data = data_;
size_ = x.size_;
capacity_ = x.capacity_;
data_ = x.data_;
x.size_ = thisSize;
x.capacity_ = capacity;
x.data_ = data;
}
iterator erase(iterator pos)
{
if (size_ == 0)
return end();
GAINPUT_ASSERT(pos >= begin() && pos < end());
memcpy(pos, pos+1, sizeof(T)*(end()-(pos+1)));
--size_;
return pos;
}
void clear() { size_ = 0; }
bool empty() const { return size_ == 0; }
size_t size() const { return size_; }
iterator find(const value_type& val)
{
for (size_t i = 0; i < size_; ++i)
{
if (data_[i] == val)
{
return data_ + i;
}
}
return end();
}
const_iterator find(const value_type& val) const
{
for (size_t i = 0; i < size_; ++i)
{
if (data_[i] == val)
{
return data_ + i;
}
}
return end();
}
private:
Allocator& allocator_;
size_t size_;
size_t capacity_;
T* data_;
};
/// A hash table mapping keys to POD-type values.
/**
* \tparam K The key pointing to a value.
* \tparam V POD-type being stored in the table.
*/
template<class K, class V>
class GAINPUT_LIBEXPORT HashMap
{
public:
static const unsigned Seed = 329856235;
enum { InvalidKey = unsigned(-1) };
/// An element of the hash table.
struct Node
{
K first; ///< The element's key.
V second; ///< The element's value.
uint32_t next; ///< The index of the next element with the same (wrapped) hash; Do not use.
};
typedef Node* iterator;
typedef const Node* const_iterator;
HashMap(Allocator& allocator = GetDefaultAllocator()) :
allocator_(allocator),
keys_(allocator_),
values_(allocator_),
size_(0)
{ }
iterator begin() { return values_.begin(); }
const_iterator begin() const { return values_.begin(); }
iterator end() { return values_.begin() + values_.size(); }
const_iterator end() const { return values_.begin() + values_.size(); }
size_t size() const { return size_; }
bool empty() const { return size_ == 0; }
size_t count(const K& k) const
{
return find(k) != end() ? 1 : 0;
}
iterator find(const K& k)
{
if (keys_.empty() || values_.empty())
return end();
uint32_t h;
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
const uint32_t ha = h % keys_.size();
volatile uint32_t vi = keys_[ha];
while (vi != InvalidKey)
{
if (values_[vi].first == k)
{
return &values_[vi];
}
vi = values_[vi].next;
}
return end();
}
const_iterator find(const K& k) const
{
if (keys_.empty() || values_.empty())
return end();
uint32_t h;
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
const uint32_t ha = h % keys_.size();
volatile uint32_t vi = keys_[ha];
while (vi != InvalidKey)
{
if (values_[vi].first == k)
{
return &values_[vi];
}
vi = values_[vi].next;
}
return end();
}
iterator insert(const K& k, const V& v)
{
if (values_.size() >= 0.6f*keys_.size())
{
Rehash(values_.size()*2 + 10);
}
uint32_t h;
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
const uint32_t ha = h % keys_.size();
uint32_t vi = keys_[ha];
if (vi == InvalidKey)
{
keys_[ha] = values_.size();
}
else
{
for (;;)
{
if (values_[vi].next == InvalidKey)
{
values_[vi].next = values_.size();
break;
}
else
{
vi = values_[vi].next;
}
}
}
Node node;
node.first = k;
node.second = v;
node.next = InvalidKey;
values_.push_back(node);
++size_;
return &values_[values_.size()-1];
}
V& operator[] (const K& k)
{
iterator it = find(k);
if (it == end())
{
return insert(k, V())->second;
}
else
{
return it->second;
}
}
size_t erase(const K& k)
{
if (keys_.empty())
return 0;
uint32_t h;
MurmurHash3_x86_32(&k, sizeof(K), Seed, &h);
const uint32_t ha = h % keys_.size();
uint32_t vi = keys_[ha];
uint32_t prevVi = InvalidKey;
while (vi != InvalidKey)
{
if (values_[vi].first == k)
{
if (prevVi == InvalidKey)
{
keys_[ha] = values_[vi].next;
}
else
{
values_[prevVi].next = values_[vi].next;
}
--size_;
if (vi == values_.size() - 1)
{
values_.pop_back();
return 1;
}
else
{
size_t lastVi = values_.size()-1;
values_[vi] = values_[lastVi];
values_.pop_back();
for (typename Array<uint32_t>::iterator it = keys_.begin(); it != keys_.end(); ++it)
{
if (*it == lastVi)
{
*it = vi;
break;
}
}
for (typename Array<Node>::iterator it = values_.begin(); it != values_.end(); ++it)
{
if (it->next == lastVi)
{
it->next = vi;
break;
}
}
return 1;
}
}
prevVi = vi;
vi = values_[vi].next;
}
return 0;
}
void clear()
{
keys_.clear();
values_.clear();
}
private:
Allocator& allocator_;
Array<uint32_t> keys_;
Array<Node> values_;
size_t size_;
void Rehash(size_t newSize)
{
Array<uint32_t> keys(allocator_, newSize);
Array<Node> values(allocator_, values_.size());
for (size_t i = 0; i < newSize; ++i)
keys.push_back(InvalidKey);
keys_.swap(keys);
values_.swap(values);
size_ = 0;
for (typename Array<Node>::const_iterator it = values.begin();
it != values.end();
++it)
{
insert(it->first, it->second);
}
}
};
/// A ring buffer.
/**
* \tparam N The number of elements that can be stored in the ring buffer.
* \tparam T Type of the elements stored in the ring buffer.
*/
template<int N, class T>
class GAINPUT_LIBEXPORT RingBuffer
{
public:
RingBuffer() :
nextRead_(0),
nextWrite_(0)
{ }
bool CanGet() const
{
return nextRead_ < nextWrite_;
}
size_t GetCount() const
{
const size_t d = nextWrite_ - nextRead_;
return d > N ? N : d;
}
T Get()
{
return buf_[(nextRead_++) % N];
}
void Put(T d)
{
buf_[(nextWrite_++) % N] = d;
while (nextRead_ + N < nextWrite_)
++nextRead_;
}
private:
T buf_[N];
size_t nextRead_;
size_t nextWrite_;
};
}
#endif

View File

@@ -0,0 +1,34 @@
#ifndef GAINPUTDEBUGRENDERER_H_
#define GAINPUTDEBUGRENDERER_H_
namespace gainput
{
/// Interface for debug rendering of input device states.
/**
* Coordinates and other measures passed to the interface's functions are in the
* range of 0.0f to 1.0f.
*
* The functions are called as part InputManager::Update().
*/
class GAINPUT_LIBEXPORT DebugRenderer
{
public:
/// Empty virtual destructor.
virtual ~DebugRenderer() { }
/// Called to draw a circle with the given radius.
virtual void DrawCircle(float x, float y, float radius) = 0;
/// Called to draw a line between the two given points.
virtual void DrawLine(float x1, float y1, float x2, float y2) = 0;
/// Called to draw some text at the given position.
virtual void DrawText(float x, float y, const char* const text) = 0;
};
}
#endif

View File

@@ -0,0 +1,71 @@
#ifndef GAINPUTHELPERS_H_
#define GAINPUTHELPERS_H_
#include <gainput/GainputLog.h>
namespace gainput
{
inline void HandleButton(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, bool value)
{
#ifdef GAINPUT_DEBUG
if (value != state.GetBool(buttonId))
{
GAINPUT_LOG("Button changed: %d, %i\n", buttonId, value);
}
#endif
if (delta)
{
const bool oldValue = state.GetBool(buttonId);
if (value != oldValue)
{
delta->AddChange(device.GetDeviceId(), buttonId, oldValue, value);
}
}
state.Set(buttonId, value);
}
inline void HandleAxis(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, float value)
{
const float deadZone = device.GetDeadZone(buttonId);
if (deadZone > 0.0f)
{
const float absValue = Abs(value);
const float sign = value < 0.0f ? -1.0f : 1.0f;
if (absValue < deadZone)
{
value = 0.0f;
}
else
{
value -= sign*deadZone;
value *= 1.0f / (1.0f - deadZone);
}
}
#ifdef GAINPUT_DEBUG
if (value != state.GetFloat(buttonId))
{
GAINPUT_LOG("Axis changed: %d, %f\n", buttonId, value);
}
#endif
if (delta)
{
const float oldValue = state.GetFloat(buttonId);
if (value != oldValue)
{
delta->AddChange(device.GetDeviceId(), buttonId, oldValue, value);
}
}
state.Set(buttonId, value);
}
}
#endif

View File

@@ -0,0 +1,59 @@
#ifndef GAINPUTINPUTDELTASTATE_H_
#define GAINPUTINPUTDELTASTATE_H_
namespace gainput
{
/// Stores a list of input state changes.
class GAINPUT_LIBEXPORT InputDeltaState
{
public:
InputDeltaState(Allocator& allocator);
/// Add a state change for a bool-type button.
/**
* \param device The input device the change occurred on.
* \param deviceButton The input button that was changed.
* \param oldValue The old button state.
* \param newValue The new button state.
*/
void AddChange(DeviceId device, DeviceButtonId deviceButton, bool oldValue, bool newValue);
/// Add a state change for a float-type button.
/**
* \param device The input device the change occurred on.
* \param deviceButton The input button that was changed.
* \param oldValue The old button state.
* \param newValue The new button state.
*/
void AddChange(DeviceId device, DeviceButtonId deviceButton, float oldValue, float newValue);
/// Clear list of state changes.
void Clear();
/// Notifies all input listeners of the previously recorded state changes.
/**
* \param listeners A list of input listeners to notify.
*/
void NotifyListeners(Array<InputListener*>& listeners) const;
private:
struct Change
{
DeviceId device;
DeviceButtonId deviceButton;
ButtonType type;
union
{
bool b;
float f;
} oldValue, newValue;
};
Array<Change> changes_;
};
}
#endif

View File

@@ -0,0 +1,271 @@
#ifndef GAINPUTINPUTDEVICE_H_
#define GAINPUTINPUTDEVICE_H_
namespace gainput
{
/// Type of an input device button.
enum ButtonType
{
BT_BOOL, ///< A boolean value button, either down (true) or up (false).
BT_FLOAT, ///< A floating-point value button, between -1.0f and 1.0f or 0.0f and 1.0f.
BT_COUNT ///< The number of different button types.
};
/// Interface for anything that provides device inputs.
/**
* An InputDevice can be anything from a physical device, like a mouse or keyboard, to the more abstract
* concept of gestures that in turn themselves depend on other InputDevices. What they have in common is
* that they provide a number of device buttons (identified by a DeviceButtonId) which can be queried for
* their state.
*
* Note that you may not instantiate an InputDevice (or any derived implementation) directly. Instead you
* have to call InputManager::CreateDevice() or InputManager::CreateAndGetDevice() with the device you want
* to instantiate as the template parameter. That way the device will be properly registered with the
* InputManager and continuously updated.
*
* Normally, you won't interact with an InputDevice directly, but instead use its device ID and its device
* buttons' IDs to map the device buttons to user buttons (see InputMap).
*/
class GAINPUT_LIBEXPORT InputDevice
{
public:
/// Type of an input device.
enum DeviceType
{
DT_MOUSE, ///< A mouse/cursor input device featuring one pointer.
DT_KEYBOARD, ///< A keyboard input device.
DT_PAD, ///< A joypad/gamepad input device.
DT_TOUCH, ///< A touch-sensitive input device supporting multiple simultaneous pointers.
DT_BUILTIN, ///< Any controls directly built into the device that also contains the screen.
DT_REMOTE, ///< A generic networked input device.
DT_GESTURE, ///< A gesture input device, building on top of other input devices.
DT_CUSTOM, ///< A custom, user-created input device.
DT_COUNT ///< The count of input device types.
};
/// Variant of an input device type.
enum DeviceVariant
{
DV_STANDARD, ///< The standard implementation of the given device type.
DV_RAW, ///< The raw input implementation of the given device type.
DV_NULL ///< The null/empty implementation of the given device type.
};
/// State of an input device.
enum DeviceState
{
DS_OK, ///< Everything is okay.
DS_LOW_BATTERY, ///< The input device is low on battery.
DS_UNAVAILABLE ///< The input device is currently not available.
};
static const unsigned AutoIndex = unsigned(-1);
/// Initializes the input device.
/**
* Do not instantiate any input device directly. Call InputManager::CreateDevice() instead.
*/
InputDevice(InputManager& manager, DeviceId device, unsigned index);
/// Empty virtual destructor.
virtual ~InputDevice();
/// Update this device, internally called by InputManager.
/**
* \param delta The delta state to add changes to. May be 0.
*/
void Update(InputDeltaState* delta);
/// Returns this device's ID.
DeviceId GetDeviceId() const { return deviceId_; }
/// Returns the device's index among devices of the same type.
unsigned GetIndex() const { return index_; }
/// Returns the device type.
virtual DeviceType GetType() const = 0;
/// Returns the device variant.
virtual DeviceVariant GetVariant() const { return DV_STANDARD; }
/// Returns the device type's name.
virtual const char* GetTypeName() const = 0;
/// Returns if this device should be updated after other devices.
virtual bool IsLateUpdate() const { return false; }
/// Returns the device state.
DeviceState GetState() const;
/// Returns if this device is available.
virtual bool IsAvailable() const { return GetState() == DS_OK || GetState() == DS_LOW_BATTERY; }
/// Returns if the given button is valid for this device.
virtual bool IsValidButtonId(DeviceButtonId deviceButton) const = 0;
/// Returns the current state of the given button.
bool GetBool(DeviceButtonId deviceButton) const;
/// Returns the previous state of the given button.
bool GetBoolPrevious(DeviceButtonId deviceButton) const;
/// Returns the current state of the given button.
float GetFloat(DeviceButtonId deviceButton) const;
/// Returns the previous state of the given button.
float GetFloatPrevious(DeviceButtonId deviceButton) const;
/// Checks if any button on this device is down.
/**
* \param[out] outButtons An array with maxButtonCount fields to receive the device buttons that are down.
* \param maxButtonCount The number of fields in outButtons.
* \return The number of device buttons written to outButtons.
*/
virtual size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const { GAINPUT_UNUSED(outButtons); GAINPUT_UNUSED(maxButtonCount); return 0; }
/// Gets the name of the given button.
/**
* \param deviceButton ID of the button.
* \param buffer A char-buffer to receive the button name.
* \param bufferLength Length of the buffer receiving the button name in bytes.
* \return The number of bytes written to buffer (includes the trailing \0).
*/
virtual size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const { GAINPUT_UNUSED(deviceButton); GAINPUT_UNUSED(buffer); GAINPUT_UNUSED(bufferLength); return 0; }
/// Returns the type of the given button.
virtual ButtonType GetButtonType(DeviceButtonId deviceButton) const = 0;
/// Returns the button's ID if the name is of this device's buttons.
/**
* \param name Name of the device button to look for.
* \return The device button ID.
*/
virtual DeviceButtonId GetButtonByName(const char* name) const { GAINPUT_UNUSED(name); return InvalidDeviceButtonId; }
/// Returns the device's state, probably best if only used internally.
InputState* GetInputState() { return state_; }
/// Returns the device's state, probably best if only used internally.
const InputState* GetInputState() const { return state_; }
/// Returns the device's previous state, probably best if only used internally.
InputState* GetPreviousInputState() { return previousState_; }
/// Returns the device's state that is currently being determined, may be 0 if not available.
virtual InputState* GetNextInputState() { return 0; }
/// Returns the previously set dead zone for the given button or 0.0f if none was set yet.
float GetDeadZone(DeviceButtonId buttonId) const;
/// Sets the dead zone for the given button.
void SetDeadZone(DeviceButtonId buttonId, float value);
/// Enable/disable debug rendering of this device.
void SetDebugRenderingEnabled(bool enabled);
/// Returns true if debug rendering is enabled, false otherwise.
bool IsDebugRenderingEnabled() const { return debugRenderingEnabled_; }
#if defined(GAINPUT_DEV) || defined(GAINPUT_ENABLE_RECORDER)
/// Returns true if this device is being controlled by a remote device
/// or a recorded input sequence, false otherwise.
bool IsSynced() const { return synced_; }
/// Sets if this device is being controlled remotely or from a recording.
/**
* \sa IsSynced()
*/
void SetSynced(bool synced) { synced_ = synced; }
#endif
protected:
/// The manager this device belongs to.
InputManager& manager_;
/// The ID of this device.
DeviceId deviceId_;
/// Index of this device among devices of the same type.
unsigned index_;
/// The current state of this device.
InputState* state_;
/// The previous state of this device.
InputState* previousState_;
float* deadZones_;
/// Specifies if this device is currently rendering debug information.
bool debugRenderingEnabled_;
#if defined(GAINPUT_DEV) || defined(GAINPUT_ENABLE_RECORDER)
/// Specifies if this device's state is actually set from a device
/// or manually set by some other system.
bool synced_;
#endif
/// Implementation of the device's Update function.
/**
* \param delta The delta state to add changes to. May be 0.
*/
virtual void InternalUpdate(InputDeltaState* delta) = 0;
/// Implementation of the device's GetState function.
/**
* \return The device's state.
*/
virtual DeviceState InternalGetState() const = 0;
/// Checks which buttons are down.
/**
* This function is normally used by GetAnyButtonDown implementations internally.
* \param outButtons An array to write buttons that are down to.
* \param maxButtonCount The size of outButtons.
* \param start The lowest device button ID to check.
* \param end The biggest device button ID to check.
* \return The number of buttons written to outButtons.
*/
size_t CheckAllButtonsDown(DeviceButtonSpec* outButtons, size_t maxButtonCount, unsigned start, unsigned end) const;
};
inline
bool
InputDevice::GetBool(DeviceButtonId deviceButton) const
{
if (!IsAvailable())
{
return false;
}
GAINPUT_ASSERT(state_);
return state_->GetBool(deviceButton);
}
inline
bool
InputDevice::GetBoolPrevious(DeviceButtonId deviceButton) const
{
if (!IsAvailable())
{
return false;
}
GAINPUT_ASSERT(previousState_);
return previousState_->GetBool(deviceButton);
}
inline
float
InputDevice::GetFloat(DeviceButtonId deviceButton) const
{
if (!IsAvailable())
{
return 0.0f;
}
GAINPUT_ASSERT(state_);
return state_->GetFloat(deviceButton);
}
inline
float
InputDevice::GetFloatPrevious(DeviceButtonId deviceButton) const
{
if (!IsAvailable())
{
return 0.0f;
}
GAINPUT_ASSERT(previousState_);
return previousState_->GetFloat(deviceButton);
}
}
#endif

View File

@@ -0,0 +1,68 @@
#ifndef GAINPUTINPUTDEVICEBUILTIN_H_
#define GAINPUTINPUTDEVICEBUILTIN_H_
namespace gainput
{
/// All valid device buttons for InputDeviceBuiltIn.
enum BuiltInButton
{
BuiltInButtonAccelerationX,
BuiltInButtonAccelerationY,
BuiltInButtonAccelerationZ,
BuiltInButtonGravityX,
BuiltInButtonGravityY,
BuiltInButtonGravityZ,
BuiltInButtonGyroscopeX,
BuiltInButtonGyroscopeY,
BuiltInButtonGyroscopeZ,
BuiltInButtonMagneticFieldX,
BuiltInButtonMagneticFieldY,
BuiltInButtonMagneticFieldZ,
BuiltInButtonCount_
};
class InputDeviceBuiltInImpl;
/// An input device for inputs that are directly built into the executing device (for example, sensors in a phone).
class GAINPUT_LIBEXPORT InputDeviceBuiltIn : public InputDevice
{
public:
/// Initializes the device.
/**
* Instantiate the device using InputManager::CreateDevice().
*
* \param manager The input manager this device is managed by.
* \param device The ID of this device.
*/
InputDeviceBuiltIn(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Shuts down the device.
~InputDeviceBuiltIn();
/// Returns DT_BUILTIN.
DeviceType GetType() const { return DT_BUILTIN; }
DeviceVariant GetVariant() const;
const char* GetTypeName() const { return "builtin"; }
bool IsValidButtonId(DeviceButtonId deviceButton) const;
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
DeviceButtonId GetButtonByName(const char* name) const;
protected:
void InternalUpdate(InputDeltaState* delta);
DeviceState InternalGetState() const;
private:
InputDeviceBuiltInImpl* impl_;
};
}
#endif

View File

@@ -0,0 +1,267 @@
#ifndef GAINPUTINPUTDEVICEKEYBOARD_H_
#define GAINPUTINPUTDEVICEKEYBOARD_H_
namespace gainput
{
/// All valid device buttons for InputDeviceKeyboard.
enum Key
{
KeyEscape,
KeyF1,
KeyF2,
KeyF3,
KeyF4,
KeyF5,
KeyF6,
KeyF7,
KeyF8,
KeyF9,
KeyF10,
KeyF11,
KeyF12,
KeyF13,
KeyF14,
KeyF15,
KeyF16,
KeyF17,
KeyF18,
KeyF19,
KeyPrint,
KeyScrollLock,
KeyBreak,
KeySpace = 0x0020,
KeyApostrophe = 0x0027,
KeyComma = 0x002c,
KeyMinus = 0x002d,
KeyPeriod = 0x002e,
KeySlash = 0x002f,
Key0 = 0x0030,
Key1 = 0x0031,
Key2 = 0x0032,
Key3 = 0x0033,
Key4 = 0x0034,
Key5 = 0x0035,
Key6 = 0x0036,
Key7 = 0x0037,
Key8 = 0x0038,
Key9 = 0x0039,
KeySemicolon = 0x003b,
KeyLess = 0x003c,
KeyEqual = 0x003d,
KeyA = 0x0041,
KeyB = 0x0042,
KeyC = 0x0043,
KeyD = 0x0044,
KeyE = 0x0045,
KeyF = 0x0046,
KeyG = 0x0047,
KeyH = 0x0048,
KeyI = 0x0049,
KeyJ = 0x004a,
KeyK = 0x004b,
KeyL = 0x004c,
KeyM = 0x004d,
KeyN = 0x004e,
KeyO = 0x004f,
KeyP = 0x0050,
KeyQ = 0x0051,
KeyR = 0x0052,
KeyS = 0x0053,
KeyT = 0x0054,
KeyU = 0x0055,
KeyV = 0x0056,
KeyW = 0x0057,
KeyX = 0x0058,
KeyY = 0x0059,
KeyZ = 0x005a,
KeyBracketLeft = 0x005b,
KeyBackslash = 0x005c,
KeyBracketRight = 0x005d,
KeyGrave = 0x0060,
KeyLeft,
KeyRight,
KeyUp,
KeyDown,
KeyInsert,
KeyHome,
KeyDelete,
KeyEnd,
KeyPageUp,
KeyPageDown,
KeyNumLock,
KeyKpEqual,
KeyKpDivide,
KeyKpMultiply,
KeyKpSubtract,
KeyKpAdd,
KeyKpEnter,
KeyKpInsert, // 0
KeyKpEnd, // 1
KeyKpDown, // 2
KeyKpPageDown, // 3
KeyKpLeft, // 4
KeyKpBegin, // 5
KeyKpRight, // 6
KeyKpHome, // 7
KeyKpUp, // 8
KeyKpPageUp, // 9
KeyKpDelete, // ,
KeyBackSpace,
KeyTab,
KeyReturn,
KeyCapsLock,
KeyShiftL,
KeyCtrlL,
KeySuperL,
KeyAltL,
KeyAltR,
KeySuperR,
KeyMenu,
KeyCtrlR,
KeyShiftR,
KeyBack,
KeySoftLeft,
KeySoftRight,
KeyCall,
KeyEndcall,
KeyStar,
KeyPound,
KeyDpadCenter,
KeyVolumeUp,
KeyVolumeDown,
KeyPower,
KeyCamera,
KeyClear,
KeySymbol,
KeyExplorer,
KeyEnvelope,
KeyEquals,
KeyAt,
KeyHeadsethook,
KeyFocus,
KeyPlus,
KeyNotification,
KeySearch,
KeyMediaPlayPause,
KeyMediaStop,
KeyMediaNext,
KeyMediaPrevious,
KeyMediaRewind,
KeyMediaFastForward,
KeyMute,
KeyPictsymbols,
KeySwitchCharset,
KeyForward,
KeyExtra1,
KeyExtra2,
KeyExtra3,
KeyExtra4,
KeyExtra5,
KeyExtra6,
KeyFn,
KeyCircumflex,
KeySsharp,
KeyAcute,
KeyAltGr,
KeyNumbersign,
KeyUdiaeresis,
KeyAdiaeresis,
KeyOdiaeresis,
KeySection,
KeyAring,
KeyDiaeresis,
KeyTwosuperior,
KeyRightParenthesis,
KeyDollar,
KeyUgrave,
KeyAsterisk,
KeyColon,
KeyExclam,
KeyBraceLeft,
KeyBraceRight,
KeySysRq,
KeyCount_
};
class InputDeviceKeyboardImpl;
/// A keyboard input device.
/**
* This input device provides support for standard keyboard devices. The valid device buttons are defined
* in the ::Key enum.
*
* This device is implemented on Android NDK, Linux, and Windows. Note that no support for
* virtual keyboards (on-screen) is present.
*
* The raw variants (InputDevice::DV_RAW) of this device do not support text input.
*/
class GAINPUT_LIBEXPORT InputDeviceKeyboard : public InputDevice
{
public:
/// Initializes the device.
/**
* Instantiate the device using InputManager::CreateDevice().
*
* \param manager The input manager this device is managed by.
* \param device The ID of this device.
*/
InputDeviceKeyboard(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Shuts down the device.
~InputDeviceKeyboard();
/// Returns DT_KEYBOARD.
DeviceType GetType() const { return DT_KEYBOARD; }
DeviceVariant GetVariant() const;
const char* GetTypeName() const { return "keyboard"; }
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton < KeyCount_; }
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
DeviceButtonId GetButtonByName(const char* name) const;
InputState* GetNextInputState();
/// Returns if text input is enabled.
bool IsTextInputEnabled() const;
/// Sets if text input is enabled and therefore if calling GetNextCharacter() make sense.
void SetTextInputEnabled(bool enabled);
/// Returns the next pending input character if text input is enabled.
char GetNextCharacter();
/// Returns the platform-specific implementation of this device (internal use only).
InputDeviceKeyboardImpl* GetPimpl() { return impl_; }
protected:
void InternalUpdate(InputDeltaState* delta);
DeviceState InternalGetState() const;
private:
InputDeviceKeyboardImpl* impl_;
HashMap<Key, const char*> keyNames_;
};
}
#endif

View File

@@ -0,0 +1,101 @@
#ifndef GAINPUTINPUTDEVICEMOUSE_H_
#define GAINPUTINPUTDEVICEMOUSE_H_
namespace gainput
{
/// All valid device buttons for InputDeviceMouse.
enum MouseButton
{
MouseButton0 = 0,
MouseButtonLeft = MouseButton0,
MouseButton1,
MouseButtonMiddle = MouseButton1,
MouseButton2,
MouseButtonRight = MouseButton2,
MouseButton3,
MouseButtonWheelUp = MouseButton3,
MouseButton4,
MouseButtonWheelDown = MouseButton4,
MouseButton5,
MouseButton6,
MouseButton7,
MouseButton8,
MouseButton9,
MouseButton10,
MouseButton11,
MouseButton12,
MouseButton13,
MouseButton14,
MouseButton15,
MouseButton16,
MouseButton17,
MouseButton18,
MouseButton19,
MouseButton20,
MouseButtonMax = MouseButton20,
MouseButtonCount,
MouseAxisX = MouseButtonCount,
MouseAxisY,
MouseButtonCount_,
MouseAxisCount = MouseButtonCount_ - MouseAxisX
};
class InputDeviceMouseImpl;
/// A mouse input device.
/**
* This input device provides support for standard mouse devices. The valid device buttons are defined
* in the ::MouseButton enum.
*
* This device is implemented on Linux and Windows.
*
* The raw variants (InputDevice::DV_RAW) of this device do not offer normalized absolute axis values.
* That means that the values of MouseAxisX and MouseAxisY don't have defined mininum or maximum
* values. Therefore only the delta (InputMap::GetFloatDelta()) should be used with raw mouse devices.
*/
class GAINPUT_LIBEXPORT InputDeviceMouse : public InputDevice
{
public:
/// Initializes the device.
/**
* Instantiate the device using InputManager::CreateDevice().
*
* \param manager The input manager this device is managed by.
* \param device The ID of this device.
*/
InputDeviceMouse(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Shuts down the device.
~InputDeviceMouse();
/// Returns DT_MOUSE.
DeviceType GetType() const { return DT_MOUSE; }
DeviceVariant GetVariant() const;
const char* GetTypeName() const { return "mouse"; }
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton < MouseButtonCount_; }
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
DeviceButtonId GetButtonByName(const char* name) const;
/// Returns the platform-specific implementation of this device (internal use only).
InputDeviceMouseImpl* GetPimpl() { return impl_; }
protected:
void InternalUpdate(InputDeltaState* delta);
DeviceState InternalGetState() const;
private:
InputDeviceMouseImpl* impl_;
};
}
#endif

View File

@@ -0,0 +1,163 @@
#ifndef GAINPUTINPUTDEVICEPAD_H_
#define GAINPUTINPUTDEVICEPAD_H_
namespace gainput
{
/// The maximum number of pads supported.
enum { MaxPadCount = 10 };
/// All valid device buttons for InputDevicePad.
enum PadButton
{
PadButtonLeftStickX,
PadButtonLeftStickY,
PadButtonRightStickX,
PadButtonRightStickY,
PadButtonAxis4, // L2/Left trigger
PadButtonAxis5, // R2/Right trigger
PadButtonAxis6,
PadButtonAxis7,
PadButtonAxis8,
PadButtonAxis9,
PadButtonAxis10,
PadButtonAxis11,
PadButtonAxis12,
PadButtonAxis13,
PadButtonAxis14,
PadButtonAxis15,
PadButtonAxis16,
PadButtonAxis17,
PadButtonAxis18,
PadButtonAxis19,
PadButtonAxis20,
PadButtonAxis21,
PadButtonAxis22,
PadButtonAxis23,
PadButtonAxis24,
PadButtonAxis25,
PadButtonAxis26,
PadButtonAxis27,
PadButtonAxis28,
PadButtonAxis29,
PadButtonAxis30,
PadButtonAxis31,
PadButtonAccelerationX,
PadButtonAccelerationY,
PadButtonAccelerationZ,
PadButtonGravityX,
PadButtonGravityY,
PadButtonGravityZ,
PadButtonGyroscopeX,
PadButtonGyroscopeY,
PadButtonGyroscopeZ,
PadButtonMagneticFieldX,
PadButtonMagneticFieldY,
PadButtonMagneticFieldZ,
PadButtonStart,
PadButtonAxisCount_ = PadButtonStart,
PadButtonSelect,
PadButtonLeft,
PadButtonRight,
PadButtonUp,
PadButtonDown,
PadButtonA, // Cross
PadButtonB, // Circle
PadButtonX, // Square
PadButtonY, // Triangle
PadButtonL1,
PadButtonR1,
PadButtonL2,
PadButtonR2,
PadButtonL3, // Left thumb
PadButtonR3, // Right thumb
PadButtonHome, // PS button
PadButton17,
PadButton18,
PadButton19,
PadButton20,
PadButton21,
PadButton22,
PadButton23,
PadButton24,
PadButton25,
PadButton26,
PadButton27,
PadButton28,
PadButton29,
PadButton30,
PadButton31,
PadButtonMax_,
PadButtonCount_ = PadButtonMax_ - PadButtonAxisCount_
};
class InputDevicePadImpl;
/// A pad input device.
/**
* This input device provides support for gamepad devices. The valid device buttons are defined
* in the ::PadButton enum.
*
* This device is implemented on Android NDK, Linux and Windows.
*
* Note that the Android implementation does not support any external pads, but only internal
* sensors (acceleration, gyroscope, magnetic field).
*/
class GAINPUT_LIBEXPORT InputDevicePad : public InputDevice
{
public:
/// The operating system device IDs for all possible pads.
static const char* PadDeviceIds[MaxPadCount];
// TODO SetPadDeviceId(padIndex, const char* id);
/// Initializes the device.
/**
* Instantiate the device using InputManager::CreateDevice().
*
* \param manager The input manager this device is managed by.
* \param device The ID of this device.
*/
InputDevicePad(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Shuts down the device.
~InputDevicePad();
/// Returns DT_PAD.
DeviceType GetType() const { return DT_PAD; }
DeviceVariant GetVariant() const;
const char* GetTypeName() const { return "pad"; }
bool IsValidButtonId(DeviceButtonId deviceButton) const;
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
DeviceButtonId GetButtonByName(const char* name) const;
InputState* GetNextInputState();
/// Enables the rumble feature of the pad.
/**
* \param leftMotor Speed of the left motor, between 0.0 and 1.0.
* \param rightMotor Speed of the right motor, between 0.0 and 1.0.
* \return true if rumble was enabled successfully, false otherwise.
*/
bool Vibrate(float leftMotor, float rightMotor);
/// Returns the platform-specific implementation of this device.
InputDevicePadImpl* GetPimpl() { return impl_; }
protected:
void InternalUpdate(InputDeltaState* delta);
DeviceState InternalGetState() const;
private:
InputDevicePadImpl* impl_;
};
}
#endif

View File

@@ -0,0 +1,107 @@
#ifndef GAINPUTINPUTDEVICETOUCH_H_
#define GAINPUTINPUTDEVICETOUCH_H_
namespace gainput
{
/// All valid device inputs for InputDeviceTouch.
enum TouchButton
{
Touch0Down,
Touch0X,
Touch0Y,
Touch0Pressure,
Touch1Down,
Touch1X,
Touch1Y,
Touch1Pressure,
Touch2Down,
Touch2X,
Touch2Y,
Touch2Pressure,
Touch3Down,
Touch3X,
Touch3Y,
Touch3Pressure,
Touch4Down,
Touch4X,
Touch4Y,
Touch4Pressure,
Touch5Down,
Touch5X,
Touch5Y,
Touch5Pressure,
Touch6Down,
Touch6X,
Touch6Y,
Touch6Pressure,
Touch7Down,
Touch7X,
Touch7Y,
Touch7Pressure,
TouchCount_
};
class InputDeviceTouchImpl;
/// A touch input device.
/**
* This input device provides support for touch screen/surface devices. The valid device buttons are defined
* in the ::TouchButton enum. For each touch point, there is a boolean input (Touch*Down) showing if the
* touch point is active, two float inputs (Touch*X, Touch*Y) showing the touch point's position, and a
* float input (Touch*Pressure) showing the touch's pressure.
*
* Not all touch points must be numbered consecutively, i.e. point #2 may be down even though #0 and #1 are not.
*
* The number of simultaneously possible touch points is implementaion-dependent.
*
* This device is implemented on Android NDK.
*/
class GAINPUT_LIBEXPORT InputDeviceTouch : public InputDevice
{
public:
/// Initializes the device.
/**
* Instantiate the device using InputManager::CreateDevice().
*
* \param manager The input manager this device is managed by.
* \param device The ID of this device.
*/
InputDeviceTouch(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Shuts down the device.
~InputDeviceTouch();
/// Returns DT_TOUCH.
DeviceType GetType() const { return DT_TOUCH; }
DeviceVariant GetVariant() const;
const char* GetTypeName() const { return "touch"; }
bool IsValidButtonId(DeviceButtonId deviceButton) const;
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
size_t GetButtonName(DeviceButtonId deviceButton, char* buffer, size_t bufferLength) const;
ButtonType GetButtonType(DeviceButtonId deviceButton) const;
DeviceButtonId GetButtonByName(const char* name) const;
InputState* GetNextInputState();
/// Returns the platform-specific implementation of this device.
InputDeviceTouchImpl* GetPimpl() { return impl_; }
protected:
void InternalUpdate(InputDeltaState* delta);
DeviceState InternalGetState() const;
private:
InputDeviceTouchImpl* impl_;
};
}
#endif

View File

@@ -0,0 +1,77 @@
#ifndef GAINPUTINPUTLISTENER_H_
#define GAINPUTINPUTLISTENER_H_
namespace gainput
{
/// Listener interface that allows to receive notifications when device button states change.
class GAINPUT_LIBEXPORT InputListener
{
public:
virtual ~InputListener() { }
/// Called when a bool-type button state changes.
/**
* \param device The input device's ID the state change occurred on.
* \param deviceButton The ID of the device button that changed.
* \param oldValue Previous state of the button.
* \param newValue New state of the button.
* \return true if the button may be processed by listeners with a lower priority, false otherwise.
*/
virtual bool OnDeviceButtonBool(DeviceId device, DeviceButtonId deviceButton, bool oldValue, bool newValue) { GAINPUT_UNUSED(device); GAINPUT_UNUSED(deviceButton); GAINPUT_UNUSED(oldValue); GAINPUT_UNUSED(newValue); return true; }
/// Called when a float-type button state changes.
/**
* \param device The input device's ID the state change occurred on.
* \param deviceButton The ID of the device button that changed.
* \param oldValue Previous state of the button.
* \param newValue New state of the button.
* \return true if the button may be processed by listeners with a lower priority, false otherwise.
*/
virtual bool OnDeviceButtonFloat(DeviceId device, DeviceButtonId deviceButton, float oldValue, float newValue) { GAINPUT_UNUSED(device); GAINPUT_UNUSED(deviceButton); GAINPUT_UNUSED(oldValue); GAINPUT_UNUSED(newValue); return true; }
/// Returns the priority which influences the order in which listeners are called by InputManager.
/**
* \sa InputManager::ReorderListeners()
*/
virtual int GetPriority() const { return 0; }
};
/// Listener interface that allows to receive notifications when user button states change.
class GAINPUT_LIBEXPORT MappedInputListener
{
public:
virtual ~MappedInputListener() { }
/// Called when a bool-type button state changes.
/**
* \param userButton The user button's ID.
* \param oldValue Previous state of the button.
* \param newValue New state of the button.
* \return true if the button may be processed by listeners with a lower priority, false otherwise.
*/
virtual bool OnUserButtonBool(UserButtonId userButton, bool oldValue, bool newValue) { GAINPUT_UNUSED(userButton); GAINPUT_UNUSED(oldValue); GAINPUT_UNUSED(newValue); return true; }
/// Called when a float-type button state changes.
/**
* \param userButton The user button's ID.
* \param oldValue Previous state of the button.
* \param newValue New state of the button.
* \return true if the button may be processed by listeners with a lower priority, false otherwise.
*/
virtual bool OnUserButtonFloat(UserButtonId userButton, float oldValue, float newValue) { GAINPUT_UNUSED(userButton); GAINPUT_UNUSED(oldValue); GAINPUT_UNUSED(newValue); return true; }
/// Returns the priority which influences the order in which listeners are called by InputMap.
/**
* \sa InputMap::ReorderListeners()
*/
virtual int GetPriority() const { return 0; }
};
}
#endif

View File

@@ -0,0 +1,331 @@
#ifndef GAINPUTINPUTMANAGER_H_
#define GAINPUTINPUTMANAGER_H_
namespace gainput
{
/// Manages all input devices and some other helpful stuff.
/**
* This manager takes care of all device-related things. Normally, you should only need one that contains
* all your input devices.
*
* After instantiating an InputManager, you have to call SetDisplaySize(). You should also create some
* input devices using the template function CreateDevice() which returns the device ID that is needed
* to do anything further with the device (for example, see InputMap).
*
* The manager has to be updated every frame by calling Update(). Depending on the platform,
* you may have to call another function as part of your message handling code (see HandleMessage(), HandleInput()).
*
* Note that destruction of an InputManager invalidates all input maps based on it and all devices created
* through it.
*/
class GAINPUT_LIBEXPORT InputManager
{
public:
/// Initializes the manager.
/**
* Further initialization is typically necessary.
* \param useSystemTime Specifies if the GetTime() function uses system time or the time
* supplied to Update(uint64_t).
* \param allocator The memory allocator to be used for all allocations.
* \see SetDisplaySize
* \see GetTime
*/
InputManager(bool useSystemTime = true, Allocator& allocator = GetDefaultAllocator());
/// Destructs the manager.
~InputManager();
/// Sets the window resolution.
/**
* Informs the InputManager and its devices of the size of the window that is used for
* receiving inputs. For example, the size is used to to normalize mouse inputs.
*/
void SetDisplaySize(int width, int height) { displayWidth_ = width; displayHeight_ = height; }
#if defined(GAINPUT_PLATFORM_LINUX)
/// [LINUX ONLY] Lets the InputManager handle the given X event.
/**
* Call this function for event types MotionNotify, ButtonPress,
* ButtonRelease, KeyPress, KeyRelease.
*/
void HandleEvent(XEvent& event);
#endif
#if defined(GAINPUT_PLATFORM_WIN)
/// [WINDOWS ONLY] Lets the InputManager handle the given Windows message.
/**
* Call this function for message types WM_CHAR, WM_KEYDOWN, WM_KEYUP,
* WM_SYSKEYDOWN, WM_SYSKEYUP, WM_?BUTTON*, WM_MOUSEMOVE, WM_MOUSEWHEEL.
*/
void HandleMessage(const MSG& msg);
#endif
#if defined(GAINPUT_PLATFORM_ANDROID)
/// [ANDROID ONLY] Lets the InputManager handle the given input event.
int32_t HandleInput(AInputEvent* event);
struct DeviceInput
{
InputDevice::DeviceType deviceType;
unsigned deviceIndex;
ButtonType buttonType;
DeviceButtonId buttonId;
union
{
float f;
bool b;
} value;
};
void HandleDeviceInput(DeviceInput const& input);
#endif
/// Updates the input state, call this every frame.
/**
* If the InputManager was initialized with `useSystemTime` set to `false`, you have to
* call Update(uint64_t) instead.
* \see GetTime
*/
void Update();
/// Updates the input state and the manager's time, call this every frame.
/**
* Updates the time returned by GetTime() and then calls the regular Update(). This function
* should only be called if the InputManager was initialized with `useSystemTime`
* set to `false`.
* \param deltaTime The provided must be in milliseconds.
* \see Update
* \see GetTime
*/
void Update(uint64_t deltaTime);
/// Returns the allocator to be used for memory allocations.
Allocator& GetAllocator() const { return allocator_; }
/// Returns a monotonic time in milliseconds.
uint64_t GetTime() const;
/// Creates an input device and registers it with the manager.
/**
* \tparam T The input device class, muste be derived from InputDevice.
* \param variant Requests the specified device variant. Note that this is only
* a request. Another implementation variant of the device may silently be instantiated
* instead. To determine what variant was instantiated, call InputDevice::GetVariant().
* \return The ID of the newly created input device.
*/
template<class T> DeviceId CreateDevice(unsigned index = InputDevice::AutoIndex, InputDevice::DeviceVariant variant = InputDevice::DV_STANDARD);
/// Creates an input device, registers it with the manager and returns it.
/**
* \tparam T The input device class, muste be derived from InputDevice.
* \param variant Requests the specified device variant. Note that this is only
* a request. Another implementation variant of the device may silently be instantiated
* instead. To determine what variant was instantiated, call InputDevice::GetVariant().
* \return The newly created input device.
*/
template<class T> T* CreateAndGetDevice(unsigned index = InputDevice::AutoIndex, InputDevice::DeviceVariant variant = InputDevice::DV_STANDARD);
/// Returns the input device with the given ID.
/**
* \return The input device or 0 if it doesn't exist.
*/
InputDevice* GetDevice(DeviceId deviceId);
/// Returns the input device with the given ID.
/**
* \return The input device or 0 if it doesn't exist.
*/
const InputDevice* GetDevice(DeviceId deviceId) const;
/// Returns the ID of the device with the given type and index.
/**
* \param typeName The name of the device type. Should come from InputDevice::GetTypeName().
* \param index The index of the device. Should come from InputDevice::GetIndex().
* \return The device's ID or InvalidDeviceId if no matching device exists.
*/
DeviceId FindDeviceId(const char* typeName, unsigned index) const;
/// Returns the ID of the device with the given type and index.
/**
* \param type The device type. Should come from InputDevice::GetType().
* \param index The index of the device. Should come from InputDevice::GetIndex().
* \return The device's ID or InvalidDeviceId if no matching device exists.
*/
DeviceId FindDeviceId(InputDevice::DeviceType type, unsigned index) const;
typedef HashMap<DeviceId, InputDevice*> DeviceMap;
/// Iterator over all registered devices.
typedef DeviceMap::iterator iterator;
/// Const iterator over all registered devices.
typedef DeviceMap::const_iterator const_iterator;
/// Returns the begin iterator over all registered devices.
iterator begin() { return devices_.begin(); }
/// Returns the end iterator over all registered devices.
iterator end() { return devices_.end(); }
/// Returns the begin iterator over all registered devices.
const_iterator begin() const { return devices_.begin(); }
/// Returns the end iterator over all registered devices.
const_iterator end() const { return devices_.end(); }
/// Registers a listener to be notified when a button state changes.
/**
* If there are listeners registered, all input devices will have to record their state changes. This incurs extra runtime costs.
*/
ListenerId AddListener(InputListener* listener);
/// De-registers the given listener.
void RemoveListener(ListenerId listenerId);
/// Sorts the list of listeners which controls the order in which listeners are called.
/**
* The order of listeners may be important as the functions being called to notify a listener of a state change can control if
* the state change will be passed to any consequent listeners. Call this function whenever listener priorites have changed. It
* is automatically called by AddListener() and RemoveListener().
*/
void ReorderListeners();
/// Checks if any button on any device is down.
/**
* \param[out] outButtons An array with maxButtonCount fields to receive the device buttons that are down.
* \param maxButtonCount The number of fields in outButtons.
* \return The number of device buttons written to outButtons.
*/
size_t GetAnyButtonDown(DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
/// Returns the number of devices with the given type.
unsigned GetDeviceCountByType(InputDevice::DeviceType type) const;
/// Returns the graphical display's width in pixels.
int GetDisplayWidth() const { return displayWidth_; }
/// Returns the graphical display's height in pixels.
int GetDisplayHeight() const { return displayHeight_; }
/// Registers a modifier that will be called after devices have been updated.
ModifierId AddDeviceStateModifier(DeviceStateModifier* modifier);
/// De-registers the given modifier.
void RemoveDeviceStateModifier(ModifierId modifierId);
void EnqueueConcurrentChange(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, bool value);
void EnqueueConcurrentChange(InputDevice& device, InputState& state, InputDeltaState* delta, DeviceButtonId buttonId, float value);
/// [IN dev BUILDS ONLY] Connect to a remote host to send device state changes to.
void ConnectForStateSync(const char* ip, unsigned port);
/// [IN dev BUILDS ONLY] Initiate sending of device state changes to the given device.
void StartDeviceStateSync(DeviceId deviceId);
/// Enable/disable debug rendering of input devices.
void SetDebugRenderingEnabled(bool enabled);
/// Returns true if debug rendering is enabled, false otherwise.
bool IsDebugRenderingEnabled() const { return debugRenderingEnabled_; }
/// Sets the debug renderer to be used if debug rendering is enabled.
void SetDebugRenderer(DebugRenderer* debugRenderer);
/// Returns the previously set debug renderer.
DebugRenderer* GetDebugRenderer() const { return debugRenderer_; }
private:
Allocator& allocator_;
DeviceMap devices_;
unsigned nextDeviceId_;
HashMap<ListenerId, InputListener*> listeners_;
unsigned nextListenerId_;
Array<InputListener*> sortedListeners_;
HashMap<ModifierId, DeviceStateModifier*> modifiers_;
unsigned nextModifierId_;
InputDeltaState* deltaState_;
uint64_t currentTime_;
struct Change
{
InputDevice* device;
InputState* state;
InputDeltaState* delta;
DeviceButtonId buttonId;
ButtonType type;
union
{
bool b;
float f;
};
};
GAINPUT_CONC_QUEUE(Change) concurrentInputs_;
int displayWidth_;
int displayHeight_;
bool useSystemTime_;
bool debugRenderingEnabled_;
DebugRenderer* debugRenderer_;
void DeviceCreated(InputDevice* device);
// Do not copy.
InputManager(const InputManager &);
InputManager& operator=(const InputManager &);
};
template<class T>
inline
DeviceId
InputManager::CreateDevice(unsigned index, InputDevice::DeviceVariant variant)
{
T* device = allocator_.New<T>(*this, nextDeviceId_, index, variant);
devices_[nextDeviceId_] = device;
DeviceCreated(device);
return nextDeviceId_++;
}
template<class T>
inline
T*
InputManager::CreateAndGetDevice(unsigned index, InputDevice::DeviceVariant variant)
{
T* device = allocator_.New<T>(*this, nextDeviceId_, index, variant);
devices_[nextDeviceId_] = device;
++nextDeviceId_;
DeviceCreated(device);
return device;
}
inline
InputDevice*
InputManager::GetDevice(DeviceId deviceId)
{
DeviceMap::iterator it = devices_.find(deviceId);
if (it == devices_.end())
{
return 0;
}
return it->second;
}
inline
const InputDevice*
InputManager::GetDevice(DeviceId deviceId) const
{
DeviceMap::const_iterator it = devices_.find(deviceId);
if (it == devices_.end())
{
return 0;
}
return it->second;
}
/// Interface for modifiers that change device input states after they have been updated.
class DeviceStateModifier
{
public:
/// Called after non-dependent devices have been updated.
/**
* This function is called by InputManager::Update() after InputDevice::Update() has been
* called on all registered devices that have InputDevice::IsLateUpdate() return \c false.
*
* \param delta All device state changes should be registered with this delta state, may be 0.
*/
virtual void Update(InputDeltaState* delta) = 0;
};
}
#endif

View File

@@ -0,0 +1,195 @@
#ifndef GAINPUTINPUTMAP_H_
#define GAINPUTINPUTMAP_H_
namespace gainput
{
class UserButton;
/// Type for filter functions that can be used to filter mapped float inputs.
typedef float (*FilterFunc_T)(float const value, void* userData);
/// Maps user buttons to device buttons.
/**
* This is the interface that should be used to get input. You can have several maps that are used
* simultaneously or use different ones depending on game state. The user button IDs have to be unique per input map.
*
* InputMap uses the provided InputManager to get devices inputs and process them into user-mapped inputs. After creating
* an InputMap, you should map some device buttons to user buttons (using MapBool() or MapFloat()). User buttons are identified
* by an ID provided by you. In order to ensure their uniqueness, it's a good idea to define an enum containing all your user buttons
* for any given InputMap. It's of course possible to map multiple different device button to one user button.
*
* After a user button has been mapped, you can query its state by calling one of the several GetBool* and GetFloat* functions. The
* result will depend on the mapped device button(s) and the policy (set using SetUserButtonPolicy()).
*/
class GAINPUT_LIBEXPORT InputMap
{
public:
/// Initializes the map.
/**
* \param manager The input manager used to get device inputs.
* \param name The name for the input map (optional). If a name is provided, it is copied to an internal buffer.
* \param allocator The allocator to be used for all memory allocations.
*/
InputMap(InputManager& manager, const char* name = 0, Allocator& allocator = GetDefaultAllocator());
/// Unitializes the map.
~InputMap();
/// Clears all mapped inputs.
void Clear();
/// Returns the input manager this input map uses.
const InputManager& GetManager() const { return manager_; }
/// Returns the map's name, if any.
/**
* \return The map's name or 0 if no name was set.
*/
const char* GetName() const { return name_; }
/// Returns the map's auto-generated ID (that should not be used outside of the library).
unsigned GetId() const { return id_; }
/// Maps a bool-type button.
/**
* \param userButton The user ID for this mapping.
* \param device The device's ID of the device button to be mapped.
* \param deviceButton The ID of the device button to be mapped.
* \return true if the mapping was created.
*/
bool MapBool(UserButtonId userButton, DeviceId device, DeviceButtonId deviceButton);
/// Maps a float-type button, possibly to a custom range.
/**
* \param userButton The user ID for this mapping.
* \param device The device's ID of the device button to be mapped.
* \param deviceButton The ID of the device button to be mapped.
* \param min Optional minimum value of the mapped button.
* \param max Optional maximum value of the mapped button.
* \param filterFunc Optional filter functions that modifies the device button value.
* \param filterUserData Optional user data pointer that is passed to filterFunc.
* \return true if the mapping was created.
*/
bool MapFloat(UserButtonId userButton, DeviceId device, DeviceButtonId deviceButton,
float min = 0.0f, float max = 1.0f,
FilterFunc_T filterFunc = 0, void* filterUserData = 0);
/// Removes all mappings for the given user button.
void Unmap(UserButtonId userButton);
/// Returns if the given user button has any mappings.
bool IsMapped(UserButtonId userButton) const;
/// Gets all device buttons mapped to the given user button.
/**
* \param userButton The user button ID of the button to return all mappings for.
* \param[out] outButtons An array with maxButtonCount fields to receive the device buttons that are mapped.
* \param maxButtonCount The number of fields in outButtons.
* \return The number of device buttons written to outButtons.
*/
size_t GetMappings(UserButtonId userButton, DeviceButtonSpec* outButtons, size_t maxButtonCount) const;
/// Policy for how multiple device buttons are summarized in one user button.
enum UserButtonPolicy
{
UBP_FIRST_DOWN, ///< The first device buttons that is down (or not 0.0f) determines the result.
UBP_MAX, ///< The maximum of all device button states is the result.
UBP_MIN, ///< The minimum of all device button states is the result.
UBP_AVERAGE ///< The average of all device button states is the result.
};
/// Sets how a user button handles inputs from multiple device buttons.
/**
* \return true if the policy was set, false otherwise (i.e. the user button doesn't exist).
*/
bool SetUserButtonPolicy(UserButtonId userButton, UserButtonPolicy policy);
/// Sets a dead zone for a float-type button.
/**
* If a dead zone is set for a button anything less or equal to the given value will be treated
* as 0.0f. The absolute input value is used in order to determine if the input value falls within the dead
* zone (i.e. with a dead zone of 0.2f, both -0.1f and 0.1f will result in 0.0f).
*
* \param userButton The user button's ID.
* \param deadZone The dead zone to be set.
* \return true if the dead zone was set, false otherwise (i.e. the user button doesn't exist).
*/
bool SetDeadZone(UserButtonId userButton, float deadZone);
/// Returns the bool state of a user button.
bool GetBool(UserButtonId userButton) const;
/// Returns if the user button is newly down.
bool GetBoolIsNew(UserButtonId userButton) const;
/// Returns the bool state of a user button from the previous frame.
bool GetBoolPrevious(UserButtonId userButton) const;
/// Returns if the user button has been released.
bool GetBoolWasDown(UserButtonId userButton) const;
/// Returns the float state of a user button.
float GetFloat(UserButtonId userButton) const;
/// Returns the float state of a user button from the previous frame.
float GetFloatPrevious(UserButtonId userButton) const;
/// Returns the delta between the previous and the current frame of the float state of the given user button.
float GetFloatDelta(UserButtonId userButton) const;
/// Gets the name of the device button mapped to the given user button.
/**
* \param userButton ID of the user button.
* \param buffer A char-buffer to receive the button name.
* \param bufferLength Length of the buffer receiving the button name in bytes.
* \return The number of bytes written to buffer (includes the trailing \0).
*/
size_t GetUserButtonName(UserButtonId userButton, char* buffer, size_t bufferLength) const;
/// Returns the user button ID the given device button is mapped to.
/**
* This function iterates over all mapped buttons and therefore shouldn't be used in a performance critical
* situation.
*
* \param device The device's ID of the device button to be checked.
* \param deviceButton The ID of the device button to be checked.
* \return The user button ID the device button is mapped to or InvalidDeviceButtonId if the device button is not mapped.
*/
UserButtonId GetUserButtonId(DeviceId device, DeviceButtonId deviceButton) const;
/// Registers a listener to be notified when a button state changes.
/**
* If there are listeners registered, all input devices will have to record their state changes. This incurs extra runtime costs.
*/
ListenerId AddListener(MappedInputListener* listener);
/// De-registers the given listener.
void RemoveListener(ListenerId listenerId);
/// Sorts the list of listeners which controls the order in which listeners are called.
/**
* The order of listeners may be important as the functions being called to notify a listener of a state change can control if
* the state change will be passed to any consequent listeners. Call this function whenever listener priorites have changed. It
* is automatically called by AddListener() and RemoveListener().
*/
void ReorderListeners();
private:
InputManager& manager_;
char* name_;
unsigned id_;
Allocator& allocator_;
typedef HashMap<UserButtonId, UserButton*> UserButtonMap;
UserButtonMap userButtons_;
UserButtonId nextUserButtonId_;
HashMap<ListenerId, MappedInputListener*> listeners_;
Array<MappedInputListener*> sortedListeners_;
unsigned nextListenerId_;
InputListener* managerListener_;
ListenerId managerListenerId_;
float GetFloatState(UserButtonId userButton, bool previous) const;
UserButton* GetUserButton(UserButtonId userButton);
const UserButton* GetUserButton(UserButtonId userButton) const;
// Do not copy.
InputMap(const InputMap &);
InputMap& operator=(const InputMap &);
};
}
#endif

View File

@@ -0,0 +1,60 @@
#ifndef GAINPUTINPUTSTATE_H_
#define GAINPUTINPUTSTATE_H_
namespace gainput
{
/// State of an input device.
class GAINPUT_LIBEXPORT InputState
{
public:
/// Initializes the state.
/**
* \param allocator The allocator to be used for all memory allocations.
* \param buttonCount The maximum number of device buttons.
*/
InputState(Allocator& allocator, unsigned int buttonCount);
/// Unitializes the state.
~InputState();
/// Returns the number of buttons in this state.
/**
* Note that not all buttons may be valid.
*
* \sa InputDevice::IsValidButtonId()
*/
unsigned GetButtonCount() const { return buttonCount_; }
/// Returns the bool state of the given device button.
bool GetBool(DeviceButtonId buttonId) const { return buttons_[buttonId].b; }
/// Sets the bool state of the given device button.
void Set(DeviceButtonId buttonId, bool value) { buttons_[buttonId].b = value; }
/// Returns the float state of the given device button.
float GetFloat(DeviceButtonId buttonId) const { return buttons_[buttonId].f; }
/// Sets the float state of the given device button.
void Set(DeviceButtonId buttonId, float value) { buttons_[buttonId].f = value; }
/// Sets the states of all buttons in this input state to the states of all buttons in the given input state.
InputState& operator=(const InputState& other);
private:
Allocator& allocator_;
unsigned int buttonCount_;
struct Button
{
union
{
bool b;
float f;
};
};
Button* buttons_;
};
}
#endif

View File

@@ -0,0 +1,26 @@
#ifndef GAINPUTIOS_H_
#define GAINPUTIOS_H_
#import <UIKit/UIKit.h>
namespace gainput
{
class InputManager;
}
/// [IOS ONLY] UIKit view that captures touch inputs.
/**
* In order to enable touch input on iOS devices (i.e. make the InputDeviceTouch work),
* an instance of this view has to be attached as a subview to the view of your application.
* Note that, for touches to work in portrait and landscape mode, the subview has to be
* rotated correctly with its parent.
*/
@interface GainputView : UIView
- (id)initWithFrame:(CGRect)frame inputManager:(gainput::InputManager&)inputManager;
@end
#endif

View File

@@ -0,0 +1,39 @@
#ifndef GAINPUT_LOG_H_
#define GAINPUT_LOG_H_
#include <gainput/gainput.h>
#if defined(GAINPUT_PLATFORM_LINUX)
#if defined(GAINPUT_DEBUG) || defined(GAINPUT_DEV)
#include <stdio.h>
#define GAINPUT_LOG(...) printf(__VA_ARGS__);
#endif
#elif defined(GAINPUT_PLATFORM_WIN)
#if defined(GAINPUT_DEBUG) || defined(GAINPUT_DEV)
#include <stdio.h>
#include <Windows.h>
#define GAINPUT_LOG(...) { char buf[1024]; sprintf(buf, __VA_ARGS__); OutputDebugStringA(buf); }
#endif
#elif defined(GAINPUT_PLATFORM_ANDROID)
#if defined(GAINPUT_DEBUG) || defined(GAINPUT_DEV)
#include <android/log.h>
#define GAINPUT_LOG(...) ((void)__android_log_print(ANDROID_LOG_INFO, "gainput", __VA_ARGS__))
#endif
#elif defined(GAINPUT_PLATFORM_IOS) || defined(GAINPUT_PLATFORM_MAC) || defined(GAINPUT_PLATFORM_TVOS)
#include <stdio.h>
#define GAINPUT_LOG(...) printf(__VA_ARGS__);
#endif
#ifndef GAINPUT_LOG
#define GAINPUT_LOG(...)
#endif
#endif

View File

@@ -0,0 +1,17 @@
#ifndef GAINPUTMAPFILTERS_H_
#define GAINPUTMAPFILTERS_H_
namespace gainput
{
/// Inverts the given input value in the range [-1.0f, 1.0f].
GAINPUT_LIBEXPORT float InvertSymmetricInput(float const value, void*);
/// Inverts the given input value in the range [0.0f, 1.0f].
GAINPUT_LIBEXPORT float InvertInput(float const value, void*);
}
#endif

View File

@@ -0,0 +1,193 @@
/**
* Gainput - C++ input library for games.
*
* Copyright (c) 2013-2017 Johannes Kuhlmann.
* Licensed under the MIT license. See LICENSE file.
*/
#ifndef GAINPUT_H_
#define GAINPUT_H_
#if defined(__ANDROID__) || defined(ANDROID)
#define GAINPUT_PLATFORM_ANDROID
#define GAINPUT_LIBEXPORT
#elif defined(__linux) || defined(__linux__) || defined(linux) || defined(LINUX)
#define GAINPUT_PLATFORM_LINUX
#define GAINPUT_LIBEXPORT
#elif defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER)
#define GAINPUT_PLATFORM_WIN
#if defined(GAINPUT_LIB_DYNAMIC)
#define GAINPUT_LIBEXPORT __declspec(dllexport)
#elif defined(GAINPUT_LIB_DYNAMIC_USE)
#define GAINPUT_LIBEXPORT __declspec(dllimport)
#else
#define GAINPUT_LIBEXPORT
#endif
#elif defined(__APPLE__)
#define GAINPUT_LIBEXPORT
#include <TargetConditionals.h>
#if TARGET_OS_TV
#define GAINPUT_PLATFORM_TVOS
#elif TARGET_OS_IPHONE
#define GAINPUT_PLATFORM_IOS
#elif TARGET_OS_MAC
#define GAINPUT_PLATFORM_MAC
#else
#error Gainput: Unknown/unsupported Apple platform!
#endif
#else
#error Gainput: Unknown/unsupported platform!
#endif
//#define GAINPUT_DEBUG
//#define GAINPUT_DEV
#define GAINPUT_ENABLE_ALL_GESTURES
#define GAINPUT_ENABLE_RECORDER
#define GAINPUT_TEXT_INPUT_QUEUE_LENGTH 32
#ifdef GAINPUT_ENABLE_CONCURRENCY
#define MOODYCAMEL_EXCEPTIONS_DISABLED
#include "concurrentqueue.h"
#define GAINPUT_CONC_QUEUE(TYPE) moodycamel::ConcurrentQueue<TYPE>
#define GAINPUT_CONC_CONSTRUCT(queue) queue()
#define GAINPUT_CONC_ENQUEUE(queue, obj) queue.enqueue(obj)
#define GAINPUT_CONC_DEQUEUE(queue, obj) queue.try_dequeue(obj)
#else
#define GAINPUT_CONC_QUEUE(TYPE) gainput::Array<TYPE>
#define GAINPUT_CONC_CONSTRUCT(queue) queue(allocator)
#define GAINPUT_CONC_ENQUEUE(queue, obj) queue.push_back(obj)
#define GAINPUT_CONC_DEQUEUE(queue, obj) (!queue.empty() ? (obj = queue[queue.size()-1], queue.pop_back(), true) : false)
#endif
#include <cassert>
#include <cstring>
#include <new>
#define GAINPUT_ASSERT assert
#define GAINPUT_UNUSED(x) (void)(x)
#if defined(GAINPUT_PLATFORM_LINUX)
#include <cstdlib>
#include <stdint.h>
union _XEvent;
typedef _XEvent XEvent;
#elif defined(GAINPUT_PLATFORM_WIN)
#include <cstdlib>
typedef struct tagMSG MSG;
namespace gainput
{
typedef unsigned __int8 uint8_t;
typedef __int8 int8_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
}
#elif defined(GAINPUT_PLATFORM_ANDROID)
#include <stdint.h>
#include <stdlib.h>
struct AInputEvent;
#endif
/// Contains all Gainput related classes, types, and functions.
namespace gainput
{
/// ID of an input device.
typedef unsigned int DeviceId;
/// ID of a specific button unique to an input device.
typedef unsigned int DeviceButtonId;
/// Describes a device button on a specific device.
struct DeviceButtonSpec
{
/// ID of the input device.
DeviceId deviceId;
/// ID of the button on the given input device.
DeviceButtonId buttonId;
};
/// ID of a user-defined, mapped button.
typedef unsigned int UserButtonId;
/// ID of an input listener.
typedef unsigned int ListenerId;
/// ID of a device state modifier.
typedef unsigned int ModifierId;
/// An invalid device ID.
static const DeviceId InvalidDeviceId = -1;
/// An invalid device button ID.
static const DeviceButtonId InvalidDeviceButtonId = -1;
/// An invalid user button ID.
static const UserButtonId InvalidUserButtonId = -1;
/// Returns the name of the library, should be "Gainput".
const char* GetLibName();
/// Returns the version number of the library.
uint32_t GetLibVersion();
/// Returns the version number of the library as a printable string.
const char* GetLibVersionString();
class InputDeltaState;
class InputListener;
class InputManager;
class DebugRenderer;
class DeviceStateModifier;
template <class T> T Abs(T a) { return a < T() ? -a : a; }
/// Switches the library's internal development server to HTTP mode.
/**
* When the server is in HTTP mode, it is possible to control touch
* input using an external HTML page that connects to the library
* via HTTP.
*
* The HTML page(s) can be found under `tools/html5client/` and should
* be placed on an HTTP server that can be reached from the touch device
* that should send touch events to the library. The touch device then
* in turn connects to the library's internal HTTP server and periodically
* sends touch input information.
*
* The pages can also be found hosted here:
* http://gainput.johanneskuhlmann.de/html5client/
*/
void DevSetHttp(bool enable);
}
#define GAINPUT_VER_MAJOR_SHIFT 16
#define GAINPUT_VER_GET_MAJOR(ver) (ver >> GAINPUT_VER_MAJOR_SHIFT)
#define GAINPUT_VER_GET_MINOR(ver) (ver & (uint32_t(-1) >> GAINPUT_VER_MAJOR_SHIFT))
#include <gainput/GainputAllocator.h>
#include <gainput/GainputContainers.h>
#include <gainput/GainputInputState.h>
#include <gainput/GainputInputDevice.h>
#include <gainput/GainputInputListener.h>
#include <gainput/GainputInputManager.h>
#include <gainput/GainputInputMap.h>
#include <gainput/GainputInputDeviceMouse.h>
#include <gainput/GainputInputDeviceKeyboard.h>
#include <gainput/GainputInputDevicePad.h>
#include <gainput/GainputInputDeviceTouch.h>
#include <gainput/GainputInputDeviceBuiltIn.h>
#include <gainput/gestures/GainputGestures.h>
#include <gainput/recorder/GainputInputRecording.h>
#include <gainput/recorder/GainputInputPlayer.h>
#include <gainput/recorder/GainputInputRecorder.h>
#endif

View File

@@ -0,0 +1,47 @@
#ifndef GAINPUTBUTTONSTICKGESTURE_H_
#define GAINPUTBUTTONSTICKGESTURE_H_
#ifdef GAINPUT_ENABLE_BUTTON_STICK_GESTURE
namespace gainput
{
/// Buttons provided by the ButtonStickGesture.
enum ButtonStickAction
{
ButtonStickAxis
};
class GAINPUT_LIBEXPORT ButtonStickGesture : public InputGesture
{
public:
/// Initializes the gesture.
ButtonStickGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Uninitializes the gesture.
~ButtonStickGesture();
/// Sets up the gesture for operation with the given axes and buttons.
void Initialize(DeviceId negativeAxisDevice, DeviceButtonId negativeAxis,
DeviceId positiveAxisDevice, DeviceButtonId positiveAxis);
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == ButtonStickAxis; }
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_FLOAT; }
protected:
void InternalUpdate(InputDeltaState* delta);
private:
DeviceButtonSpec negativeAxis_;
DeviceButtonSpec positiveAxis_;
};
}
#endif
#endif

View File

@@ -0,0 +1,99 @@
#ifndef GAINPUTDOUBLECLICKGESTURE_H_
#define GAINPUTDOUBLECLICKGESTURE_H_
#ifdef GAINPUT_ENABLE_DOUBLE_CLICK_GESTURE
namespace gainput
{
/// Buttons provided by the DoubleClickGesture.
enum DoubleClickAction
{
DoubleClickTriggered ///< The button triggered by double-clicking.
};
/// A double-click gesture.
/**
* This gesture implements the classic double-click functionality. Its only device button ::DoubleClickTriggered is
* true for one frame after the specified button has been active for a specified number of times in a given
* time frame. It's also possible to disallow the pointer from travelling too far between and during clicks.
*
* After instantiating the gesture like any other input device, call one of the Initialize() functions to properly
* set it up.
*
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
* \c GAINPUT_ENABLE_DOUBLE_CLICK_GESTURE defined.
*
* \sa Initialize
* \sa SetClicksTargetCount
* \sa InputManager::CreateDevice
*/
class GAINPUT_LIBEXPORT DoubleClickGesture : public InputGesture
{
public:
/// Initializes the gesture.
DoubleClickGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Uninitializes the gesture.
~DoubleClickGesture();
/// Sets up the gesture for operation without position checking.
/**
* \param actionButtonDevice ID of the input device containing the action button.
* \param actionButton ID of the device button to be used as the action button.
* \param timeSpan Allowed time between clicks in milliseconds.
*/
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, uint64_t timeSpan = 300);
/// Sets up the gesture for operation with position checking, i.e. the user may not move the mouse too far between clicks.
/**
* \param actionButtonDevice ID of the input device containing the action button.
* \param actionButton ID of the device button to be used as the action button.
* \param xAxisDevice ID of the input device containing the X coordinate of the pointer.
* \param xAxis ID of the device button/axis to be used for the X coordinate of the pointer.
* \param xTolerance The amount the pointer may travel in the X coordinate to still be valid.
* \param yAxisDevice ID of the input device containing the Y coordinate of the pointer.
* \param yAxis ID of the device button/axis to be used for the Y coordinate of the pointer.
* \param yTolerance The amount the pointer may travel in the Y coordinate to still be valid.
* \param timeSpan Allowed time between clicks in milliseconds.
*/
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton,
DeviceId xAxisDevice, DeviceButtonId xAxis, float xTolerance,
DeviceId yAxisDevice, DeviceButtonId yAxis, float yTolerance,
uint64_t timeSpan = 300);
/// Sets the number of clicks to trigger an action.
/**
* \param count The number of clicks that will trigger this gesture; the default is 2, i.e. double-click.
*/
void SetClicksTargetCount(unsigned count) { clicksTargetCount_ = count; }
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == DoubleClickTriggered; }
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_BOOL; }
protected:
void InternalUpdate(InputDeltaState* delta);
private:
DeviceButtonSpec actionButton_;
DeviceButtonSpec xAxis_;
float xTolerance_;
DeviceButtonSpec yAxis_;
float yTolerance_;
uint64_t timeSpan_;
uint64_t firstClickTime_;
float firstClickX_;
float firstClickY_;
unsigned clicksRegistered_;
unsigned clicksTargetCount_;
};
}
#endif
#endif

View File

@@ -0,0 +1,69 @@
#ifndef GAINPUTGESTURES_H_
#define GAINPUTGESTURES_H_
#ifdef GAINPUT_ENABLE_ALL_GESTURES
#define GAINPUT_ENABLE_BUTTON_STICK_GESTURE
#define GAINPUT_ENABLE_DOUBLE_CLICK_GESTURE
#define GAINPUT_ENABLE_HOLD_GESTURE
#define GAINPUT_ENABLE_PINCH_GESTURE
#define GAINPUT_ENABLE_ROTATE_GESTURE
#define GAINPUT_ENABLE_SIMULTANEOUSLY_DOWN_GESTURE
#define GAINPUT_ENABLE_TAP_GESTURE
#endif
namespace gainput
{
/// Base class for all input gestures.
/**
* Input gestures are a way to process basic input data into more complex input data. For example,
* multiple buttons may be interpreted over time to form a new button. A very simple gesture would the
* ubiquitous double-click.
*
* Mainly for consistency and convenience reasons, all gestures should derive from this class though it's not
* strictly necessary (deriving from InputDevice would suffice).
*
* Input gestures are basically just input devices that don't get their data from some hardware device
* but from other input devices instead. Therefore gestures must also be created by calling
* InputManager::CreateDevice() or InputManager::CreateAndGetDevice(). Most gestures require further
* initialization which is done by calling one of their \c Initialize() member functions. After that,
* they should be good to go and their buttons can be used like any other input device button, i.e.
* they can be mapped to some user button.
*
* Gestures can be excluded from compilation if they are not required. In order to include all gestures
* \c GAINPUT_ENABLE_ALL_GESTURES should be defined in \c gainput.h . This define must be present when
* the library is built, otherwise the actual functionality won't be present. Similarly, there is one
* define for each gesture. The names of these are documented in the descriptions of the
* individual gesture classes. If no such define is defined, no gesture will be included.
*/
class GAINPUT_LIBEXPORT InputGesture : public InputDevice
{
public:
/// Returns DT_GESTURE.
DeviceType GetType() const { return DT_GESTURE; }
const char* GetTypeName() const { return "gesture"; }
bool IsLateUpdate() const { return true; }
protected:
/// Gesture base constructor.
InputGesture(InputManager& manager, DeviceId device, unsigned index) : InputDevice(manager, device, index == InputDevice::AutoIndex ? manager.GetDeviceCountByType(DT_GESTURE) : 0) { }
DeviceState InternalGetState() const { return DS_OK; }
};
}
#include <gainput/gestures/GainputButtonStickGesture.h>
#include <gainput/gestures/GainputDoubleClickGesture.h>
#include <gainput/gestures/GainputHoldGesture.h>
#include <gainput/gestures/GainputPinchGesture.h>
#include <gainput/gestures/GainputRotateGesture.h>
#include <gainput/gestures/GainputSimultaneouslyDownGesture.h>
#include <gainput/gestures/GainputTapGesture.h>
#endif

View File

@@ -0,0 +1,94 @@
#ifndef GAINPUTHOLDGESTURE_H_
#define GAINPUTHOLDGESTURE_H_
#ifdef GAINPUT_ENABLE_HOLD_GESTURE
namespace gainput
{
/// Buttons provided by the HoldGesture.
enum HoldAction
{
HoldTriggered ///< The button that triggers after holding for the given time.
};
/// A hold-to-trigger gesture.
/**
* This gesture, mainly meant for touch devices, triggers after the specified button has been down for at least
* the specified amount of time. Its button ::HoldTriggered is then either active for one frame or as long as
* the source button is down.
*
* After instantiating the gesture like any other input device, call one of the Initialize() functions to properly
* set it up.
*
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
* \c GAINPUT_ENABLE_HOLD_GESTURE defined.
*
* \sa Initialize
* \sa InputManager::CreateDevice
*/
class GAINPUT_LIBEXPORT HoldGesture : public InputGesture
{
public:
/// Initializes the gesture.
HoldGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Uninitializes the gesture.
~HoldGesture();
/// Sets up the gesture for operation without position checking.
/**
* \param actionButtonDevice ID of the input device containing the action button.
* \param actionButton ID of the device button to be used as the action button.
* \param oneShot Specifies if the gesture triggers only once after the given time or if it triggers as long as the source button is down.
* \param timeSpan Time in milliseconds the user needs to hold in order to trigger the gesture.
*/
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, bool oneShot = true, uint64_t timeSpan = 800);
/// Sets up the gesture for operation with position checking, i.e. the user may not move the mouse too far while holding.
/**
* \param actionButtonDevice ID of the input device containing the action button.
* \param actionButton ID of the device button to be used as the action button.
* \param xAxisDevice ID of the input device containing the X coordinate of the pointer.
* \param xAxis ID of the device button/axis to be used for the X coordinate of the pointer.
* \param xTolerance The amount the pointer may travel in the X coordinate to still be valid.
* \param yAxisDevice ID of the input device containing the Y coordinate of the pointer.
* \param yAxis ID of the device button/axis to be used for the Y coordinate of the pointer.
* \param yTolerance The amount the pointer may travel in the Y coordinate to still be valid.
* \param oneShot Specifies if the gesture triggers only once after the given time or if it triggers as long as the source button is down.
* \param timeSpan Time in milliseconds the user needs to hold in order to trigger the gesture.
*/
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton,
DeviceId xAxisDevice, DeviceButtonId xAxis, float xTolerance,
DeviceId yAxisDevice, DeviceButtonId yAxis, float yTolerance,
bool oneShot = true,
uint64_t timeSpan = 800);
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == HoldTriggered; }
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_BOOL; }
protected:
void InternalUpdate(InputDeltaState* delta);
private:
DeviceButtonSpec actionButton_;
DeviceButtonSpec xAxis_;
float xTolerance_;
DeviceButtonSpec yAxis_;
float yTolerance_;
bool oneShot_;
bool oneShotReset_;
uint64_t timeSpan_;
uint64_t firstDownTime_;
float firstDownX_;
float firstDownY_;
};
}
#endif
#endif

View File

@@ -0,0 +1,86 @@
#ifndef GAINPUTPINCHGESTURE_H_
#define GAINPUTPINCHGESTURE_H_
#ifdef GAINPUT_ENABLE_PINCH_GESTURE
namespace gainput
{
/// Buttons provided by the PinchGesture.
enum PinchAction
{
PinchTriggered, ///< The button that triggers when both pinch buttons are down.
PinchScale ///< The current pinch scale value if pinching is active.
};
/// A multi-touch pinch-to-scale gesture.
/**
* This gesture, mainly meant for multi-touch devices, triggers (::PinchTriggered is down) when both specified
* source buttons are down. It will then determine the distance between the two 2D touch points and report
* any change in distance as a factor of the initial distance using ::PinchScale.
*
* After instantiating the gesture like any other input device, call Initialize() to properly
* set it up.
*
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
* \c GAINPUT_ENABLE_PINCH_GESTURE defined.
*
* \sa Initialize
* \sa InputManager::CreateDevice
*/
class GAINPUT_LIBEXPORT PinchGesture : public InputGesture
{
public:
/// Initializes the gesture.
PinchGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Uninitializes the gesture.
~PinchGesture();
/// Sets up the gesture for operation with the given axes and buttons.
/**
* \param downDevice ID of the input device containing the first touch button.
* \param downButton ID of the device button to be used as the first touch button.
* \param xAxisDevice ID of the input device containing the X coordinate of the first touch point.
* \param xAxis ID of the device button/axis to be used for the X coordinate of the first touch point.
* \param yAxisDevice ID of the input device containing the Y coordinate of the first touch point.
* \param yAxis ID of the device button/axis to be used for the Y coordinate of the first touch point.
* \param down2Device ID of the input device containing the second touch button.
* \param downButton2 ID of the device button to be used as the second touch button.
* \param xAxis2Device ID of the input device containing the X coordinate of the second touch point.
* \param xAxis2 ID of the device button/axis to be used for the X coordinate of the second touch point.
* \param yAxis2Device ID of the input device containing the Y coordinate of the second touch point.
* \param yAxis2 ID of the device button/axis to be used for the Y coordinate of the second touch point.
*/
void Initialize(DeviceId downDevice, DeviceButtonId downButton,
DeviceId xAxisDevice, DeviceButtonId xAxis,
DeviceId yAxisDevice, DeviceButtonId yAxis,
DeviceId down2Device, DeviceButtonId downButton2,
DeviceId xAxis2Device, DeviceButtonId xAxis2,
DeviceId yAxis2Device, DeviceButtonId yAxis2);
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == PinchTriggered || deviceButton == PinchScale; }
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return deviceButton == PinchTriggered ? BT_BOOL : BT_FLOAT; }
protected:
void InternalUpdate(InputDeltaState* delta);
private:
DeviceButtonSpec downButton_;
DeviceButtonSpec xAxis_;
DeviceButtonSpec yAxis_;
DeviceButtonSpec downButton2_;
DeviceButtonSpec xAxis2_;
DeviceButtonSpec yAxis2_;
bool pinching_;
float initialDistance_;
};
}
#endif
#endif

View File

@@ -0,0 +1,87 @@
#ifndef GAINPUTROTATEGESTURE_H_
#define GAINPUTROTATEGESTURE_H_
#ifdef GAINPUT_ENABLE_ROTATE_GESTURE
namespace gainput
{
/// Buttons provided by the RotateGesture.
enum RotateAction
{
RotateTriggered, ///< The button that triggers when both rotate buttons are down.
RotateAngle ///< The current rotation angle in radians if rotation is triggered (::RotateTriggered).
};
/// A multi-touch rotate gesture.
/**
* This gesture, mainly meant for multi-touch devices, triggers (::RotateTriggered is down) when both specified
* source buttons are down. It then determines the angle between the two specified 2D touch points and reports any
* change in angle using ::RotateAngle. The initial angle between the two points is defined as no rotation.
*
* After instantiating the gesture like any other input device, call Initialize() to properly
* set it up.
*
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
* \c GAINPUT_ENABLE_ROTATE_GESTURE defined.
*
* \sa Initialize
* \sa InputManager::CreateDevice
*/
class GAINPUT_LIBEXPORT RotateGesture : public InputGesture
{
public:
/// Initializes the gesture.
RotateGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Uninitializes the gesture.
~RotateGesture();
/// Sets up the gesture for operation with the given axes and buttons.
/**
* \param downDevice ID of the input device containing the first touch button.
* \param downButton ID of the device button to be used as the first touch button.
* \param xAxisDevice ID of the input device containing the X coordinate of the first touch point.
* \param xAxis ID of the device button/axis to be used for the X coordinate of the first touch point.
* \param yAxisDevice ID of the input device containing the Y coordinate of the first touch point.
* \param yAxis ID of the device button/axis to be used for the Y coordinate of the first touch point.
* \param down2Device ID of the input device containing the second touch button.
* \param downButton2 ID of the device button to be used as the second touch button.
* \param xAxis2Device ID of the input device containing the X coordinate of the second touch point.
* \param xAxis2 ID of the device button/axis to be used for the X coordinate of the second touch point.
* \param yAxis2Device ID of the input device containing the Y coordinate of the second touch point.
* \param yAxis2 ID of the device button/axis to be used for the Y coordinate of the second touch point.
*/
void Initialize(DeviceId downDevice, DeviceButtonId downButton,
DeviceId xAxisDevice, DeviceButtonId xAxis,
DeviceId yAxisDevice, DeviceButtonId yAxis,
DeviceId down2Device, DeviceButtonId downButton2,
DeviceId xAxis2Device, DeviceButtonId xAxis2,
DeviceId yAxis2Device, DeviceButtonId yAxis2);
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == RotateTriggered || deviceButton == RotateAngle; }
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return deviceButton == RotateTriggered ? BT_BOOL : BT_FLOAT; }
protected:
void InternalUpdate(InputDeltaState* delta);
private:
DeviceButtonSpec downButton_;
DeviceButtonSpec xAxis_;
DeviceButtonSpec yAxis_;
DeviceButtonSpec downButton2_;
DeviceButtonSpec xAxis2_;
DeviceButtonSpec yAxis2_;
bool rotating_;
float initialAngle_;
};
}
#endif
#endif

View File

@@ -0,0 +1,66 @@
#ifndef GAINPUTSIMULTANEOUSLYDOWNGESTURE_H_
#define GAINPUTSIMULTANEOUSLYDOWNGESTURE_H_
#ifdef GAINPUT_ENABLE_SIMULTANEOUSLY_DOWN_GESTURE
namespace gainput
{
/// Buttons provided by the SimultaneouslyDownGesture.
enum SimultaneouslyDownAction
{
SimultaneouslyDownTriggered ///< The button triggered by double-clicking.
};
/// A gesture that tracks if a number of buttons is down simultaneously.
/**
* This gesture can be used to detect if multiple buttons are down at the same time. Its only
* device button ::SimultaneouslyDownTriggered is true while all buttons provided through AddButton()
* are down.
*
* After instantiating the gesture like any other input device, call AddButton() as often as necessary
* to properly set it up.
*
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
* \c GAINPUT_ENABLE_SIMULTANEOUSLY_DOWN_GESTURE defined.
*
* \sa AddButton
* \sa InputManager::CreateDevice
*/
class GAINPUT_LIBEXPORT SimultaneouslyDownGesture : public InputGesture
{
public:
/// Initializes the gesture.
SimultaneouslyDownGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Uninitializes the gesture.
~SimultaneouslyDownGesture();
/// Adds the given button as a button to check.
/**
* \param device ID of the input device containing the button to be checked.
* \param button ID of the device button to be checked.
*/
void AddButton(DeviceId device, DeviceButtonId button);
/// Removes all buttons previously registered through AddButton().
void ClearButtons();
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == SimultaneouslyDownTriggered; }
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_BOOL; }
protected:
void InternalUpdate(InputDeltaState* delta);
private:
Array<DeviceButtonSpec> buttons_;
};
}
#endif
#endif

View File

@@ -0,0 +1,66 @@
#ifndef GAINPUTTAPGESTURE_H_
#define GAINPUTTAPGESTURE_H_
#ifdef GAINPUT_ENABLE_TAP_GESTURE
namespace gainput
{
/// Buttons provided by the TapGesture.
enum TapAction
{
TapTriggered ///< The button that is triggered by tapping.
};
/// A tap-to-trigger gesture.
/**
* This gesture, mainly meant for touch devices, triggers after the specified button has been down and released
* during the specified time frame. If the button is down for a longer time, no action is triggered.
*
* After instantiating the gesture like any other input device, call Initialize() to properly
* set it up.
*
* In order for this gesture to be available, Gainput must be built with \c GAINPUT_ENABLE_ALL_GESTURES or
* \c GAINPUT_ENABLE_TAP_GESTURE defined.
*
* \sa Initialize
* \sa InputManager::CreateDevice
*/
class GAINPUT_LIBEXPORT TapGesture : public InputGesture
{
public:
/// Initializes the gesture.
TapGesture(InputManager& manager, DeviceId device, unsigned index, DeviceVariant variant);
/// Uninitializes the gesture.
~TapGesture();
/// Sets up the gesture.
/**
* \param actionButtonDevice ID of the input device containing the action button.
* \param actionButton ID of the device button to be used as the action button.
* \param timeSpan Time in milliseconds the user may hold at most.
*/
void Initialize(DeviceId actionButtonDevice, DeviceButtonId actionButton, uint64_t timeSpan = 500);
bool IsValidButtonId(DeviceButtonId deviceButton) const { return deviceButton == TapTriggered; }
ButtonType GetButtonType(DeviceButtonId deviceButton) const { GAINPUT_UNUSED(deviceButton); GAINPUT_ASSERT(IsValidButtonId(deviceButton)); return BT_BOOL; }
protected:
void InternalUpdate(InputDeltaState* delta);
private:
DeviceButtonSpec actionButton_;
uint64_t timeSpan_;
uint64_t firstDownTime_;
};
}
#endif
#endif

View File

@@ -0,0 +1,65 @@
#ifndef GAINPUTINPUTPLAYER_H_
#define GAINPUTINPUTPLAYER_H_
#ifdef GAINPUT_ENABLE_RECORDER
namespace gainput
{
/// Plays back a previously recorded sequence of device state changes.
/**
* In order for input recording to be available, Gainput must have been built with
* \c GAINPUT_ENABLE_RECORDER defined.
*/
class GAINPUT_LIBEXPORT InputPlayer : public DeviceStateModifier
{
public:
/// Initializes the player.
/**
* \param manager The manager to receive the device state changes.
* \param recording The recording to play, may be 0.
*/
InputPlayer(InputManager& manager, InputRecording* recording = 0);
/// Destructs the player.
~InputPlayer();
/// Updates the player, called internally from InputManager::Update().
void Update(InputDeltaState* delta);
/// Starts the playback.
/**
* A recording must have been provided before doing this, either through the
* constructor or SetRecording().
*/
void Start();
/// Stops the Playback.
void Stop();
/// Returns if the player is currently playing.
bool IsPlaying() const { return isPlaying_; }
/// Sets the recording to play.
void SetRecording(InputRecording* recording);
/// Returns the currently set recording.
InputRecording* GetRecording() { return recording_; }
/// Returns the currently set recording.
const InputRecording* GetRecording() const { return recording_; }
private:
InputManager& manager_;
bool isPlaying_;
InputRecording* recording_;
uint64_t startTime_;
Array<DeviceId> devicesToReset_;
ModifierId playingModifierId_;
};
}
#endif
#endif

View File

@@ -0,0 +1,73 @@
#ifndef GAINPUTINPUTRECORDER_H_
#define GAINPUTINPUTRECORDER_H_
#ifdef GAINPUT_ENABLE_RECORDER
namespace gainput
{
/// Records a sequence of button state changes.
/**
* In order for input recording to be available, Gainput must have been built with
* \c GAINPUT_ENABLE_RECORDER defined.
*/
class GAINPUT_LIBEXPORT InputRecorder
{
public:
/// Initializes the recorder.
/**
* \param manager The InputManager to receive button state changes from.
*/
InputRecorder(InputManager& manager);
/// Destructs the recorder.
~InputRecorder();
/// Starts recording.
/**
* Also clears the InputRecording that is being recorded to so that it's not possible
* to resume recording after stopping to record.
*/
void Start();
/// Stops recording.
void Stop();
/// Returns if the recorder is currently recording.
bool IsRecording() const { return isRecording_; }
/// Adds a device to record the button state changes of.
/**
* If no device is set, all devices are recorded.
* \param device The ID of the device to record.
*/
void AddDeviceToRecord(DeviceId device) { recordedDevices_[device] = true; }
/// Returns if the given device should be recorded.
/**
* \param device The ID of the device to check.
*/
bool IsDeviceToRecord(DeviceId device) { return recordedDevices_.empty() || recordedDevices_.count(device) > 0; }
/// Returns the recording that is being recorded to, may be 0.
InputRecording* GetRecording() { return recording_; }
/// Returns the recording that is being recorded to, may be 0.
const InputRecording* GetRecording() const { return recording_; }
/// Returns the time the recording was started.
uint64_t GetStartTime() const { return startTime_; }
private:
InputManager& manager_;
bool isRecording_;
InputListener* recordingListener_;
ListenerId recordingListenerId_;
InputRecording* recording_;
uint64_t startTime_;
HashMap<DeviceId, bool> recordedDevices_;
};
}
#endif
#endif

View File

@@ -0,0 +1,125 @@
#ifndef GAINPUTINPUTRECORDING_H_
#define GAINPUTINPUTRECORDING_H_
#ifdef GAINPUT_ENABLE_RECORDER
namespace gainput
{
/// A single recorded change for a device button.
struct GAINPUT_LIBEXPORT RecordedDeviceButtonChange
{
/// The time at which the change occurred.
uint64_t time;
/// The ID of the device owning the button that changed.
DeviceId deviceId;
/// The ID of the button that changed.
DeviceButtonId buttonId;
union
{
/// If the button's type is ::BT_BOOL, this contains the new value.
bool b;
/// If the button's type is ::BT_FLOAT, this contains the new value.
float f;
};
};
/// A recorded sequence of input changes.
/**
* The recording can be recorded to, played, or serialized/deserialized.
*
* In order for input recording to be available, Gainput must have been built with
* \c GAINPUT_ENABLE_RECORDER defined.
*
* \sa InputPlayer
* \sa InputRecorder
*/
class GAINPUT_LIBEXPORT InputRecording
{
public:
/// Initializes the recording in an empty state.
/**
* \param allocator The allocator to be used for all memory allocations.
*/
InputRecording(Allocator& allocator = GetDefaultAllocator());
/// Initializes the recording from the given serialized data.
/**
* The recording is reconstructed from a previously serialized recording obtained through
* GetSerialized().
*
* \param manager Used to resolve device and button references in the recording.
* \param data The serialized recording as obtained from GetSerialized().
* \param size The length of the serialized recording as obtained from GetSerializedSize().
* \param allocator The allocator to be used for all memory allocations.
*/
InputRecording(InputManager& manager, void* data, size_t size, Allocator& allocator = GetDefaultAllocator());
/// Appends a device button change to the recording.
/**
* The changes must be added in chronological order, i.e. time must always greater or equal to the time
* AddChange() was last called with.
*
* \param time The time elapsed before the change occurred.
* \param deviceId The ID of the device owning the button that changed.
* \param buttonId The ID of the button that changed.
* \param value The new value of the button.
*/
void AddChange(uint64_t time, DeviceId deviceId, DeviceButtonId buttonId, bool value);
/// Appends a device button change to the recording.
/**
* The changes must be added in chronological order, i.e. time must always greater or equal to the time
* AddChange() was last called with.
*
* \param time The time elapsed before the change occurred.
* \param deviceId The ID of the device owning the button that changed.
* \param buttonId The ID of the button that changed.
* \param value The new value of the button.
*/
void AddChange(uint64_t time, DeviceId deviceId, DeviceButtonId buttonId, float value);
/// Removes all state changes.
void Clear();
/// Gets the next button change before and including the given time and returns it.
/**
* \param time The time up to which to return changes.
* \param[out] outChange The change properties will be written to this if this function returns true.
* \return true if a change matching the given time was found, false otherwise.
*/
bool GetNextChange(uint64_t time, RecordedDeviceButtonChange& outChange);
/// Resets the playback position.
/**
* After calling this function, GetNextChange() will return changes from the beginning of the recorded
* sequence of changes again.
*/
void Reset() { position_ = 0; }
/// Returns what time frame this recording spans.
uint64_t GetDuration() const;
/// Returns the size required to serialize this recording.
size_t GetSerializedSize() const;
/// Serializes this recording to the given buffer.
/**
* This function serializes this recording so that it can be saved and read back in and deserialized later.
*
* \param manager Used to resolve device and button references in the recording.
* \param data A buffer of (at least) a size as returned by GetSerializedSize().
*/
void GetSerialized(InputManager& manager, void* data) const;
private:
Array<RecordedDeviceButtonChange> changes_;
/// The position in changes_ for reading.
unsigned position_;
};
}
#endif
#endif