13#if defined(SG_WINDOWS)
19#include <simgear/debug/ErrorReportingCallback.hxx>
20#include <simgear/props/props_io.hxx>
26using simgear::PropertyList;
28FGJoystickInput::axis::axis ()
29 : last_value(9999999),
40FGJoystickInput::axis::~axis ()
44FGJoystickInput::joystick::joystick ()
54void FGJoystickInput::joystick::clearAxesAndButtons()
64FGJoystickInput::joystick::~joystick ()
67 clearAxesAndButtons();
80void FGJoystickInput::_remove(
bool all)
82 SGPropertyNode * js_nodes =
fgGetNode(
"/input/joysticks",
true);
86 joystick* joy = &joysticks[
i];
88 if (all || (!joy->predefined))
89 js_nodes->removeChild(
"js",
i);
92 joy->clearAxesAndButtons();
99 SG_LOG(SG_INPUT, SG_DEBUG,
"Initializing joystick bindings");
100 SGPropertyNode_ptr js_nodes =
fgGetNode(
"/input/joysticks",
true);
101 status_node =
fgGetNode(
"/devices/status/joysticks",
true);
106 jsJoystick * js =
new jsJoystick(
i);
107 joysticks[
i].plibJS.reset(js);
108 joysticks[
i].initializing =
true;
110 if (js->notWorking()) {
111 SG_LOG(SG_INPUT, SG_DEBUG,
"Joystick " <<
i <<
" not found");
115 const char *
name = js->getName();
116 SGPropertyNode_ptr js_node = js_nodes->getChild(
"js",
i);
119 SG_LOG(SG_INPUT, SG_INFO,
"Using existing bindings for joystick " <<
i);
122 joysticks[
i].predefined =
false;
123 SG_LOG(SG_INPUT, SG_INFO,
"Looking for bindings for joystick \"" <<
name <<
'"');
124 SGPropertyNode_ptr named;
127 std::string indexedName = computeDeviceIndexName(
name,
i);
130 std::string source = named->getStringValue(
"source",
"user defined");
131 SG_LOG(SG_INPUT, SG_INFO,
"... found joystick: " << source);
134 std::string source = named->getStringValue(
"source",
"user defined");
135 SG_LOG(SG_INPUT, SG_INFO,
"... found joystick: " << source);
137 std::string source = named->getStringValue(
"source",
"user defined");
138 SG_LOG(SG_INPUT, SG_INFO,
"No config found for joystick \"" <<
name
139 <<
"\"\nUsing default: \"" << source <<
'"');
142 SG_LOG(SG_INPUT, SG_WARN,
"No joystick configuration file with <name>" <<
name <<
"</name> entry found!");
145 js_node = js_nodes->getChild(
"js",
i,
true);
146 copyProperties(named, js_node);
147 js_node->setStringValue(
"id",
name);
152std::string FGJoystickInput::computeDeviceIndexName(
const std::string&
name,
156 for (
int i = 0;
i < lastIndex;
i++) {
157 if (joysticks[
i].plibJS && (joysticks[
i].plibJS->getName() ==
name)) {
162 std::ostringstream os;
163 os <<
name <<
"_" << index;
169 SG_LOG(SG_INPUT, SG_DEBUG,
"Re-Initializing joystick bindings");
183 SGPropertyNode_ptr js_nodes =
fgGetNode(
"/input/joysticks");
186 SGPropertyNode_ptr js_node = js_nodes->getChild(
"js",
i);
187 jsJoystick *js = joysticks[
i].plibJS.get();
188 if (!js_node || js->notWorking())
192 simgear::ErrorReportContext errCtx(
"input-device",
"");
196 joyGetDevCaps(
i, &jsCaps,
sizeof(jsCaps) );
197 unsigned int nbuttons = jsCaps.wNumButtons;
203 int naxes = js->getNumAxes();
205 joysticks[
i].naxes = naxes;
206 joysticks[
i].nbuttons = nbuttons;
208 SG_LOG(SG_INPUT, SG_DEBUG,
"Initializing joystick " <<
i);
216 js->getMinRange(minRange);
217 js->getMaxRange(maxRange);
218 js->getCenter(center);
221 joysticks[
i].axes =
new axis[naxes];
222 joysticks[
i].buttons =
new FGButton[nbuttons];
227 std::ostringstream str;
229 std::string module = str.str();
230 nasalsys->createModule(module.c_str(), module.c_str(),
"", 0);
234 for (j = 0; j <
nasal.size(); j++) {
235 nasal[j]->setStringValue(
"module", module.c_str());
236 bool ok = nasalsys->handleCommand(
nasal[j],
nullptr);
239 simgear::reportFailure(simgear::LoadFailure::BadData, simgear::ErrorCode::InputDeviceConfig,
240 "Failed to parse input device Nasal");
248 size_t nb_axes = axes.size();
249 for (j = 0; j < nb_axes; j++ ) {
250 const SGPropertyNode * axis_node = axes[j];
251 const SGPropertyNode * num_node = axis_node->getChild(
"number");
252 int n_axis = axis_node->getIndex();
260 n_axis = num_node->getIntValue(
"unix", -1);
271 if (n_axis >= naxes) {
272 SG_LOG(SG_INPUT, SG_DEBUG,
"Dropping bindings for axis " << n_axis);
275 axis &a = joysticks[
i].axes[n_axis];
277 js->setDeadBand(n_axis, axis_node->getDoubleValue(
"dead-band", 0.0));
279 a.tolerance = axis_node->getDoubleValue(
"tolerance", 0.002);
280 minRange[n_axis] = axis_node->getDoubleValue(
"min-range", minRange[n_axis]);
281 maxRange[n_axis] = axis_node->getDoubleValue(
"max-range", maxRange[n_axis]);
282 center[n_axis] = axis_node->getDoubleValue(
"center", center[n_axis]);
287 a.low.
init(axis_node->getChild(
"low"),
"low", module );
288 a.low_threshold = axis_node->getDoubleValue(
"low-threshold", -0.9);
290 a.high.
init(axis_node->getChild(
"high"),
"high", module );
291 a.high_threshold = axis_node->getDoubleValue(
"high-threshold", 0.9);
292 a.interval_sec = axis_node->getDoubleValue(
"interval-sec",0.0);
293 a.delay_sec = axis_node->getDoubleValue(
"delay-sec",0.0);
294 a.release_delay_sec = axis_node->getDoubleValue(
"release-delay-sec",0.0);
302 for (
auto button_node : buttons ) {
303 size_t n_but = button_node->getIndex();
305 const SGPropertyNode * num_node = button_node->getChild(
"number");
306 if (NULL != num_node)
309 if (n_but >= nbuttons) {
310 SG_LOG(SG_INPUT, SG_DEBUG,
"Dropping bindings for button " << n_but);
314 std::ostringstream buf;
315 buf << (unsigned)n_but;
317 SG_LOG(SG_INPUT, SG_DEBUG,
"Initializing button " << buf.str());
318 FGButton &b = joysticks[
i].buttons[n_but];
319 b.
init(button_node, buf.str(), module );
321 b.
interval_sec = button_node->getDoubleValue(
"interval-sec",0.0);
322 b.
delay_sec = button_node->getDoubleValue(
"delay-sec",0.0);
327 js->setMinRange(minRange);
328 js->setMaxRange(maxRange);
329 js->setCenter(center);
333void FGJoystickInput::updateJoystick(
int index, FGJoystickInput::joystick* joy,
double dt)
338 bool pressed, last_state;
339 bool axes_initialized;
342 jsJoystick * js = joy->plibJS.get();
343 if (js == 0 || js->notWorking()) {
344 joysticks[index].initializing =
true;
346 joysticks[index].init_dt += dt;
347 if (joysticks[index].init_dt >= 1.0) {
348 joysticks[index].plibJS.reset(
new jsJoystick(index) );
349 joysticks[index].init_dt = 0.0;
355 js->read(&buttons, axis_values);
356 if (js->notWorking()) {
357 joysticks[index].initializing =
true;
364 axes_initialized =
true;
365 if (joysticks[index].initializing) {
367 if (!joysticks[index].initialized) {
368 js->read(NULL, joysticks[index].values);
369 joysticks[index].initialized =
true;
373 for (j = 0; j < joy->naxes; j++) {
374 if (axis_values[j] != joysticks[index].values[j])
break;
376 if (j < joy->naxes) {
377 joysticks[index].initializing =
false;
379 axes_initialized =
false;
384 SGPropertyNode_ptr
status = status_node->getChild(
"joystick", index,
true);
385 if (axes_initialized) {
387 status->getChild(
"axis", j,
true)->setFloatValue(axis_values[j]);
392 status->getChild(
"button", j,
true)->setBoolValue((buttons & (1u << j)) > 0 );
396 if (axes_initialized) {
397 for (
int j = 0; j < joy->naxes; j++) {
398 axis &a = joy->axes[j];
404 if (fabs(axis_values[j] - a.last_value) > a.tolerance
406 a.last_value = axis_values[j];
407 for (
unsigned int k = 0; k < a.bindings[
KEYMOD_NONE].size(); k++)
413 pressed = axis_values[j] < a.low_threshold || axis_values[j] > a.high_threshold;
414 delay = (pressed ? last_state ? a.interval_sec : a.delay_sec : a.release_delay_sec );
415 if(pressed || last_state) a.last_dt += dt;
417 if(a.last_dt >= delay) {
418 if (a.low.bindings[modifiers].size())
419 joy->axes[j].low.
update( modifiers, axis_values[j] < a.low_threshold );
421 if (a.high.bindings[modifiers].size())
422 joy->axes[j].high.
update( modifiers, axis_values[j] > a.high_threshold );
430 for (
int j = 0; j < joy->nbuttons; j++) {
431 FGButton &b = joy->buttons[j];
432 pressed = (buttons & (1u << j)) > 0;
435 if(pressed || last_state) b.
last_dt += dt;
438 joy->buttons[j].
update( modifiers, pressed );
448 updateJoystick(
i, &joysticks[
i], dt);
455 SGSubsystemMgr::GENERAL,
456 {{
"nasal", SGSubsystemMgr::Dependency::HARD}});
SGPropertyNode_ptr configurationForDeviceName(const std::string &name)
bool hasConfiguration(const std::string &name) const
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.