Instrument Neutral Distributed Interface INDI 2.2.5
joystickdriver.h
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2013-2026 Jasem Mutlaq. All rights reserved.
3
4 Based on code by Keith Lantz.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 The full GNU General Public License is included in this distribution in the
22 file called LICENSE.
23*******************************************************************************/
24
25#pragma once
26
27#include <iostream>
28#include <functional>
29#include <algorithm>
30#include <fcntl.h>
31#include <pthread.h>
32#include <cmath>
33#include <cstdint>
34#include <linux/joystick.h>
35#include <vector>
36#include <unistd.h>
37
38#define JOYSTICK_DEV "/dev/input/js0"
39
40// ─────────────────────────────────────────────────────────────────────────────
41// ABS event-code constants (subset of linux/input-event-codes.h).
42// Duplicated so we don't require a separate evdev header.
43// ─────────────────────────────────────────────────────────────────────────────
44#ifndef ABS_X
45#define ABS_X 0x00
46#define ABS_Y 0x01
47#define ABS_Z 0x02
48#define ABS_RX 0x03
49#define ABS_RY 0x04
50#define ABS_RZ 0x05
51#define ABS_THROTTLE 0x06
52#define ABS_RUDDER 0x07
53#define ABS_WHEEL 0x08
54#define ABS_GAS 0x09
55#define ABS_BRAKE 0x0a
56#define ABS_HAT0X 0x10
57#define ABS_HAT0Y 0x11
58#define ABS_HAT1X 0x12
59#define ABS_HAT1Y 0x13
60#define ABS_HAT2X 0x14
61#define ABS_HAT2Y 0x15
62#define ABS_HAT3X 0x16
63#define ABS_HAT3Y 0x17
64#endif
65
66typedef struct
67{
68 float theta, r, x, y;
70
71typedef struct
72{
73 std::vector<signed short> button;
74 std::vector<signed short> axis;
76
80enum class JoyAxisType
81{
82 STICK,
83 TRIGGER,
84 HAT,
86};
87
92{
93 int i0;
94 int i1;
95 uint8_t absX;
96 uint8_t absY;
97 bool isHat;
98 const char *name;
99};
100
113{
114 public:
117
118 typedef std::function<void(int joystick_n, double mag, double angle)> joystickFunc;
119 typedef std::function<void(int axis_n, double value)> axisFunc;
120 typedef std::function<void(int button_n, int value)> buttonFunc;
121
122 bool Connect();
123 bool Disconnect();
124
125 void setPort(const char *port);
126 void setPoll(int ms);
127
128 const char *getName();
129 uint32_t getVersion();
130
131 // ── Axis / joystick counts ────────────────────────────────────────
132 uint8_t getNumOfAxes();
133 uint8_t getNumrOfButtons();
134
140 uint8_t getNumOfJoysticks();
141
142 // ── Per-axis type information ─────────────────────────────────────
147 uint8_t getAxisAbsCode(int axis) const;
148
152 JoyAxisType getAxisType(int axis) const;
153
158 const char *getAxisLabel(int axis) const;
159
164 const JoyAxisPair *getJoystickPair(int n) const;
165
166 // ── Position / button queries ─────────────────────────────────────
168 bool buttonPressed(int n);
169
170 // ── Callbacks ─────────────────────────────────────────────────────
171 void setJoystickCallback(joystickFunc joystickCallback);
172 void setAxisCallback(axisFunc axisCallback);
173 void setButtonCallback(buttonFunc buttonCallback);
174
175 // ── Calibration ───────────────────────────────────────────────────
186 void setAxisCalibration(int axis, int center, int minVal, int maxVal);
187
199 void setAxisReversed(int axis, bool reversed);
200
201 protected:
202 static void joystickEvent(int joystick_n, double mag, double angle);
203 static void axisEvent(int axis_n, int value);
204 static void buttonEvent(int button_n, int value);
205
206 static void *loop(void *obj);
207 void readEv();
208
212
213 private:
214 pthread_t thread;
215 bool active;
216 int joystick_fd;
217 js_event *joystick_ev;
218 joystick_state *joystick_st;
219 uint32_t version;
220 uint8_t axes;
221 uint8_t buttons;
222 char name[256];
223 char dev_path[256];
224 int pollMS;
225
226 // ── Axis map (from JSIOCGAXMAP) ───────────────────────────────────
228 std::vector<uint8_t> m_axmap;
229
231 std::vector<JoyAxisPair> m_stickPairs;
232
234 std::vector<int> m_axisToPairIndex;
235
236 // ── Per-axis calibration ──────────────────────────────────────────
237 std::vector<int> m_calCenter;
238 std::vector<int> m_calMin;
239 std::vector<int> m_calMax;
240
241 // ── Per-axis reversal ─────────────────────────────────────────────
243 std::vector<bool> m_axisReversed;
244
245 // ── Helpers ───────────────────────────────────────────────────────
246 float normalizeAxis(int value, int idx) const;
247
249 static JoyAxisType classifyAbsCode(uint8_t absCode);
250
252 static const char *absCodeLabel(uint8_t code);
253
255 void buildAxisPairs();
256};
The JoyStickDriver class provides basic functionality to read events from supported game pads under L...
buttonFunc buttonCallbackFunc
static void buttonEvent(int button_n, int value)
uint8_t getNumOfJoysticks()
getNumOfJoysticks Returns the number of proper analog-stick / hat pairs found via JSIOCGAXMAP....
JoyAxisType getAxisType(int axis) const
getAxisType Returns the classified type of axis.
uint8_t getAxisAbsCode(int axis) const
getAxisAbsCode Returns the ABS_* event code for axis, or 0xFF if the axis map is not available.
const JoyAxisPair * getJoystickPair(int n) const
getJoystickPair Returns the axis-pair descriptor for joystick n, or nullptr if out of range.
uint32_t getVersion()
uint8_t getNumrOfButtons()
static void * loop(void *obj)
void setAxisCalibration(int axis, int center, int minVal, int maxVal)
setAxisCalibration Set piecewise-linear calibration for one axis.
static void axisEvent(int axis_n, int value)
void setButtonCallback(buttonFunc buttonCallback)
void setAxisReversed(int axis, bool reversed)
setAxisReversed Enable or disable reversal for a single axis.
axisFunc axisCallbackFunc
joystickFunc joystickCallbackFunc
std::function< void(int axis_n, double value)> axisFunc
std::function< void(int joystick_n, double mag, double angle)> joystickFunc
void setAxisCallback(axisFunc axisCallback)
const char * getName()
static void joystickEvent(int joystick_n, double mag, double angle)
void setPoll(int ms)
void setJoystickCallback(joystickFunc joystickCallback)
bool buttonPressed(int n)
void setPort(const char *port)
const char * getAxisLabel(int axis) const
getAxisLabel Returns a human-readable label for axis (e.g. "Left-Stick X", "L2 Trigger",...
std::function< void(int button_n, int value)> buttonFunc
joystick_position joystickPosition(int n)
JoyAxisType
Axis type classification inferred from JSIOCGAXMAP.
@ HAT
Digital hat / d-pad (ABS_HAT0X/Y … ABS_HAT3Y)
@ STICK
Analog stick (ABS_X/Y, ABS_RX/RY, throttle, rudder, wheel)
@ TRIGGER
Analog trigger — single-axis input (ABS_Z/RZ, gas, brake)
A matched pair of axis indices that together form a joystick.
bool isHat
True for digital hat / d-pad pairs.
const char * name
Human-readable name (e.g. "Left Stick")
uint8_t absY
ABS_* code for the Y axis.
int i0
Index of the horizontal (X) axis.
uint8_t absX
ABS_* code for the X axis.
int i1
Index of the vertical (Y) axis.
std::vector< signed short > axis
std::vector< signed short > button