Joystick.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2024 Jose Luis Blanco Claraco |
5  | Copyright (C) 2017 Borys Tymchenko (Odessa Polytechnic University) |
6  | Distributed under 3-clause BSD License |
7  | See COPYING |
8  +-------------------------------------------------------------------------+ */
9 
10 // NOTE: This file is borrowed from mrpt-hwdrivers (BSD-3 License)
11 
12 /* +------------------------------------------------------------------------+
13  | Mobile Robot Programming Toolkit (MRPT) |
14  | https://www.mrpt.org/ |
15  | |
16  | Copyright (c) 2005-2024, Individual contributors, see AUTHORS file |
17  | See: https://www.mrpt.org/Authors - All rights reserved. |
18  | Released under BSD License. See: https://www.mrpt.org/License |
19  +------------------------------------------------------------------------+ */
20 
21 #include <mrpt/config.h>
22 #include <mrpt/core/exceptions.h>
23 
24 #ifdef _WIN32
25 #define WIN32_LEAN_AND_MEAN
26 #include <windows.h>
27 //
28 #include <mmsystem.h>
29 
30 #if !defined(__GNUC__)
31 #pragma comment(lib, "WINMM.LIB")
32 #endif
33 #endif
34 
35 #if defined(MRPT_OS_LINUX) || defined(__APPLE__)
36 // Linux
37 #include <fcntl.h>
38 #include <sys/ioctl.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42 
43 #include <cerrno>
44 #include <cstdio>
45 #include <cstdlib>
46 #include <cstring>
47 
48 #if defined(MRPT_OS_LINUX) && defined(HAVE_LINUX_INPUT_H)
49 #include <linux/input.h>
50 #include <linux/joystick.h>
51 #endif
52 #endif
53 
54 #include <mvsim/Joystick.h>
55 
56 using mvsim::Joystick;
57 
58 Joystick::Joystick() = default;
59 
60 /*---------------------------------------------------------------
61  Destructor
62  ---------------------------------------------------------------*/
63 Joystick::~Joystick()
64 {
65 #if defined(MRPT_OS_LINUX) && defined(HAVE_LINUX_INPUT_H)
66  // Close joystick, if open:
67  if (m_joy_fd > 0)
68  {
69  close(m_joy_fd);
70  m_joy_fd = -1;
71  }
72 #endif
73 }
74 
75 /*---------------------------------------------------------------
76  getJoysticksCount
77  Returns the number of Joysticks in the computer.
78  ---------------------------------------------------------------*/
80 {
81  MRPT_START
82 #ifdef _WIN32
83  return joyGetNumDevs();
84 #elif defined(MRPT_OS_LINUX) && defined(HAVE_LINUX_INPUT_H)
85  // Try to open several joy devs:
86  int joy_fd = -1;
87  int nJoys = 0;
88 
89  do
90  {
91  if (-1 != (joy_fd = open(mrpt::format("/dev/input/js%i", nJoys).c_str(), O_RDONLY)))
92  {
93  nJoys++;
94  close(joy_fd);
95  }
96  } while (joy_fd != -1);
97 
98  return nJoys;
99 #else
100  // Apple:
101  return 0;
102 #endif
103  MRPT_END
104 }
105 
106 /*---------------------------------------------------------------
107  Gets joystick information.
108 
109  \return Returns true if successfull, false on error, for example, if joystick
110  is not present.
111  ---------------------------------------------------------------*/
112 bool Joystick::getJoystickPosition(int nJoy, State& output)
113 {
114  MRPT_START
115 #ifdef _WIN32
116  JOYINFO jinfo;
117 
118  int ID = JOYSTICKID1 + nJoy;
119 
120  // Get joy pos:
121  if (JOYERR_NOERROR != joyGetPos(ID, &jinfo)) return false; // Error.
122 
123  // Output data:
124  float x = (jinfo.wXpos - m_x_min) / (float)(m_x_max - m_x_min);
125  float y = (jinfo.wYpos - m_y_min) / (float)(m_y_max - m_y_min);
126  float z = (jinfo.wZpos - m_z_min) / (float)(m_z_max - m_z_min);
127 
128  x = 2 * x - 1;
129  y = 2 * y - 1;
130  z = 2 * z - 1;
131 
132  output.buttons.resize(4);
133 
134  output.buttons[0] = 0 != (jinfo.wButtons & JOY_BUTTON1);
135  output.buttons[1] = 0 != (jinfo.wButtons & JOY_BUTTON2);
136  output.buttons[2] = 0 != (jinfo.wButtons & JOY_BUTTON3);
137  output.buttons[3] = 0 != (jinfo.wButtons & JOY_BUTTON4);
138 
139  output.axes_raw.resize(3);
140  output.axes_raw[0] = jinfo.wXpos;
141  output.axes_raw[1] = jinfo.wYpos;
142  output.axes_raw[2] = jinfo.wZpos;
143 
144  output.axes.resize(3);
145  output.axes[0] = x;
146  output.axes[1] = y;
147  output.axes[2] = z;
148 
149  return true;
150 #elif defined(MRPT_OS_LINUX) && defined(HAVE_LINUX_INPUT_H)
151  // Already open?
152  if (m_joy_index == nJoy && m_joy_fd != -1)
153  {
154  // Ok
155  }
156  else
157  {
158  // Close previous opened joy?
159  if (m_joy_fd != -1) close(m_joy_fd);
160 
161  // Go, try open joystick:
162  if ((m_joy_fd = open(mrpt::format("/dev/input/js%i", nJoy).c_str(), O_RDONLY)) < 0)
163  return false;
164 
165  // Perfect!
166  m_joy_index = nJoy;
167 
168  // Read in non-blocking way: **** Refer to sources of "jstest"!!!! ***
169  fcntl(m_joy_fd, F_SETFL, O_NONBLOCK);
170  }
171 
172  struct js_event js;
173 
174  while (read(m_joy_fd, &js, sizeof(struct js_event)) == sizeof(struct js_event))
175  {
176  // js.number: Button number
177  const size_t jsNum = static_cast<size_t>(js.number);
178 
179  // Button?
180  if (js.type & JS_EVENT_BUTTON)
181  {
182  if (m_joystate_btns.size() < jsNum + 1) m_joystate_btns.resize(jsNum + 1);
183 
184  m_joystate_btns[jsNum] = (js.value != 0);
185  }
186 
187  // Axes?
188  if (js.type & JS_EVENT_AXIS)
189  {
190  if (m_joystate_axes.size() < jsNum + 1) m_joystate_axes.resize(jsNum + 1);
191 
192  m_joystate_axes[jsNum] = static_cast<int>(js.value);
193  }
194  }
195 
196  if (errno != EAGAIN)
197  {
198  // Joystick disconnected?
199  m_joy_fd = -1;
200  m_joy_index = -1;
201  return false;
202  }
203 
204  // Fill out data:
205  output.buttons = m_joystate_btns;
206 
207  const size_t nAxis = m_joystate_axes.size();
208  output.axes_raw.resize(nAxis);
209  output.axes.resize(nAxis);
210 
211  for (size_t i = 0; i < nAxis; i++)
212  {
213  output.axes_raw[i] = m_joystate_axes[i];
214 
215  const int calib_min = m_minPerAxis.size() > i ? m_minPerAxis[i] : -32767;
216  const int calib_max = m_maxPerAxis.size() > i ? m_maxPerAxis[i] : 32767;
217 
218  output.axes[i] = -1.0f + 2.0f * (m_joystate_axes[i] - calib_min) /
219  static_cast<float>(calib_max - calib_min);
220  }
221 
222  return true;
223 #else
224  // Apple.
225  return false;
226 #endif
227  MRPT_END
228 }
229 
230 void Joystick::setLimits(const std::vector<int>& minPerAxis, const std::vector<int>& maxPerAxis)
231 {
232  m_minPerAxis = minPerAxis;
233  m_maxPerAxis = maxPerAxis;
234 }
mvsim::Joystick::m_maxPerAxis
std::vector< int > m_maxPerAxis
Definition: Joystick.h:43
mvsim::Joystick::State::buttons
std::vector< bool > buttons
Definition: Joystick.h:73
mvsim::Joystick::getJoystickPosition
bool getJoystickPosition(int nJoy, State &output)
Definition: Joystick.cpp:112
mvsim::Joystick::getJoysticksCount
static int getJoysticksCount()
Definition: Joystick.cpp:79
mvsim::Joystick::State
Definition: Joystick.h:71
mvsim::Joystick::State::axes
std::vector< float > axes
Definition: Joystick.h:74
mvsim::Joystick::State::axes_raw
std::vector< int > axes_raw
!< Normalized position values [0,1]
Definition: Joystick.h:75
mvsim::Joystick::setLimits
void setLimits(const std::vector< int > &minPerAxis, const std::vector< int > &maxPerAxis)
Definition: Joystick.cpp:230
mvsim::Joystick
Definition: Joystick.h:39
Joystick.h
mvsim::Joystick::m_minPerAxis
std::vector< int > m_minPerAxis
Definition: Joystick.h:43


mvsim
Author(s):
autogenerated on Wed May 28 2025 02:13:08