From 609628d61854b94e9f6f5ee5543d0d233852614b Mon Sep 17 00:00:00 2001
From: Mhat <127427093+Mhatxotic@users.noreply.github.com>
Date: Sun, 26 Jan 2025 00:31:30 +0000
Subject: [PATCH] 25.1.26
[Engine]
* Move all joystick related code to a new 'joystick.hpp' module and tidy up names and clean out redundant code.
* Increase supported buttons from GLFW_BUTTON_LAST+1 to 128 and protect from potential overflow.
* Increase supported axes from GLFW_AXIS_LAST+1 to 8 and protect from overflow.
* Show more information with 'input' console command.
* Fix 'Input.GetJoyButton()' returning raw button data and not translated data.
[Assets]
* Update API documentation.
---
docs/index.html | 22 +-
src/conlib.hpp | 88 +++----
src/core.hpp | 2 +-
src/engine.cpp | 1 +
src/engine.hpp | 10 +-
src/glfwutil.hpp | 12 +
src/input.hpp | 502 ++--------------------------------------
src/joystick.hpp | 582 +++++++++++++++++++++++++++++++++++++++++++++++
src/json.hpp | 4 +-
src/llcommon.hpp | 1 +
src/llinput.hpp | 39 ++--
11 files changed, 705 insertions(+), 558 deletions(-)
create mode 100644 src/joystick.hpp
diff --git a/docs/index.html b/docs/index.html
index 03a6655..2325eaa 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -1,7 +1,7 @@
-
-
-
+
+
+
@@ -11,18 +11,18 @@
-
+
-
+
-
+
-
+
- Mhatxotic Engine 25.1.22.118 API reference
+ Mhatxotic Engine 25.1.26.24 API reference
- Mhatxotic Engine 25.1.22.118 API reference
+ Mhatxotic Engine 25.1.26.24 API reference
@@ -5736,7 +5736,7 @@ Function Parameters:-
Return Parameters:-
Result (integer) = Number of ticks the button has been held down.
Synopsis:-
- Returns the state of the specified joystick button.
Result can be: =0: The button is not held down.
>0: The button was held down for this many game ticks.
+ Returns the state of the specified joystick button.
Result can be: =0: The button is not held down.
=1: The button was pressed.
>1: The button is being held.
Copyright © 2025 Mhatxotic Design, All Rights Reserved.
- This document was generated at Thu Jan 23 01:39:36 2025 +0000
+ This document was generated at Sun Jan 26 00:32:39 2025 +0000
diff --git a/src/conlib.hpp b/src/conlib.hpp
index eee654a..d59ebc5 100644
--- a/src/conlib.hpp
+++ b/src/conlib.hpp
@@ -889,71 +889,77 @@ cConsole->AddLineA(sTable.Finish(),
/* ========================================================================= */
{ "input", 1, 2, CFL_VIDEO, [](const Args &aArgs){
/* ------------------------------------------------------------------------- */
-// Get joysticks data
-const JoyList &jlList = cInput->GetConstJoyList();
+// Required joystick namespace
+using namespace IJoystick::P;
// If argument specified
if(aArgs.size() > 1)
{ // Convert parmeter to number
const size_t stArg = StrToNum(aArgs[1]);
- if(stArg >= jlList.size())
+ if(stArg >= cInput->JoyGetCount())
return cConsole->AddLine("Joystick index argument invalid!");
// Get joystick information and return if not connected
- const JoyInfo &jiRef = jlList[stArg];
- if(jiRef.IsDisconnected())
+ const JoyInfo &jiRef = cInput->JoyGetConst(stArg);
+ if(jiRef.JoyIsDisconnected())
return cConsole->AddLine("Joystick is not being polled right now!");
// Build axis state data
Statistic sAxes;
- sAxes.Header();
- for(size_t stIndex = 0; stIndex < jiRef.GetAxisCount(); ++stIndex)
- sAxes.Header(StrFormat("A$$$$", setw(2), right, setfill('0'), stIndex));
- // Buffered
- sAxes.Data("BUF");
- for(size_t stIndex = 0; stIndex < jiRef.GetAxisCount(); ++stIndex)
- sAxes.DataN(jiRef.GetAxisState(stIndex));
- // Unbuffered
- sAxes.Data("RAW");
- for(size_t stIndex = 0; stIndex < jiRef.GetAxisCount(); ++stIndex)
- sAxes.DataN(jiRef.GetUnbufferedAxisState(stIndex), 1);
+ // Buffered headers
+ StdForEach(seq, jiRef.JoyAxisListBegin(), jiRef.JoyAxisListEnd(),
+ [&sAxes](const JoyAxisInfo &jaiRef) { sAxes.Header(StrFormat("BA$$$$",
+ setw(2), right, setfill('0'), jaiRef.AxisGetId()), true); });
+ // Unbuffered headers
+ StdForEach(seq, jiRef.JoyAxisListBegin(), jiRef.JoyAxisListEnd(),
+ [&sAxes](const JoyAxisInfo &jaiRef) { sAxes.Header(StrFormat("UA$$$$",
+ setw(2), right, setfill('0'), jaiRef.AxisGetId()), true); });
+ // Reserve memory for data entries
+ sAxes.Reserve(jiRef.JoyAxisListCount() * 2);
+ // Buffered state
+ StdForEach(seq, jiRef.JoyAxisListBegin(), jiRef.JoyAxisListEnd(),
+ [&sAxes](const JoyAxisInfo &jaiRef)
+ { sAxes.DataN(jaiRef.AxisGetBufferedState()); });
+ // Unbuffered state
+ StdForEach(seq, jiRef.JoyAxisListBegin(), jiRef.JoyAxisListEnd(),
+ [&sAxes](const JoyAxisInfo &jaiRef)
+ { sAxes.DataN(jaiRef.AxisGetUnbufferedState(), 1); });
// Build button state data
Statistic sButtons;
- sButtons.Header();
- for(size_t stIndex = 0; stIndex < jiRef.GetButtonCount(); ++stIndex)
- sButtons.Header(StrFormat("B$$$$", setw(2), right, setfill('0'), stIndex));
- // Buffered
- sButtons.Data("BUF");
- for(size_t stIndex = 0; stIndex < jiRef.GetButtonCount(); ++stIndex)
- sButtons.DataN(jiRef.GetButtonState(stIndex));
- // Unbuffered
- sButtons.Data("RAW");
- for(size_t stIndex = 0; stIndex < jiRef.GetButtonCount(); ++stIndex)
- sButtons.DataN(jiRef.GetUnbufferedButtonState(stIndex));
+ // Buffered headers
+ StdForEach(seq, jiRef.JoyButtonListBegin(), jiRef.JoyButtonListEnd(),
+ [&sButtons](const JoyButtonInfo &jbiRef)
+ { sButtons.Header(StrFormat("B$$$$",
+ setw(2), right, setfill('0'), jbiRef.ButtonGetId()), true); });
+ // Reserve memory for data entries
+ sButtons.Reserve(jiRef.JoyButtonListCount());
+ // Buffered state
+ StdForEach(seq, jiRef.JoyButtonListBegin(), jiRef.JoyButtonListEnd(),
+ [&sButtons](const JoyButtonInfo &jbiRef)
+ { sButtons.DataN(jbiRef.ButtonGetState()); });
// Dump to console output and return
return cConsole->AddLineF("$$Data for $ '$' at index $.", sAxes.Finish(),
- sButtons.Finish(), jiRef.GetGamepadOrJoystickString(), jiRef.IdentGet(),
+ sButtons.Finish(), jiRef.JoyGetGamepadOrJoystickString(), jiRef.IdentGet(),
stArg);
-} // Joysticks connected
-size_t stConnected = 0;
-// Make a table to automatically format our data neatly
+} // Make a table to automatically format our data neatly
Statistic sTable;
sTable.Header("ID").Header("FL").Header("AX").Header("BT")
- .Header("NAME", false).Reserve(jlList.size());
+ .Header("GUID", false).Header("NAME", false)
+ .Header("IDENT", false).Reserve(cInput->JoyGetCount());
// For each joystick
+const JoyList &jlList = cInput->JoyListGetConst();
for(const JoyInfo &jiRef : jlList)
{ // If joystick is connected
- if(jiRef.IsDisconnected())
+ if(jiRef.JoyIsDisconnected())
{ // If joystick name was empty then ignore it. Still show disconnected ones
if(jiRef.IdentGet().empty()) continue;
- } // Connected
- else ++stConnected;
- // Store data
- sTable.DataN(jiRef.GetId()).Data(StrFromEvalTokens({
- { jiRef.FlagIsSet(JF_GAMEPAD), 'G' },
- { jiRef.FlagIsSet(JF_CONNECTED), 'C' }
- })).DataN(jiRef.GetAxisCount()).DataN(jiRef.GetButtonCount())
+ } // Store data
+ sTable.DataN(jiRef.JoyGetId()).Data(StrFromEvalTokens({
+ { jiRef.JoyIsGamepad(), 'G' }, { jiRef.JoyIsConnected(), 'C' }
+ })).DataN(jiRef.JoyAxisListCount()).DataN(jiRef.JoyButtonListCount())
+ .Data(jiRef.JoyGUID()).Data(jiRef.JoyGamePadName())
.Data(jiRef.IdentGet());
} // Print totals
cConsole->AddLineF("$$ connected ($ supported).", sTable.Finish(),
- StrCPluraliseNum(stConnected, "input", "inputs"), jlList.size());
+ StrCPluraliseNum(cInput->JoyGetConnected(), "input", "inputs"),
+ jlList.size());
/* ------------------------------------------------------------------------- */
} }, // End of 'input' function
/* ========================================================================= */
diff --git a/src/core.hpp b/src/core.hpp
index aec0434..d22a3f7 100644
--- a/src/core.hpp
+++ b/src/core.hpp
@@ -139,7 +139,7 @@ class Core final : // Members initially private
{ // Set main fbo by default on each frame
cFboCore->ActivateMain();
// Poll joysticks
- cInput->PollJoysticks();
+ cInput->JoyPoll();
// Execute a tick for each frame missed
cLua->ExecuteMain();
// Break if we've caught up
diff --git a/src/engine.cpp b/src/engine.cpp
index 77df6f6..f47b70a 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -103,6 +103,7 @@ namespace E { // Start of engine namespace
#include "file.hpp" // FStream+FileMap class header
#include "clip.hpp" // Clipboard class header
#include "congraph.hpp" // Console rendering class header
+#include "joystick.hpp" // Joystick structure class header
#include "input.hpp" // Input handling class header
#include "display.hpp" // Window handling class header
#include "mask.hpp" // BitMask system header
diff --git a/src/engine.hpp b/src/engine.hpp
index 6c05671..be1c49e 100644
--- a/src/engine.hpp
+++ b/src/engine.hpp
@@ -12,9 +12,9 @@
#define VER_AUTHOR "Mhatxotic Design" // Author of engine
#define VER_MAJOR 25 // Version major (year)
#define VER_MINOR 1 // Version minor (month)
-#define VER_BUILD 25 // Version build (day)
-#define VER_REV 1 // Version rev (build#)
-#define VER_STR_NQ 25,1,25,1 // Version as literal
-#define VER_STR "25.1.25.1" // Version as string
-#define VER_DATE "Sat Jan 25 00:32:33 2025 +0000" // Compilation date
+#define VER_BUILD 26 // Version build (day)
+#define VER_REV 27 // Version rev (build#)
+#define VER_STR_NQ 25,1,26,27 // Version as literal
+#define VER_STR "25.1.26.27" // Version as string
+#define VER_DATE "Sun Jan 26 01:08:13 2025 +0000" // Compilation date
/* == EoF =========================================================== EoF == */
diff --git a/src/glfwutil.hpp b/src/glfwutil.hpp
index 35c0f7c..c571c52 100644
--- a/src/glfwutil.hpp
+++ b/src/glfwutil.hpp
@@ -180,6 +180,18 @@ static const unsigned char *GlFWGetJoystickButtons(int iJ, int &iJAB)
/* -- Joystick other ------------------------------------------------------- */
static const char *GlFWGetJoystickName(const int iJ)
{ return glfwGetJoystickName(iJ); }
+/* -- Joystick is actually a game controller ------------------------------- */
+static bool GlFWJoystickIsGamepad(const int iJ)
+ { return glfwJoystickIsGamepad(iJ); }
+/* -- Get gamepad name ----------------------------------------------------- */
+static const char *GlFWGetGamepadName(const int iJ)
+ { return glfwGetGamepadName(iJ); }
+/* -- Get joystick unique identification number ---------------------------- */
+static const char *GlFWGetJoystickGUID(const int iJ)
+ { return glfwGetJoystickGUID(iJ); }
+/* -- Return if joystick is present ---------------------------------------- */
+static bool GlFWJoystickPresent(const int iJ)
+ { return glfwJoystickPresent(iJ); }
/* -- Set swap interval ---------------------------------------------------- */
static void GlFWSetVSync(const int iI) { glfwSwapInterval(iI); }
/* -- Wait for window event ------------------------------------------------ */
diff --git a/src/input.hpp b/src/input.hpp
index 649e58c..f8bdf06 100644
--- a/src/input.hpp
+++ b/src/input.hpp
@@ -14,11 +14,11 @@ using namespace ICVar::P; using namespace ICVarDef::P;
using namespace ICVarLib::P; using namespace IEvtMain::P;
using namespace IEvtWin::P; using namespace IFboCore::P;
using namespace IFlags; using namespace IGlFW::P;
-using namespace IGlFWUtil::P; using namespace IIdent::P;
+using namespace IGlFWUtil::P; using namespace IJoystick::P;
using namespace ILog::P; using namespace ILuaFunc::P;
using namespace IStd::P; using namespace IString::P;
-using namespace ISysUtil::P; using namespace IUtf;
-using namespace IUtil::P; using namespace Lib::OS::GlFW;
+using namespace ISysUtil::P; using namespace IUtil::P;
+using namespace Lib::OS::GlFW;
/* ------------------------------------------------------------------------- */
namespace P { // Start of public module namespace
/* == Input flags ========================================================== */
@@ -30,321 +30,14 @@ BUILD_FLAGS(Input,
IF_FSTOGGLER {Flag[2]}, IF_MOUSEFOCUS {Flag[3]},
// Send events at startup Do joystick polling?
IF_INITEVENTS {Flag[4]}, IF_POLLJOYSTICKS {Flag[5]}
-);/* -- Axis class --------------------------------------------------------- */
-class JoyAxisInfo
-{ /* -------------------------------------------------------------- */ private:
- const int iId; // Axis unique identifier
- float fDeadZoneR; // Reverse deadzone threshold
- float fDeadZoneF; // Forward deadzone threshold
- float fUnbuffered; // Current unbuffered axis press state
- int iBuffered; // Current buffered axis press state
- /* -- Get axis identifier ---------------------------------------- */ public:
- int AxisGetId(void) const { return iId; }
- /* -- Get reverse deadzone value ----------------------------------------- */
- float AxisGetReverseDeadZone(void) const { return fDeadZoneR; }
- /* -- Get forward deadzone value ----------------------------------------- */
- float AxisGetForwardDeadZone(void) const { return fDeadZoneF; }
- /* -- Set reverse deadzone value ----------------------------------------- */
- void AxisSetReverseDeadZone(const float fDZ) { fDeadZoneR = -fDZ; }
- /* -- Set forward deadzone value ----------------------------------------- */
- void AxisSetForwardDeadZone(const float fDZ) { fDeadZoneF = fDZ; }
- /* -- Get unbuffered state ----------------------------------------------- */
- float AxisGetUnbufferedState(void) const { return fUnbuffered; }
- /* -- Get buffered state ------------------------------------------------- */
- int AxisGetBufferedState(void) const { return iBuffered; }
- /* -- Clear button state ------------------------------------------------- */
- void AxisClearState(void) { fUnbuffered = 0.0f; iBuffered = GLFW_RELEASE; }
- /* -- Set axis state ----------------------------------------------------- */
- void AxisSetState(const float*const fpData)
- { // Get the axis reading and if it's moving negatively?
- fUnbuffered = fpData[AxisGetId()];
- if(fUnbuffered < fDeadZoneR)
- { // Released or already in reverse position?
- if(iBuffered <= GLFW_RELEASE)
- { // Set to -GLFW_REPEAT if currently -GLFW_PRESSED or
- // -GLFW_PRESSED if currently GLFW_RELEASE
- if(iBuffered > -GLFW_REPEAT) --iBuffered;
- // State changed
- return;
- }
- } // Moving positively?
- else if(fUnbuffered > fDeadZoneF)
- { // Released or already in forward position?
- if(iBuffered >= GLFW_RELEASE)
- { // Set to GLFW_REPEAT if currentl GLFW_PRESSED or
- // GLFW_PRESSED if currently GLFW_RELEASE
- if(iBuffered < GLFW_REPEAT) ++iBuffered;
- // State changed
- return;
- }
- } // Nothing pressed so reset buffered counter
- iBuffered = GLFW_RELEASE;
- }
- /* -- Constructor with unique id ----------------------------------------- */
- explicit JoyAxisInfo(const int iNId) :
- /* -- Initialisers ----------------------------------------------------- */
- iId(iNId), // Set unique id
- fDeadZoneR(-0.25f), // Set default reverse deadzone
- fDeadZoneF(0.25f), // Set default forward deadzone
- fUnbuffered(0.0f), // Set default unbuffered state
- iBuffered(GLFW_RELEASE) // Set default state
- /* -- No code ---------------------------------------------------------- */
- { }
-};/* -- Axis data list type ------------------------------------------------ */
-typedef array JoyAxisList;
-/* -- Button class --------------------------------------------------------- */
-class JoyButtonInfo
-{ /* -- Private variables ----------------------------------------- */ private:
- const int iId; // Button unique identifier
- unsigned int uiUnbuffered, // Current unbuffered butn press state
- uiBuffered; // Current buffered butn press state
- /* -- Get button id ---------------------------------------------- */ public:
- int ButtonGetId(void) const { return iId; }
- /* -- Get unbuffered state (GLFW_RELEASE or GLFW_PRESS) ------------------ */
- unsigned int ButtonGetUnbufferedState(void) const { return uiUnbuffered; }
- /* -- Get buffered state (GLFW_RELEASE, GLFW_PRESS or GLFW_REPEAT) ------- */
- unsigned int ButtonGetBufferedState(void) const { return uiBuffered; }
- /* -- Clear button state ------------------------------------------------- */
- void ButtonClearState(void) { uiUnbuffered = uiBuffered = GLFW_RELEASE; }
- /* -- Set button state --------------------------------------------------- */
- void ButtonSetState(const unsigned char*const ucpState)
- { // Save unbuffered state and compare it
- uiUnbuffered = static_cast(ucpState[ButtonGetId()]);
- switch(uiUnbuffered)
- { // Button is released?
- case GLFW_RELEASE:
- // Reset button state if not released (0 = released)
- if(uiBuffered > GLFW_RELEASE) uiBuffered = GLFW_RELEASE;
- // Done
- return;
- // Button is pressed? Increase button state (1=pressed and 2=held)
- case GLFW_PRESS:
- // Set GLFW_PRESSED if GLFW_RELEASED or
- // GLFW_REPEAT if GLFW_PRESSED.
- if(uiBuffered < GLFW_REPEAT) ++uiBuffered;
- // Done
- return;
- // Shouldn't get here
- default: break;
- } // Reset to released
- uiBuffered = GLFW_RELEASE;
- }
- /* -- Constructor with unique id ----------------------------------------- */
- explicit JoyButtonInfo(const int iNId) :
- /* -- Initialisers ----------------------------------------------------- */
- iId(iNId), // Set unique id
- uiUnbuffered(GLFW_RELEASE), // Set default unbuffered state
- uiBuffered(GLFW_RELEASE) // Set default buffered state
- /* -- No code ---------------------------------------------------------- */
- { }
-};/* -- Button data list --------------------------------------------------- */
-typedef array JoyButtonList;
-/* -- Joystick type typedef ------------------------------------------------ */
-BUILD_FLAGS(Joy,
- /* ----------------------------------------------------------------------- */
- // No flags Joystick is connnected?
- JF_NONE {Flag[0]}, JF_CONNECTED {Flag[1]},
- // Joystick is actually a gamepad
- JF_GAMEPAD {Flag[2]}
-);/* -- Joystick class ----------------------------------------------------- */
-class JoyInfo :
- /* -- Derived classes ---------------------------------------------------- */
- public JoyFlags, // Joystick flags
- public Ident // Joystick identifier
-{ /* -------------------------------------------------------------- */ private:
- const int iId; // Unique identifier of this
- /* -- Unbuffered and buffered axis data struct --------------------------- */
- JoyAxisList jalData; // Joystick axes data
- JoyButtonList jblData; // Joystick buttons data
- size_t stAxes; // Axes count
- size_t stButtons; // Button count
- /* -- Return joystick id ----------------------------------------- */ public:
- int GetId(void) const { return iId; }
- /* -- Clear button state ------------------------------------------------- */
- void ClearButtonState(void)
- { StdForEach(par_unseq, jblData.begin(), jblData.end(),
- [](JoyButtonInfo& jbiItem) { jbiItem.ButtonClearState(); }); }
- /* -- Get button count --------------------------------------------------- */
- size_t GetButtonCount(void) const { return stButtons; }
- /* -- Refresh button data ------------------------------------------------ */
- void RefreshButtons(void)
- { // Get joystick buttons and if found?
- int iButtons;
- if(const unsigned char*const cpData =
- GlFWGetJoystickButtons(GetId(), iButtons))
- { // Convert integer to sizet and return if there are no buttons
- stButtons = UtilMinimum(static_cast(iButtons), jblData.size());
- if(!stButtons) return;
- // Enumerate state for each joy button
- for(size_t stBId = 0; stBId < stButtons; ++stBId)
- jblData[stBId].ButtonSetState(cpData);
- }
- }
- /* -- Clear axis state --------------------------------------------------- */
- void ClearAxisState(void)
- { StdForEach(par_unseq, jalData.begin(), jalData.end(),
- [](JoyAxisInfo &jaiItem) { jaiItem.AxisClearState(); }); }
- /* -- Get axis count ----------------------------------------------------- */
- size_t GetAxisCount(void) const { return stAxes; }
- /* -- Refresh axis data for this ----------------------------------------- */
- void RefreshAxes(void)
- { // Get axis data and if succeeded?
- int iAxes;
- if(const float*const fpData = GlFWGetJoystickAxes(GetId(), iAxes))
- { // Clamp count to number we support on the stack and return if no axes
- stAxes = UtilMinimum(static_cast(iAxes), jalData.size());
- if(!stAxes) return;
- // Enumerate state for each joystick axis
- for(size_t stAId = 0; stAId < stAxes; ++stAId)
- jalData[stAId].AxisSetState(fpData);
- }
- }
- /* -- Refresh data ------------------------------------------------------- */
- void RefreshData(void) { RefreshAxes(); RefreshButtons(); }
- /* -- Return type of joystick -------------------------------------------- */
- const string_view &GetGamepadOrJoystickString(void) const
- { // Return if it is a gamepad or a joystick
- static const string_view svGamepad{ "gamepad" },
- svJoystick{ "joystick" };
- return FlagIsSet(JF_GAMEPAD) ? svGamepad : svJoystick;
- }
- /* -- Joystick is connected/disconnected? ------------------------ */ public:
- bool IsConnected(void) const { return FlagIsSet(JF_CONNECTED); }
- bool IsDisconnected(void) const { return !IsConnected(); }
- /* -- Get joystick button list data -------------------------------------- */
- const JoyButtonList &GetConstButtonList(void) const { return jblData; }
- /* -- Get joystick axis list data ---------------------------------------- */
- const JoyAxisList &GetConstAxisList(void) const { return jalData; }
- /* -- Clear button state if connected ------------------------------------ */
- void ClearButtonStateIfConnected(void)
- { if(IsConnected()) ClearButtonState(); }
- /* -- Clear buttons and axis state --------------------------------------- */
- void ClearState(void) { ClearAxisState(); ClearButtonState(); }
- /* -- Refresh data if connected ------------------------------------------ */
- void RefreshDataIfConnected() { if(IsConnected()) RefreshData(); }
- /* -- Get buffered button state ------------------------------------------ */
- unsigned int GetButtonState(const size_t stButtonId) const
- { return jblData[stButtonId].ButtonGetBufferedState(); }
- /* -- Get unbuffered button state ---------------------------------------- */
- unsigned int GetUnbufferedButtonState(const size_t stButtonId) const
- { return jblData[stButtonId].ButtonGetUnbufferedState(); }
- /* -- Get axis state ----------------------------------------------------- */
- int GetAxisState(const size_t stAxisId) const
- { return jalData[stAxisId].AxisGetBufferedState(); }
- /* -- Get unbuffered axis state ------------------------------------------ */
- float GetUnbufferedAxisState(const size_t stAxisId) const
- { return jalData[stAxisId].AxisGetUnbufferedState(); }
- /* -- Get axis state ----------------------------------------------------- */
- void SetAxisForwardDeadZone(const size_t stAxisId, const float fDZ)
- { jalData[stAxisId].AxisSetForwardDeadZone(fDZ); }
- void SetAxisReverseDeadZone(const size_t stAxisId, const float fDZ)
- { jalData[stAxisId].AxisSetReverseDeadZone(fDZ); }
- void SetAxisDeadZones(const size_t stAxisId,
- const float fFDZ, const float fRDZ)
- { // Get axis data and set the new values
- JoyAxisInfo &jaiItem = jalData[stAxisId];
- jaiItem.AxisSetForwardDeadZone(fFDZ);
- jaiItem.AxisSetReverseDeadZone(fRDZ);
- }
- /* -- Set default positive deadzone -------------------------------------- */
- void SetReverseDeadZone(const float fDZ)
- { StdForEach(par_unseq, jalData.begin(), jalData.end(),
- [fDZ](JoyAxisInfo &jaiItem)
- { jaiItem.AxisSetReverseDeadZone(fDZ); }); }
- /* -- Set default positive deadzone -------------------------------------- */
- void SetForwardDeadZone(const float fDZ)
- { StdForEach(par_unseq, jalData.begin(), jalData.end(),
- [fDZ](JoyAxisInfo &jaiItem)
- { jaiItem.AxisSetForwardDeadZone(fDZ); }); }
- /* -- Get/Set gamepad status ------------------------------------------- */
- void Connect(void)
- { // Now connected
- FlagSet(JF_CONNECTED);
- // Set gamepad status
- FlagSetOrClear(JF_GAMEPAD, glfwJoystickIsGamepad(GetId()));
- // Get joystick name and if it's not null?
- if(const char*const cpName = GlFWGetJoystickName(GetId()))
- { // If monitor name is blank return blank name
- if(*cpName) IdentSet(cpName);
- // Return blank name
- else IdentSet(cCommon->Unspec());
- } // Return null name
- else IdentSet(cCommon->Null());
- // Refresh joystick data
- RefreshData();
- // We gained this joystick
- cLog->LogInfoExSafe("Input detected $ '$' (I:$;B:$;A:$).",
- GetGamepadOrJoystickString(), IdentGet(), GetId(), GetButtonCount(),
- GetAxisCount());
- // Return if it's not a gamepad
- if(FlagIsClear(JF_GAMEPAD)) return;
- // Report name and identifier
- if(const char*const cpName = glfwGetGamepadName(GetId()))
- cLog->LogDebugExSafe("- Gamepad Name: $.", cpName);
- if(const char*const cpIdent = glfwGetJoystickGUID(GetId()))
- cLog->LogDebugExSafe("- Gamepad Identifier: $.", cpIdent);
- }
- /* -- Remove connected flag ---------------------------------------------- */
- void DoDisconnect(void) { FlagClear(JF_CONNECTED); }
- /* -- Reset data --------------------------------------------------------- */
- void Disconnect(void)
- { // Ignore if already disconnected
- if(IsDisconnected()) return;
- // No longer connected
- DoDisconnect();
- // We lost the specified joystick
- cLog->LogInfoExSafe("Input disconnected $ '$' (I:$).",
- GetGamepadOrJoystickString(), IdentGet(), GetId());
- }
- /* -- Detect joystick ---------------------------------------------------- */
- bool IsPresent(void) { return glfwJoystickPresent(GetId()); }
- /* -- Constructor -------------------------------------------------------- */
- explicit JoyInfo(const int iNId) :
- /* -- Initialisers ----------------------------------------------------- */
- JoyFlags{ JF_NONE }, // Set no flags
- /* -- Other initialisers ----------------------------------------------- */
- iId(iNId), // Set unique joystick id
- /* -- Initialise joystick axes ----------------------------------------- */
-#define JAI(x) JoyAxisInfo{ GLFW_GAMEPAD_AXIS_ ## x }
- /* --------------------------------------------------------------------- */
- jalData{ { // Initialise joystick axes ids
- /* ------------------------------------------------------------------- */
- JAI(LEFT_X), JAI(LEFT_Y), JAI(RIGHT_X),
- JAI(RIGHT_Y), JAI(LEFT_TRIGGER), JAI(RIGHT_TRIGGER)
- /* ------------------------------------------------------------------- */
- } }, // End of joystic axes ids init
- /* --------------------------------------------------------------------- */
-#undef JAI // Done with this macro
- /* -- Initialise joystick buttons -------------------------------------- */
-#define JBL(x) JoyButtonInfo{ GLFW_GAMEPAD_BUTTON_ ## x }
- /* --------------------------------------------------------------------- */
- jblData{ { // Initialise joystick buttons ids
- /* ------------------------------------------------------------------- */
- JBL(A), JBL(B), JBL(X), JBL(Y),
- JBL(LEFT_BUMPER), JBL(RIGHT_BUMPER), JBL(BACK), JBL(START),
- JBL(GUIDE), JBL(LEFT_THUMB), JBL(RIGHT_THUMB), JBL(DPAD_UP),
- JBL(DPAD_RIGHT), JBL(DPAD_DOWN), JBL(DPAD_LEFT)
- /* ------------------------------------------------------------------- */
- } }, // End of joystick button ids init
- /* --------------------------------------------------------------------- */
-#undef JBL // Done with this macro
- /* --------------------------------------------------------------------- */
- stAxes(0), // Set no axies
- stButtons(0) // Set no buttons
- /* -- No code ---------------------------------------------------------- */
- { }
-};/* -- Joystick state typedefs -------------------------------------------- */
-typedef array JoyList; // Actual joystick data
-typedef JoyList::const_iterator JoyListIt; // Iterator for vector of joys
-/* == Input class ========================================================== */
+);/* == Input class ========================================================== */
static class Input final : // Handles keyboard, mouse & controllers
/* -- Base classes ------------------------------------------------------- */
private IHelper, // Initialsation helper
public InputFlags, // Input configuration settings
- private EvtMain::RegVec // Events list to register
-{ /* -- Controller --------------------------------------------------------- */
- JoyList jlData; // Joystick data
- /* -- Console ------------------------------------------------------------ */
+ private EvtMain::RegVec, // Events list to register
+ public Joystick // Joystick class
+{ /* -- Console ------------------------------------------------------------ */
int iConsoleKey1, // First console key
iConsoleKey2; // Second console key
/* -- Events ----------------------------------------------------- */ public:
@@ -354,10 +47,7 @@ static class Input final : // Handles keyboard, mouse & controllers
lfOnMouseFocus, // Mouse focus changed from window
lfOnKey, // Unfiltered key pressed
lfOnChar, // Filtered key pressed
- lfOnDragDrop, // Drag and dropped files
- lfOnJoyState; // Joystick connection event
- /* -------------------------------------------------------------- */ private:
- size_t stConnected; // Joysticks connected
+ lfOnDragDrop; // Drag and dropped files
/* ----------------------------------------------------------------------- */
int iWinWidth, // Actual window width
iWinHeight; // Actual window height
@@ -490,49 +180,14 @@ static class Input final : // Handles keyboard, mouse & controllers
vFiles.clear();
vFiles.shrink_to_fit();
}
- /* -- Enable or disable joystick polling --------------------------------- */
- void EnablePolling(void) { FlagSet(IF_POLLJOYSTICKS); }
- void DisablePolling(void) { FlagClear(IF_POLLJOYSTICKS); }
- /* -- Joystick state changed --------------------------------------------- */
- void OnJoyState(const EvtMainEvent &emeEvent)
- { // Get reference to actual arguments vector
- const EvtMainArgs &emaArgs = emeEvent.aArgs;
- // Get joystick id as int
- const int iId = emaArgs[0].i;
- // What happened to the joystick?
- switch(const int iState = emaArgs[1].i)
- { // Connected?
- case GLFW_CONNECTED:
- // Increase connected count and enable polling if the first
- if(++stConnected == 1) EnablePolling();
- // Setup the joystick state and return
- return SetupJoystickAndDispatch(static_cast(iId));
- // Disconnected?
- case GLFW_DISCONNECTED:
- // Decrease connected count and disable polling if the last
- if(!--stConnected) DisablePolling();
- // Clear the joystick state and return
- return ClearJoystickAndDispatch(static_cast(iId));
- // Invalid code?
- default:
- // Log the bad joystick state and return
- cLog->LogWarningExSafe("Input ignored bad joystick state ($ = $$)!",
- iId, hex, iState);
- // No need to dispatch any events
- return;
- }
- }
/* -- Window past event--------------------------------------------------- */
void OnWindowPaste(const EvtMainEvent&)
{ // Get text in clipboard
- UtfDecoder utfString{ cGlFW->WinGetClipboard() };
+ IUtf::UtfDecoder utfString{ cGlFW->WinGetClipboard() };
// For each character, ddd the character to queue if valid
while(const unsigned int uiChar = utfString.Next())
if(uiChar >= 32) cConsole->OnCharPress(uiChar);
}
- /* -- Event handler for 'glfwSetJoystickCallback' ------------------------ */
- static void OnGamePad(int iJId, int iEvent)
- { cEvtMain->Add(EMC_INP_JOY_STATE, iJId, iEvent); }
/* -- Commit cursor visibility now ------------------------------- */ public:
void CommitCursorNow(void) { cGlFW->WinSetCursor(FlagIsSet(IF_CURSOR)); }
/* -- Commit cursor visibility ------------------------------------------- */
@@ -550,20 +205,9 @@ static class Input final : // Handles keyboard, mouse & controllers
void ResetEnvironment(void)
{ // Reset cursor visibility
SetCursor(true);
- // For each joystick
- for(JoyInfo &jsData : GetJoyList())
- { // Clear the connected flag
- jsData.DoDisconnect();
- // Clear the state
- jsData.ClearState();
- } // No devices connected until the joystick event is set again.
- stConnected = 0;
- // Disable polling
- DisablePolling();
+ // Reset joystick environment
+ JoyReset();
}
- /* -- Get joystick list data --------------------------------------------- */
- JoyList &GetJoyList(void) { return jlData; }
- const JoyList &GetConstJoyList(void) const { return jlData; }
/* -- Get window size ---------------------------------------------------- */
int GetWindowWidth(void) const { return iWinWidth; }
int GetWindowHeight(void) const { return iWinHeight; }
@@ -597,79 +241,9 @@ static class Input final : // Handles keyboard, mouse & controllers
void SetCursorCentre(void)
{ SetCursorPos(cFboCore->GetMatrixWidth() / 2.0f,
cFboCore->GetMatrixHeight() / 2.0f); }
- /* -- Joystick main tick ------------------------------------------------- */
- void DoPollJoysticks(void)
- { for(JoyInfo &jsData : GetJoyList())
- jsData.RefreshDataIfConnected(); }
- void PollJoysticks(void)
- { if(FlagIsSet(IF_POLLJOYSTICKS)) DoPollJoysticks(); }
- bool JoystickExists(const size_t stId)
- { return GetJoyData(stId).IsConnected(); }
- /* -- Dispatch connected event to lua ------------------------------------ */
- void DispatchLuaEvent(const size_t stJoystickId, const bool bConnected)
- { lfOnJoyState.LuaFuncDispatch(static_cast(stJoystickId),
- bConnected); }
- /* -- DeInitialise a joystick -------------------------------------------- */
- void ClearJoystickAndDispatch(const size_t stJoystickId)
- { // Get joystick data and ign ore if joystick wasn't originally connected
- JoyInfo &jsData = GetJoyData(stJoystickId);
- if(jsData.IsDisconnected()) return;
- // Send lua event to let guest know joystick was disconnected
- DispatchLuaEvent(stJoystickId, false);
- // Clear joystick, axis and button data
- jsData.Disconnect();
- jsData.ClearState();
- }
- /* -- Initialise a new joystick ------------------------------------------ */
- void SetupJoystickAndDispatch(const size_t stJoystickId)
- { // Get joystick data and ign ore if joystick wasn't originally connected
- JoyInfo &jsData = GetJoyData(stJoystickId);
- if(jsData.IsConnected()) return;
- // Begin detection and refresh data
- jsData.Connect();
- jsData.RefreshData();
- // Send lua event to let guest know joystick was connected and return
- DispatchLuaEvent(stJoystickId, true);
- }
- /* -- Return a joystick is present? -------------------------------------- */
- void AutoDetectJoystick(void)
- { // Reset connected count
- stConnected = 0;
- // Enumerate joysticks and if joystick is present?
- for(JoyInfo &jsData : GetJoyList())
- // If joystick is present?
- if(jsData.IsPresent())
- { // Send event that the joystick was connected
- SetupJoystickAndDispatch(static_cast(jsData.GetId()));
- // Increase connected count
- ++stConnected;
- } // Send event that the joystick was disconnected
- else ClearJoystickAndDispatch(static_cast(jsData.GetId()));
- // If we did not find joysticks?
- if(!stConnected)
- { // Disable polling to not waste CPU cycles
- DisablePolling();
- // Log no controllers
- return cLog->LogDebugSafe("Input detected no controller devices.");
- } // Enable polling
- EnablePolling();
- // Log result
- cLog->LogDebugExSafe(
- "Input enabling joystick polling as $ devices are detected.",
- stConnected);
- }
- /* -- Clear joystick state ----------------------------------------------- */
- void ClearJoystickButtons(void)
- { StdForEach(par_unseq, GetJoyList().begin(), GetJoyList().end(),
- [](JoyInfo &jsData) { jsData.ClearButtonStateIfConnected(); }); }
- /* -- Clear keyboard, mouse and joystick states -------------------------- */
- void ClearJoyStates(void) { ClearJoystickButtons(); }
- /* -- Return joystick data ----------------------------------------------- */
- JoyInfo &GetJoyData(const size_t stId) { return GetJoyList()[stId]; }
- /* -- Return joysticks count --------------------------------------------- */
- size_t GetJoyCount(void) const { return GetConstJoyList().size(); }
- /* -- Disable/Enable input events ---------------------------------------- */
+ /* -- Disable input events ----------------------------------------------- */
void DisableInputEvents(void) { cEvtMain->UnregisterEx(*this); }
+ /* -- Enable input events ------------------------------------------------ */
void EnableInputEvents(void) { cEvtMain->RegisterEx(*this); }
/* -- Init --------------------------------------------------------------- */
void Init(void)
@@ -684,19 +258,19 @@ static class Input final : // Handles keyboard, mouse & controllers
IHInitialise();
// Log progress
cLog->LogDebugSafe("Input interface is initialising...");
- // Init input engine events
- EnableInputEvents();
// Init input settings
SetRawMouseEnabled(cCVars->GetInternal(INP_RAWMOUSE));
SetStickyKeyEnabled(cCVars->GetInternal(INP_STICKYKEY));
SetStickyMouseEnabled(cCVars->GetInternal(INP_STICKYMOUSE));
// Set/Restore cursor state
SetCursor(FlagIsSet(IF_CURSOR));
- // Register joystick callback
- glfwSetJoystickCallback(OnGamePad);
+ // Init joystick system
+ JoyInit();
+ // Init input engine events
+ EnableInputEvents();
// Log progress
cLog->LogDebugExSafe("Input interface initialised (R:$;J:$).",
- StrFromBoolTF(GlFWIsRawMouseMotionSupported()), GetJoyCount());
+ StrFromBoolTF(GlFWIsRawMouseMotionSupported()), JoyGetCount());
}
/* -- DeInit ------------------------------------------------------------- */
void DeInit(void)
@@ -704,18 +278,18 @@ static class Input final : // Handles keyboard, mouse & controllers
if(IHNotDeInitialise()) return;
// Log progress
cLog->LogDebugSafe("Input interface deinitialising...");
- // Unregister joystick callback
- glfwSetJoystickCallback(nullptr);
// Deinit engine events in the order they were registered
DisableInputEvents();
+ // De-init joystick system
+ JoyDeInit();
// Log progress
cLog->LogDebugSafe("Input interface deinitialised.");
}
/* -- Constructor -------------------------------------------------------- */
Input(void) :
/* -- Initialisers ----------------------------------------------------- */
- IHelper(__FUNCTION__), // Init initialisation helper class
- InputFlags(IF_NONE), // No flags set initially
+ IHelper{ __FUNCTION__ }, // Init initialisation helper class
+ InputFlags{ IF_NONE }, // No flags set initially
/* -- Init events for event manager ------------------------------------ */
EvtMain::RegVec{ // Events list to register
{ EMC_INP_CHAR, bind(&Input::OnFilteredKey, this, _1) },
@@ -726,17 +300,8 @@ static class Input final : // Handles keyboard, mouse & controllers
{ EMC_INP_MOUSE_SCROLL, bind(&Input::OnMouseWheel, this, _1) },
{ EMC_INP_KEYPRESS, bind(&Input::OnKeyPress, this, _1) },
{ EMC_INP_DRAG_DROP, bind(&Input::OnDragDrop, this, _1) },
- { EMC_INP_JOY_STATE, bind(&Input::OnJoyState, this, _1) },
+ { EMC_INP_JOY_STATE, bind(&Joystick::OnJoyState, this, _1) },
},
- /* -- Init joysticks --------------------------------------------------- */
- jlData{ { JoyInfo{ GLFW_JOYSTICK_1 }, JoyInfo{ GLFW_JOYSTICK_2 },
- JoyInfo{ GLFW_JOYSTICK_3 }, JoyInfo{ GLFW_JOYSTICK_4 },
- JoyInfo{ GLFW_JOYSTICK_5 }, JoyInfo{ GLFW_JOYSTICK_6 },
- JoyInfo{ GLFW_JOYSTICK_7 }, JoyInfo{ GLFW_JOYSTICK_8 },
- JoyInfo{ GLFW_JOYSTICK_9 }, JoyInfo{ GLFW_JOYSTICK_10 },
- JoyInfo{ GLFW_JOYSTICK_11 }, JoyInfo{ GLFW_JOYSTICK_12 },
- JoyInfo{ GLFW_JOYSTICK_13 }, JoyInfo{ GLFW_JOYSTICK_14 },
- JoyInfo{ GLFW_JOYSTICK_15 }, JoyInfo{ GLFW_JOYSTICK_16 } } },
/* -- More initialisers ------------------------------------------------ */
iConsoleKey1(GLFW_KEY_UNKNOWN), // Init primary console key
iConsoleKey2(GLFW_KEY_UNKNOWN), // Init secondary console key
@@ -747,8 +312,6 @@ static class Input final : // Handles keyboard, mouse & controllers
lfOnKey{ "OnUnfilteredKey" }, // Init unfiltered keypress lua event
lfOnChar{ "OnFilteredKey" }, // Init filtered keypress lua event
lfOnDragDrop{ "OnDragDrop" }, // Init drag & drop lua event
- lfOnJoyState{ "OnJoyState" }, // Init joy state lua event
- stConnected(0), // Init joystick count to zero
iWinWidth(0), // Window width init by display
iWinHeight(0) // Window height init by display
/* -- No code ---------------------------------------------------------- */
@@ -778,25 +341,6 @@ static class Input final : // Handles keyboard, mouse & controllers
// CVar allowed to be set
return ACCEPT;
}
- /* -- Handle a deadzone change ------------------------------------------- */
- CVarReturn SetDefaultJoyDZ(const float fDZ,
- const function &fcbCallBack)
- { // Bail if invalid deadzone
- if(fDZ > 1) return DENY;
- // Set it
- StdForEach(par_unseq, GetJoyList().begin(),
- GetJoyList().end(), fcbCallBack);
- // Success
- return ACCEPT;
- }
- /* -- Set default negative deadzone -------------------------------------- */
- CVarReturn SetDefaultJoyRevDZ(const float fNewDeadZone)
- { return SetDefaultJoyDZ(fNewDeadZone, [fNewDeadZone](JoyInfo &jiItem)
- { jiItem.SetReverseDeadZone(fNewDeadZone); }); }
- /* -- Set default positive deadzone -------------------------------------- */
- CVarReturn SetDefaultJoyFwdDZ(const float fNewDeadZone)
- { return SetDefaultJoyDZ(fNewDeadZone, [fNewDeadZone](JoyInfo &jiItem)
- { jiItem.SetForwardDeadZone(fNewDeadZone); }); }
/* -- Set first console key ---------------------------------------------- */
CVarReturn SetConsoleKey1(const int iK)
{ return CVarSimpleSetIntNG(iConsoleKey1, iK, GLFW_KEY_LAST); }
diff --git a/src/joystick.hpp b/src/joystick.hpp
new file mode 100644
index 0000000..89ef4e6
--- /dev/null
+++ b/src/joystick.hpp
@@ -0,0 +1,582 @@
+/* == JOYSTICK.HPP ========================================================= **
+** ######################################################################### **
+** ## Mhatxotic Engine (c) Mhatxotic Design, All Rights Reserved ## **
+** ######################################################################### **
+** ## This module defines classes for setting and accessing joystick data ## **
+** ######################################################################### **
+** ========================================================================= */
+#pragma once // Only one incursion allowed
+/* ------------------------------------------------------------------------- */
+namespace IJoystick { // Start of private module namespace
+/* -- Dependencies --------------------------------------------------------- */
+using namespace ICVarDef::P; using namespace IEvtMain::P;
+using namespace IEvtWin::P; using namespace IFlags;
+using namespace IGlFWUtil::P; using namespace IIdent::P;
+using namespace ILog::P; using namespace ILuaFunc::P;
+using namespace IStd::P; using namespace IString::P;
+using namespace Lib::OS::GlFW;
+/* ------------------------------------------------------------------------- */
+namespace P { // Start of public module namespace
+/* == Input flags ========================================================== */
+BUILD_FLAGS(Input,
+ /* ----------------------------------------------------------------------- */
+ // No flags Mouse cursor is enabled?
+ IF_NONE {Flag[0]}, IF_CURSOR {Flag[1]},
+ // Full-screen toggler enabled? Mouse cursor has focus?
+ IF_FSTOGGLER {Flag[2]}, IF_MOUSEFOCUS {Flag[3]},
+ // Send events at startup Do joystick polling?
+ IF_INITEVENTS {Flag[4]}, IF_POLLJOYSTICKS {Flag[5]}
+);/* -- Axis class --------------------------------------------------------- */
+class JoyAxisInfo
+{ /* -------------------------------------------------------------- */ private:
+ const int iId; // Axis unique identifier
+ float fDeadZoneR; // Reverse deadzone threshold
+ float fDeadZoneF; // Forward deadzone threshold
+ float fUnbuffered; // Current unbuffered axis press state
+ int iBuffered; // Current buffered axis press state
+ /* -- Get axis identifier ---------------------------------------- */ public:
+ int AxisGetId(void) const { return iId; }
+ /* -- Get reverse deadzone value ----------------------------------------- */
+ float AxisGetReverseDeadZone(void) const { return fDeadZoneR; }
+ /* -- Get forward deadzone value ----------------------------------------- */
+ float AxisGetForwardDeadZone(void) const { return fDeadZoneF; }
+ /* -- Set reverse deadzone value ----------------------------------------- */
+ void AxisSetReverseDeadZone(const float fDZ) { fDeadZoneR = -fDZ; }
+ /* -- Set forward deadzone value ----------------------------------------- */
+ void AxisSetForwardDeadZone(const float fDZ) { fDeadZoneF = fDZ; }
+ /* -- Get unbuffered state ----------------------------------------------- */
+ float AxisGetUnbufferedState(void) const { return fUnbuffered; }
+ /* -- Get buffered state ------------------------------------------------- */
+ int AxisGetBufferedState(void) const { return iBuffered; }
+ /* -- Clear button state ------------------------------------------------- */
+ void AxisClearState(void) { fUnbuffered = 0.0f; iBuffered = GLFW_RELEASE; }
+ /* -- Set axis state ----------------------------------------------------- */
+ void AxisSetState(const float*const fpData)
+ { // Get the axis reading and if it's moving negatively?
+ fUnbuffered = fpData[AxisGetId()];
+ if(fUnbuffered < fDeadZoneR)
+ { // Released or already in reverse position?
+ if(iBuffered <= GLFW_RELEASE)
+ { // Set to -GLFW_REPEAT if currently -GLFW_PRESSED or
+ // -GLFW_PRESSED if currently GLFW_RELEASE
+ if(iBuffered > -GLFW_REPEAT) --iBuffered;
+ // State changed
+ return;
+ }
+ } // Moving positively?
+ else if(fUnbuffered > fDeadZoneF)
+ { // Released or already in forward position?
+ if(iBuffered >= GLFW_RELEASE)
+ { // Set to GLFW_REPEAT if currentl GLFW_PRESSED or
+ // GLFW_PRESSED if currently GLFW_RELEASE
+ if(iBuffered < GLFW_REPEAT) ++iBuffered;
+ // State changed
+ return;
+ }
+ } // Nothing pressed so reset buffered counter
+ iBuffered = GLFW_RELEASE;
+ }
+ /* -- Constructor with unique id ----------------------------------------- */
+ explicit JoyAxisInfo(const int iNId) :
+ /* -- Initialisers ----------------------------------------------------- */
+ iId(iNId), // Set unique id
+ fDeadZoneR(-0.25f), // Set default reverse deadzone
+ fDeadZoneF(0.25f), // Set default forward deadzone
+ fUnbuffered(0.0f), // Set default unbuffered state
+ iBuffered(GLFW_RELEASE) // Set default state
+ /* -- No code ---------------------------------------------------------- */
+ { }
+};/* -- Axis data list type ------------------------------------------------ */
+template,
+ class Iterator = typename Container::const_iterator>
+ class JoyAxisList : private Container
+{ /* -------------------------------------------------------------- */ private:
+ int iAxes; // Button count as int
+ /* -- Return axes count clamped ------------------------------------------ */
+ int JoyAxisListSizeCountClamped(void) const { return iAxes & 0x7f; }
+ /* -- Return button class ------------------------------------------------ */
+ JoyAxisInfo &JoyAxisListGetMod(const size_t stId) { return (*this)[stId]; }
+ /* -- Return axes array size ------------------------------------- */ public:
+ size_t JoyAxisListSize(void) const { return this->size(); }
+ /* -- Return axes count -------------------------------------------------- */
+ size_t JoyAxisListCount(void) const { return static_cast(iAxes); }
+ /* -- Return button class ------------------------------------------------ */
+ const JoyAxisInfo &JoyAxisListGet(const size_t stId) const
+ { return (*this)[stId]; }
+ /* -- Clear button data -------------------------------------------------- */
+ void JoyAxisListClear(void)
+ { StdForEach(par_unseq, this->begin(),
+ this->begin() + JoyAxisListSizeCountClamped(),
+ [](JoyAxisInfo& jaiRef) { jaiRef.AxisClearState(); }); }
+ /* -- Refresh button data ------------------------------------------------ */
+ void JoyAxisListRefresh(const int iJId)
+ { // Get joystick axes and if found? Refresh axes data for each one
+ if(const float *fpData = GlFWGetJoystickAxes(iJId, iAxes))
+ StdForEach(seq, this->begin(),
+ this->begin() + JoyAxisListSizeCountClamped(),
+ [fpData](JoyAxisInfo &jaiData){ jaiData.AxisSetState(fpData); });
+ else iAxes = 0;
+ }
+ /* -- Get axis state ----------------------------------------------------- */
+ void JoyAxisListSetForwardDeadZone(const size_t stAxisId, const float fDZ)
+ { JoyAxisListGetMod(stAxisId).AxisSetForwardDeadZone(fDZ); }
+ void JoyAxisListSetReverseDeadZone(const size_t stAxisId, const float fDZ)
+ { JoyAxisListGetMod(stAxisId).AxisSetReverseDeadZone(fDZ); }
+ void JoyAxisListSetDeadZones(const size_t stAxisId,
+ const float fFDZ, const float fRDZ)
+ { // Get axis data and set the new values
+ JoyAxisInfo &jaiItem = JoyAxisListGetMod(stAxisId);
+ jaiItem.AxisSetForwardDeadZone(fFDZ);
+ jaiItem.AxisSetReverseDeadZone(fRDZ);
+ }
+ /* -- Set default positive deadzone -------------------------------------- */
+ void JoyAxisListSetReverseDeadZone(const float fDZ)
+ { StdForEach(par_unseq, this->begin(),
+ this->end() + JoyAxisListSizeCountClamped(),
+ [fDZ](JoyAxisInfo &jaiItem)
+ { jaiItem.AxisSetReverseDeadZone(fDZ); }); }
+ /* -- Set default positive deadzone -------------------------------------- */
+ void JoyAxisListSetForwardDeadZone(const float fDZ)
+ { StdForEach(par_unseq, this->begin(),
+ this->end() + JoyAxisListSizeCountClamped(),
+ [fDZ](JoyAxisInfo &jaiItem)
+ { jaiItem.AxisSetForwardDeadZone(fDZ); }); }
+ /* -- Iterators ---------------------------------------------------------- */
+ Iterator JoyAxisListBegin(void) const
+ { return this->cbegin(); }
+ Iterator JoyAxisListEnd(void) const
+ { return this->cbegin() + JoyAxisListSizeCountClamped(); }
+ /* -- Default constructor ------------------------------------- */ protected:
+ JoyAxisList(void) :
+ /* -- Initialise joystick buttons -------------------------------------- */
+#define JAIX(x) JoyAxisInfo{ x }
+#define JAI(x) JAIX(GLFW_GAMEPAD_AXIS_ ## x)
+ /* --------------------------------------------------------------------- */
+ Container{{ // Initialise joystick axes ids
+ /* ------------------------------------------------------------------- */
+ JAI(LEFT_X), JAI(LEFT_Y), JAI(RIGHT_X), JAI(RIGHT_Y),
+ JAI(LEFT_TRIGGER), JAI(RIGHT_TRIGGER), JAIX(7), JAIX(8)
+ /* ------------------------------------------------------------------- */
+ }}, // End of joystick axes ids init
+ /* --------------------------------------------------------------------- */
+#undef JAI // Done with this macro
+#undef JAIX // Done with this macro
+ /* --------------------------------------------------------------------- */
+ iAxes(0) // Initialise axes count
+ /* -- No code ---------------------------------------------------------- */
+ { }
+ /* ----------------------------------------------------------------------- */
+ DELETECOPYCTORS(JoyAxisList) // Suppress default functions for safety
+};/* ----------------------------------------------------------------------- */
+
+/* -- Button class --------------------------------------------------------- */
+class JoyButtonInfo
+{ /* -- Private variables ----------------------------------------- */ private:
+ const int iId; // Button unique identifier
+ unsigned int uiState; // Current buffered butn press state
+ /* -- Get button id ---------------------------------------------- */ public:
+ int ButtonGetId(void) const { return iId; }
+ /* -- Get buffered state (GLFW_RELEASE, GLFW_PRESS or GLFW_REPEAT) ------- */
+ unsigned int ButtonGetState(void) const { return uiState; }
+ /* -- Clear button state ------------------------------------------------- */
+ void ButtonClearState(void) { uiState = GLFW_RELEASE; }
+ /* -- Set button state --------------------------------------------------- */
+ void ButtonSetState(const unsigned char*const ucpState)
+ { // Save unbuffered state and compare it
+ switch(const unsigned int uiUnbuffered =
+ static_cast(ucpState[ButtonGetId()]))
+ { // Button is released?
+ case GLFW_RELEASE:
+ // Reset button state if not released (0 = released)
+ if(uiState > GLFW_RELEASE) uiState = GLFW_RELEASE;
+ // Done
+ return;
+ // Button is pressed? Increase button state (1=pressed and 2=held)
+ case GLFW_PRESS:
+ // Set GLFW_PRESSED if GLFW_RELEASED or
+ // GLFW_REPEAT if GLFW_PRESSED.
+ if(uiState < GLFW_REPEAT) ++uiState;
+ // Done
+ return;
+ // Shouldn't get here
+ default:
+ // Reset to released
+ uiState = GLFW_RELEASE;
+ // Done
+ return;
+ }
+ }
+ /* -- Constructor with unique id ----------------------------------------- */
+ explicit JoyButtonInfo(const int iNId) :
+ /* -- Initialisers ----------------------------------------------------- */
+ iId(iNId), // Set unique id
+ uiState(GLFW_RELEASE) // Set default buffered state
+ /* -- No code ---------------------------------------------------------- */
+ { }
+};/* -- Button data list --------------------------------------------------- */
+template,
+ class Iterator = typename Container::const_iterator>
+ class JoyButtonList : private Container
+{ /* ----------------------------------------------------------------------- */
+ int iButtons; // Button count as int
+ /* -- Return button array size ----------------------------------- */ public:
+ int JoyButtonListSizeCountClamped(void) const { return iButtons & 0x7f; }
+ /* -- Return button array size ------------------------------------------- */
+ size_t JoyButtonListSize(void) const { return this->size(); }
+ /* -- Return button count ------------------------------------------------ */
+ size_t JoyButtonListCount(void) const
+ { return static_cast(iButtons); }
+ /* -- Return button class ------------------------------------------------ */
+ const JoyButtonInfo &JoyButtonListGet(const size_t stId) const
+ { return (*this)[stId]; }
+ /* -- Clear button data -------------------------------------------------- */
+ void JoyButtonListClear(void)
+ { StdForEach(par_unseq, this->begin(),
+ this->begin() + JoyButtonListSizeCountClamped(),
+ [](JoyButtonInfo& jbiRef) { jbiRef.ButtonClearState(); }); }
+ /* -- Refresh button data ------------------------------------------------ */
+ void JoyButtonListRefresh(const int iJId)
+ { // Get joystick buttons and if found? Refresh button data for each one
+ if(const unsigned char*const ucpData =
+ GlFWGetJoystickButtons(iJId, iButtons))
+ StdForEach(seq, this->begin(),
+ this->begin() + JoyButtonListSizeCountClamped(),
+ [ucpData](JoyButtonInfo &jbiData){ jbiData.ButtonSetState(ucpData); });
+ else iButtons = 0;
+ }
+ /* -- Iterators ---------------------------------------------------------- */
+ Iterator JoyButtonListBegin(void) const
+ { return this->cbegin(); }
+ Iterator JoyButtonListEnd(void) const
+ { return this->cbegin() + JoyButtonListSizeCountClamped(); }
+ /* -- Default constructor ------------------------------------- */ protected:
+ JoyButtonList(void) :
+ /* -- Initialise joystick buttons -------------------------------------- */
+#define JBLX(x) JoyButtonInfo{ x }
+#define JBL(n) JBLX(GLFW_GAMEPAD_BUTTON_ ## n)
+ /* --------------------------------------------------------------------- */
+ Container{{ // Initialise joystick buttons ids
+ /* ------------------------------------------------------------------- */
+ JBL(A), JBL(B), JBL(X), JBL(Y),
+ JBL(LEFT_BUMPER), JBL(RIGHT_BUMPER), JBL(BACK), JBL(START),
+ JBL(GUIDE), JBL(LEFT_THUMB), JBL(RIGHT_THUMB), JBL(DPAD_UP),
+ JBL(DPAD_RIGHT), JBL(DPAD_DOWN), JBL(DPAD_LEFT),
+ JBLX( 15),JBLX( 16),JBLX( 17),JBLX( 18),JBLX( 19),JBLX( 20),JBLX( 21),
+ JBLX( 22),JBLX( 23),JBLX( 24),JBLX( 25),JBLX( 26),JBLX( 27),JBLX( 28),
+ JBLX( 29),JBLX( 30),JBLX( 31),JBLX( 32),JBLX( 33),JBLX( 34),JBLX( 35),
+ JBLX( 36),JBLX( 37),JBLX( 38),JBLX( 39),JBLX( 40),JBLX( 41),JBLX( 42),
+ JBLX( 43),JBLX( 44),JBLX( 45),JBLX( 46),JBLX( 47),JBLX( 48),JBLX( 49),
+ JBLX( 50),JBLX( 51),JBLX( 52),JBLX( 53),JBLX( 54),JBLX( 55),JBLX( 56),
+ JBLX( 57),JBLX( 58),JBLX( 59),JBLX( 60),JBLX( 61),JBLX( 62),JBLX( 63),
+ JBLX( 64),JBLX( 65),JBLX( 66),JBLX( 67),JBLX( 68),JBLX( 69),JBLX( 70),
+ JBLX( 71),JBLX( 72),JBLX( 73),JBLX( 74),JBLX( 75),JBLX( 76),JBLX( 77),
+ JBLX( 78),JBLX( 79),JBLX( 80),JBLX( 81),JBLX( 82),JBLX( 83),JBLX( 84),
+ JBLX( 85),JBLX( 86),JBLX( 87),JBLX( 88),JBLX( 89),JBLX( 90),JBLX( 91),
+ JBLX( 92),JBLX( 93),JBLX( 94),JBLX( 95),JBLX( 96),JBLX( 97),JBLX( 98),
+ JBLX( 99),JBLX(100),JBLX(101),JBLX(102),JBLX(103),JBLX(104),JBLX(105),
+ JBLX(106),JBLX(107),JBLX(108),JBLX(109),JBLX(110),JBLX(111),JBLX(112),
+ JBLX(113),JBLX(114),JBLX(115),JBLX(116),JBLX(117),JBLX(118),JBLX(119),
+ JBLX(120),JBLX(121),JBLX(122),JBLX(123),JBLX(124),JBLX(125),JBLX(126),
+ JBLX(127)
+ /* ------------------------------------------------------------------- */
+ }}, // End of joystick button ids init
+ /* ------------------------------------------------------------------- */
+#undef JBL // Done with this macro
+#undef JBX // Done with this macro
+ /* --------------------------------------------------------------------- */
+ iButtons(0) // Initialise button count
+ /* -- No code ---------------------------------------------------------- */
+ { }
+ /* ----------------------------------------------------------------------- */
+ DELETECOPYCTORS(JoyButtonList) // Suppress default functions for safety
+};/* ----------------------------------------------------------------------- */
+/* -- Joystick type typedef ------------------------------------------------ */
+BUILD_FLAGS(Joy,
+ /* ----------------------------------------------------------------------- */
+ // No flags Joystick is connnected?
+ JF_NONE {Flag[0]}, JF_CONNECTED {Flag[1]},
+ // Joystick is actually a gamepad
+ JF_GAMEPAD {Flag[2]}
+);/* -- Joystick class ----------------------------------------------------- */
+class JoyInfo :
+ /* -- Base classes ------------------------------------------------------- */
+ public JoyFlags, // Joystick flags
+ public Ident, // Joystick identifier
+ public JoyAxisList<>, // Joystick axes list
+ public JoyButtonList<> // Joystick button list
+{ /* ----------------------------------------------------------------------- */
+ const int iId; // Unique identifier of this
+ string strName, // Name of controller
+ strGuid; // Guid of controller
+ /* -- Return joystick id ----------------------------------------- */ public:
+ int JoyGetId(void) const { return iId; }
+ /* -- Return type of joystick -------------------------------------------- */
+ const string_view &JoyGetGamepadOrJoystickString(void) const
+ { // Return if it is a gamepad or a joystick
+ static const string_view svGamepad{ "gamepad" },
+ svJoystick{ "joystick" };
+ return FlagIsSet(JF_GAMEPAD) ? svGamepad : svJoystick;
+ }
+ /* -- Refresh data ------------------------------------------------------- */
+ void JoyRefreshData(void)
+ { JoyAxisListRefresh(JoyGetId()); JoyButtonListRefresh(JoyGetId()); }
+ /* -- Joystick is connected/disconnected? -------------------------------- */
+ bool JoyIsConnected(void) const { return FlagIsSet(JF_CONNECTED); }
+ bool JoyIsDisconnected(void) const { return !JoyIsConnected(); }
+ /* -- Clear button state if connected ------------------------------------ */
+ void JoyClearButtonStateIfConnected(void)
+ { if(JoyIsConnected()) JoyButtonListClear(); }
+ /* -- Clear buttons and axis state --------------------------------------- */
+ void JoyClearState(void) { JoyAxisListClear(); JoyButtonListClear(); }
+ /* -- Refresh data if connected ------------------------------------------ */
+ void JoyRefreshDataIfConnected(void)
+ { if(JoyIsConnected()) JoyRefreshData(); }
+ /* -- Return gamepad name ------------------------------------------------ */
+ const string &JoyGamePadName(void) const { return strName; }
+ /* -- Return guid name --------------------------------------------------- */
+ const string &JoyGUID(void) const { return strGuid; }
+ /* -- Return if joystick is a gamepad ------------------------------------ */
+ bool JoyIsGamepad(void) const { return FlagIsSet(JF_GAMEPAD); }
+ /* -- Get/Set gamepad status --------------------------------------------- */
+ void JoyConnect(void)
+ { // Now connected
+ FlagSet(JF_CONNECTED);
+ // Set gamepad status
+ FlagSetOrClear(JF_GAMEPAD, GlFWJoystickIsGamepad(JoyGetId()));
+ // Get joystick name and if it's not null?
+ if(const char*const cpName = GlFWGetJoystickName(JoyGetId()))
+ { // If monitor name is blank return blank name
+ if(*cpName) IdentSet(cpName);
+ // Return blank name
+ else IdentSet(cCommon->Unspec());
+ } // Return null name
+ else IdentSet(cCommon->Null());
+ // Refresh joystick data
+ JoyRefreshData();
+ // We gained this joystick
+ cLog->LogInfoExSafe("Joystick detected $ '$' (I:$;B:$;A:$).",
+ JoyGetGamepadOrJoystickString(), IdentGet(), JoyGetId(),
+ JoyButtonListCount(), JoyAxisListCount());
+ // Report unique identifier
+ if(const char*const cpIdent = GlFWGetJoystickGUID(JoyGetId()))
+ { // Save guid for future reference and log the identifier
+ strGuid = cpIdent;
+ cLog->LogDebugExSafe("- Identifier: $.", strGuid);
+ } // Clear guid
+ else strGuid = cCommon->Null();
+ // Report name if gamepad
+ if(JoyIsGamepad())
+ if(const char*const cpName = GlFWGetGamepadName(JoyGetId()))
+ { // Save name for future reference and log the identifier
+ strName = cpName;
+ cLog->LogDebugExSafe("- Gamepad Name: $.", strName);
+ } // Clear name
+ else strName = cCommon->Null();
+ else strName.clear();
+ }
+ /* -- Remove connected flag ---------------------------------------------- */
+ void JoyDoDisconnect(void) { FlagClear(JF_CONNECTED); }
+ /* -- Reset data --------------------------------------------------------- */
+ void JoyDisconnect(void)
+ { // Ignore if already disconnected
+ if(JoyIsDisconnected()) return;
+ // No longer connected
+ JoyDoDisconnect();
+ // We lost the specified joystick
+ cLog->LogInfoExSafe("Joystick disconnected $ '$' (I:$).",
+ JoyGetGamepadOrJoystickString(), IdentGet(), JoyGetId());
+ }
+ /* -- Detect joystick ---------------------------------------------------- */
+ bool JoyIsPresent(void) { return GlFWJoystickPresent(JoyGetId()); }
+ /* -- Constructor -------------------------------------------------------- */
+ explicit JoyInfo(const int iNId) :
+ /* -- Initialisers ----------------------------------------------------- */
+ JoyFlags{ JF_NONE }, // Set no flags
+ /* -- Other initialisers ----------------------------------------------- */
+ iId(iNId) // Set unique joystick id
+ /* -- No code ---------------------------------------------------------- */
+ { }
+};/* -- Joystick state typedefs -------------------------------------------- */
+typedef array JoyList; // Actual joystick data
+typedef JoyList::const_iterator JoyListIt; // Iterator for vector of joys
+/* ------------------------------------------------------------------------- */
+class Joystick :
+ /* -- Base classes ------------------------------------------------------- */
+ public JoyList // Joystick list data classes
+{ /* -- Variables ---------------------------------------------------------- */
+ bool bPoll; // Poll joysticks?
+ LuaFunc lfOnJoyState; // Joystick lua event
+ size_t stConnected; // Joysticks connected
+ /* -- Event handler for 'glfwSetJoystickCallback' ------------------------ */
+ static void OnGamePad(int iJId, int iEvent)
+ { cEvtMain->Add(EMC_INP_JOY_STATE, iJId, iEvent); }
+ /* -- Enable or disable joystick polling --------------------------------- */
+ void JoyEnablePoll(void) { bPoll = true; }
+ void JoyDisablePoll(void) { bPoll = false; }
+ /* -- Dispatch connected event to lua ------------------------------------ */
+ void JoyDispatchLuaEvent(const size_t stJoystickId, const bool bConnected)
+ { lfOnJoyState.LuaFuncDispatch(static_cast(stJoystickId),
+ bConnected); }
+ /* -- Joystick state changed ------------------------------------- */ public:
+ void OnJoyState(const EvtMainEvent &emeEvent)
+ { // Get reference to actual arguments vector
+ const EvtMainArgs &emaArgs = emeEvent.aArgs;
+ // Get joystick id as int
+ const int iJId = emaArgs[0].i, iEvent = emaArgs[1].i;
+ // Show warning if joystick id is out of range
+ if(static_cast(iJId) >= JoyGetCount())
+ return cLog->LogWarningExSafe(
+ "Joystick event $ for id $ is out of range!", iEvent, iJId);
+ // What happened to the joystick?
+ switch(iEvent)
+ { // Connected?
+ case GLFW_CONNECTED:
+ // Increase connected count and enable polling if the first
+ if(++stConnected == 1) JoyEnablePoll();
+ // Setup the joystick state and return
+ return JoySetupDispatch(static_cast(iJId));
+ // Disconnected?
+ case GLFW_DISCONNECTED:
+ // Decrease connected count and disable polling if the last
+ if(!--stConnected) JoyDisablePoll();
+ // Clear the joystick state and return
+ return JoyClearDispatch(static_cast(iJId));
+ // Invalid code?
+ default:
+ // Log the bad joystick state and return
+ cLog->LogWarningExSafe("Joystick ignored bad state $$ for id $$!",
+ hex, iEvent, dec, iJId);
+ // No need to dispatch any events
+ return;
+ }
+ }
+ /* -- Poll joysticks if enabled ------------------------------------------ */
+ void JoyPoll(void)
+ { if(bPoll)
+ for(JoyInfo &jiRef : *this) jiRef.JoyRefreshDataIfConnected(); }
+ /* -- Return event ------------------------------------------------------- */
+ LuaFunc &JoyGetLuaEvent(void) { return lfOnJoyState; }
+ /* -- Return writable joystick data -------------------------------------- */
+ JoyInfo &JoyGet(const size_t stJId) { return (*this)[stJId]; }
+ /* -- Return read-only joystick data ------------------------------------- */
+ const JoyInfo &JoyGetConst(const size_t stJId) const
+ { return (*this)[stJId]; }
+ /* -- Get read-only acess to joystick list ------------------------------- */
+ const JoyList &JoyListGetConst(void) const { return *this; }
+ /* -- Get connected count ----------------------------------------------- */
+ size_t JoyGetConnected(void) const { return stConnected; }
+ /* -- Return joysticks count --------------------------------------------- */
+ size_t JoyGetCount(void) const { return JoyListGetConst().size(); }
+ /* -- Return if joystick is connected ------------------------------------ */
+ bool JoyIsConnected(const size_t stId)
+ { return JoyGetConst(stId).JoyIsConnected(); }
+ /* -- Clear buttons and axis state --------------------------------------- */
+ void JoyClearStates(void)
+ { StdForEach(par_unseq, this->begin(), this->end(),
+ [](JoyInfo &jiRef) { jiRef.JoyClearButtonStateIfConnected(); }); }
+ /* -- DeInitialise a joystick -------------------------------------------- */
+ void JoyClearDispatch(const size_t stJoystickId)
+ { // Get joystick data and ign ore if joystick wasn't originally connected
+ JoyInfo &jiRef = JoyGet(stJoystickId);
+ if(jiRef.JoyIsDisconnected()) return;
+ // Send lua event to let guest know joystick was disconnected
+ JoyDispatchLuaEvent(stJoystickId, false);
+ // Clear joystick, axis and button data
+ jiRef.JoyDisconnect();
+ jiRef.JoyClearState();
+ }
+ /* -- Initialise a new joystick ------------------------------------------ */
+ void JoySetupDispatch(const size_t stJoystickId)
+ { // Get joystick data and ign ore if joystick wasn't originally connected
+ JoyInfo &jiRef = JoyGet(stJoystickId);
+ if(jiRef.JoyIsConnected()) return;
+ // Begin detection and refresh data
+ jiRef.JoyConnect();
+ jiRef.JoyRefreshData();
+ // Send lua event to let guest know joystick was connected and return
+ JoyDispatchLuaEvent(stJoystickId, true);
+ }
+ /* -- Return a joystick is present? -------------------------------------- */
+ void JoyDetect(void)
+ { // Reset connected count
+ stConnected = 0;
+ // Enumerate joysticks and if joystick is present?
+ for(JoyInfo &jiRef : *this)
+ // If joystick is present?
+ if(jiRef.JoyIsPresent())
+ { // Send event that the joystick was connected
+ JoySetupDispatch(static_cast(jiRef.JoyGetId()));
+ // Increase connected count
+ ++stConnected;
+ } // Send event that the joystick was disconnected
+ else JoyClearDispatch(static_cast(jiRef.JoyGetId()));
+ // If we did not find joysticks?
+ if(!JoyGetConnected())
+ { // Disable polling to not waste CPU cycles
+ JoyDisablePoll();
+ // Log no controllers
+ return cLog->LogDebugSafe("Joystick detected no controller devices.");
+ } // Enable polling
+ JoyEnablePoll();
+ // Log result
+ cLog->LogDebugExSafe(
+ "Joystick enabling joystick polling as $ devices are detected.",
+ JoyGetConnected());
+ }
+ /* -- Reset environment -------------------------------------------------- */
+ void JoyReset(void)
+ { // For each joystick
+ for(JoyInfo &jiRef : *this)
+ { // Clear the connected flag and clear the state
+ jiRef.JoyDoDisconnect();
+ jiRef.JoyClearState();
+ } // No devices connected until the joystick event is set again.
+ stConnected = 0;
+ // Disable polling
+ JoyDisablePoll();
+ }
+ /* -- Init/DeInit joystick callback -------------------------------------- */
+ void JoyInit(void) const { glfwSetJoystickCallback(OnGamePad); }
+ void JoyDeInit(void) const { glfwSetJoystickCallback(nullptr); }
+ /* -- Constructor --------------------------------------------- */ protected:
+ Joystick(void) :
+ /* -- Init joystick ids ------------------------------------------------ */
+ JoyList{{ JoyInfo{ GLFW_JOYSTICK_1 }, JoyInfo{ GLFW_JOYSTICK_2 },
+ JoyInfo{ GLFW_JOYSTICK_3 }, JoyInfo{ GLFW_JOYSTICK_4 },
+ JoyInfo{ GLFW_JOYSTICK_5 }, JoyInfo{ GLFW_JOYSTICK_6 },
+ JoyInfo{ GLFW_JOYSTICK_7 }, JoyInfo{ GLFW_JOYSTICK_8 },
+ JoyInfo{ GLFW_JOYSTICK_9 }, JoyInfo{ GLFW_JOYSTICK_10 },
+ JoyInfo{ GLFW_JOYSTICK_11 }, JoyInfo{ GLFW_JOYSTICK_12 },
+ JoyInfo{ GLFW_JOYSTICK_13 }, JoyInfo{ GLFW_JOYSTICK_14 },
+ JoyInfo{ GLFW_JOYSTICK_15 }, JoyInfo{ GLFW_JOYSTICK_16 } }},
+ /* -- More initialisers ------------------------------------------------ */
+ bPoll(false), // Init disabled polling
+ lfOnJoyState{ "OnJoyState" }, // Init joy state lua event
+ stConnected(0) // Init joystick count to zero
+ /* -- No code ---------------------------------------------------------- */
+ { }
+ /* -- Destructor --------------------------------------------------------- */
+ ~Joystick(void) { JoyDeInit(); }
+ /* ----------------------------------------------------------------------- */
+ DELETECOPYCTORS(Joystick) // Suppress default functions for safety
+ /* -- Handle a deadzone change ----------------------------------- */ public:
+ CVarReturn SetDefaultJoyDZ(const float fDZ,
+ const function &fcbCallBack)
+ { // Return if invalid deadzone else set it and return success
+ if(fDZ > 1) return DENY;
+ StdForEach(par_unseq, this->begin(), this->end(), fcbCallBack);
+ return ACCEPT;
+ }
+ /* -- Set default negative deadzone -------------------------------------- */
+ CVarReturn SetDefaultJoyRevDZ(const float fNewDeadZone)
+ { return SetDefaultJoyDZ(fNewDeadZone, [fNewDeadZone](JoyInfo &jiRef)
+ { jiRef.JoyAxisListSetReverseDeadZone(fNewDeadZone); }); }
+ /* -- Set default positive deadzone -------------------------------------- */
+ CVarReturn SetDefaultJoyFwdDZ(const float fNewDeadZone)
+ { return SetDefaultJoyDZ(fNewDeadZone, [fNewDeadZone](JoyInfo &jiRef)
+ { jiRef.JoyAxisListSetForwardDeadZone(fNewDeadZone); }); }
+};/* ----------------------------------------------------------------------- */
+} // End of public module namespace
+/* ------------------------------------------------------------------------- */
+} // End of private module namespace
+/* == EoF =========================================================== EoF == */
diff --git a/src/json.hpp b/src/json.hpp
index 9089596..c5b1ec0 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -104,7 +104,7 @@ CTOR_BEGIN_ASYNC_DUO(Jsons, Json, CLHelperUnsafe, ICHelperUnsafe),
StdSort(par_unseq, rjvVal.MemberBegin(), rjvVal.MemberEnd(), SortType());
}
/* -- When file data has loaded ---------------------------------- */ public:
- void AsyncReady(FileMap &fmData)
+ void AsyncReady(const FileMap &fmData)
{ // The memory isn't null-terminated so we have to do that and also this
// could be a file map so we can't modify it so we'll load it all properly
// and null-terminate it and place it into a RapidJson StringStream object
@@ -386,7 +386,7 @@ CTOR_BEGIN_ASYNC_DUO(Jsons, Json, CLHelperUnsafe, ICHelperUnsafe),
/* -- No code ---------------------------------------------------------- */
{ }
/* -- Constructor from a filename ---------------------------------------- */
- Json(const string &strFile) :
+ explicit Json(const string &strFile) :
/* -- Initialisers ----------------------------------------------------- */
Json{} // Use default initialisers
/* -- Initialise from file --------------------------------------------- */
diff --git a/src/llcommon.hpp b/src/llcommon.hpp
index 111c352..084d9b2 100644
--- a/src/llcommon.hpp
+++ b/src/llcommon.hpp
@@ -143,6 +143,7 @@ typedef AgIntegerL AgSizeTL;
typedef AgIntegerLG AgSizeTLG;
typedef AgIntegerLG AgSSizeTLG;
typedef AgIntegerLG AgUIntLG;
+typedef AgIntegerLGE AgIntLGE;
typedef AgIntegerLGE AgSizeTLGE;
typedef AgIntegerLGE AgSSizeTLGE;
typedef AgIntegerLGE AgUIntLGE;
diff --git a/src/llinput.hpp b/src/llinput.hpp
index 7082bdd..041caad 100644
--- a/src/llinput.hpp
+++ b/src/llinput.hpp
@@ -18,8 +18,8 @@
namespace LLInput { // Input namespace
/* -- Dependencies --------------------------------------------------------- */
using namespace IGlFW::P; using namespace IGlFWUtil::P;
-using namespace IInput::P; using namespace ILua::P;
-using namespace Common;
+using namespace IInput::P; using namespace IJoystick::P;
+using namespace ILua::P; using namespace Common;
/* ========================================================================= **
** ######################################################################### **
** ## Input common helper classes ## **
@@ -27,16 +27,16 @@ using namespace Common;
** -- Get joystick index argument ------------------------------------------ */
struct AgJoystickId : public AgSizeTLGE {
explicit AgJoystickId(lua_State*const lS, const int iArg) :
- AgSizeTLGE{ lS, iArg, 0, cInput->GetJoyCount() }{} };
+ AgSizeTLGE{ lS, iArg, 0, cInput->JoyGetCount() }{} };
/* -- Get joystick data from joystick index -------------------------------- */
struct AgJoystickData : public ArClass {
explicit AgJoystickData(lua_State*const lS, const int iArg) :
- ArClass{ cInput->GetJoyData(AgJoystickId{lS, iArg}()) }{} };
+ ArClass{ cInput->JoyGet(AgJoystickId{lS, iArg}()) }{} };
/* -- Get axis data from joystick data ------------------------------------- */
struct AgJoystickAxis : public AgSizeTLGE {
explicit AgJoystickAxis(lua_State*const lS, const int iArg,
const JoyInfo &jiData) :
- AgSizeTLGE{ lS, iArg, 0, jiData.GetAxisCount() }{} };
+ AgSizeTLGE{ lS, iArg, 0, jiData.JoyAxisListCount() }{} };
/* -- Get DeadZone argument ------------------------------------------------ */
struct AgDeadZone : public AgNumberLGE {
explicit AgDeadZone(lua_State*const lS, const int iArg) :
@@ -56,7 +56,7 @@ LLFUNC(SetJoyAxisForwardDeadZone, 0,
const AgJoystickData aData{lS, 1};
const AgJoystickAxis aAxis{lS, 2, aData};
const AgDeadZone aDeadZone{lS, 3};
- aData().SetAxisForwardDeadZone(aAxis, aDeadZone))
+ aData().JoyAxisListSetForwardDeadZone(aAxis, aDeadZone))
/* ========================================================================= */
// $ Input.SetJoyAxisReverseDeadZone
// > JId:integer=The joystick id.
@@ -69,7 +69,7 @@ LLFUNC(SetJoyAxisReverseDeadZone, 0,
const AgJoystickData aData{lS, 1};
const AgJoystickAxis aAxis{lS, 2, aData};
const AgDeadZone aDeadZone{lS, 3};
- aData().SetAxisReverseDeadZone(aAxis, aDeadZone))
+ aData().JoyAxisListSetReverseDeadZone(aAxis, aDeadZone))
/* ========================================================================= */
// $ Input.SetJoyAxisDeadZones
// > JId:integer=The joystick id.
@@ -85,7 +85,7 @@ LLFUNC(SetJoyAxisDeadZones, 0,
const AgJoystickAxis aAxis{lS, 2, aData};
const AgDeadZone aDeadZoneForward{lS, 3},
aDeadZoneReverse{lS, 4};
- aData().SetAxisDeadZones(aAxis, aDeadZoneForward, aDeadZoneReverse))
+ aData().JoyAxisListSetDeadZones(aAxis, aDeadZoneForward, aDeadZoneReverse))
/* ========================================================================= */
// $ Input.SetCursorPos
// > X:integer=The X co-ordinate of the mouse cursor.
@@ -103,7 +103,7 @@ LLFUNC(SetCursorPos, 0,
// ? Clears the keyboard, mouse and joystick states which wipes the current
// ? state of all the control methods preventing input.
/* ------------------------------------------------------------------------- */
-LLFUNC(ClearStates, 0, cInput->ClearJoystickButtons())
+LLFUNC(ClearStates, 0, cInput->JoyClearStates())
/* ========================================================================= */
// $ Input.CursorCentre
// ? Sets the mouse cursor in the centre of the window.
@@ -123,7 +123,7 @@ LLFUNC(SetCursor, 0, cInput->SetCursor(AgBoolean{lS, 1}))
// ? Tests if the specified joystick exists.
/* ------------------------------------------------------------------------- */
LLFUNC(JoyExists, 1,
- LuaUtilPushVar(lS, cInput->JoystickExists(AgJoystickId{lS, 1})))
+ LuaUtilPushVar(lS, cInput->JoyIsConnected(AgJoystickId{lS, 1})))
/* ========================================================================= */
// $ Input.GetJoyName
// > Id:integer=The joystick id.
@@ -138,7 +138,7 @@ LLFUNC(GetJoyName, 1, LuaUtilPushVar(lS, AgJoystickData{lS, 1}().IdentGet()))
// ? Returns the number of buttons this joystick supports.
/* ------------------------------------------------------------------------- */
LLFUNC(GetNumJoyButtons, 1,
- LuaUtilPushVar(lS, AgJoystickData{lS, 1}().GetButtonCount()))
+ LuaUtilPushVar(lS, AgJoystickData{lS, 1}().JoyButtonListCount()))
/* ========================================================================= */
// $ Input.GetNumJoyAxises
// > Id:integer=The joystick id.
@@ -146,7 +146,7 @@ LLFUNC(GetNumJoyButtons, 1,
// ? Returns the number of axises this joystick supports.
/* ------------------------------------------------------------------------- */
LLFUNC(GetNumJoyAxises, 1,
- LuaUtilPushVar(lS, AgJoystickData{lS, 1}().GetAxisCount()))
+ LuaUtilPushVar(lS, AgJoystickData{lS, 1}().JoyAxisListCount()))
/* ========================================================================= */
// $ Input.GetJoyButton
// > Id:integer=The joystick id.
@@ -156,12 +156,14 @@ LLFUNC(GetNumJoyAxises, 1,
// ?
// ? Result can be:
// ? =0: The button is not held down.
-// ? >0: The button was held down for this many game ticks.
+// ? =1: The button was pressed.
+// ? >1: The button is being held.
/* ------------------------------------------------------------------------- */
LLFUNC(GetJoyButton, 1,
const AgJoystickData aData{lS, 1};
- const AgSizeTLGE aJoystickButton{lS, 2, 0, aData().GetButtonCount()};
- LuaUtilPushVar(lS, aData().GetButtonState(aJoystickButton)))
+ const AgSizeTLGE aJoystickButton{lS, 2, 0, aData().JoyButtonListCount()};
+ LuaUtilPushVar(lS,
+ aData().JoyButtonListGet(aJoystickButton()).ButtonGetState()))
/* ========================================================================= */
// $ Input.GetJoyAxis
// > Id:integer=The joystick id.
@@ -172,7 +174,7 @@ LLFUNC(GetJoyButton, 1,
LLFUNC(GetJoyAxis, 1,
const AgJoystickData aData{lS, 1};
const AgJoystickAxis aAxis{lS, 2, aData};
- LuaUtilPushVar(lS, aData().GetAxisState(aAxis)))
+ LuaUtilPushVar(lS, aData().JoyAxisListGet(aAxis).AxisGetBufferedState()))
/* ========================================================================= */
// $ Input.GetJoyAxisUB
// > Id:integer=The joystick id.
@@ -182,7 +184,7 @@ LLFUNC(GetJoyAxis, 1,
LLFUNC(GetJoyAxisUB, 1,
const AgJoystickData aData{lS, 1};
const AgJoystickAxis aAxis{lS, 2, aData};
- LuaUtilPushVar(lS, aData().GetUnbufferedAxisState(aAxis)))
+ LuaUtilPushVar(lS, aData().JoyAxisListGet(aAxis).AxisGetUnbufferedState()))
/* ========================================================================= */
// $ Input.OnMouseFocus
// > Func:function=The callback function to use
@@ -242,8 +244,7 @@ LLFUNC(OnChar, 0, cLua->SetLuaRef(lS, cInput->lfOnChar))
// ? (false).
/* ------------------------------------------------------------------------- */
LLFUNC(OnJoyState, 0,
- if(cLua->SetLuaRef(lS, cInput->lfOnJoyState))
- cInput->AutoDetectJoystick())
+ if(cLua->SetLuaRef(lS, cInput->JoyGetLuaEvent())) cInput->JoyDetect())
/* ========================================================================= */
// $ Input.OnKey
// > Func:function=The callback function to use