g13gui/g13d/stick.cc
June Tate-Gans e97cb2c6c3 stick: Fix a logic error I introduced
Late night hacking causes all kinds of silliness. We only want to stop running
an action when the key is not pressed now, but was prior pressed. My logic
caused it to fire when not pressed and not prior pressed, erroneously, leading
to stuck keys.
2021-04-25 23:16:03 -05:00

174 lines
4.0 KiB
C++

/* This file contains code for managing keys and profiles
*
*/
#include <boost/foreach.hpp>
#include <iomanip>
#include <iostream>
#include "device.h"
namespace G13 {
Stick::Stick(Device &keypad)
: _keypad(keypad),
_bounds(0, 0, 255, 255),
_center_pos(127, 127),
_north_pos(127, 0) {
_stick_mode = STICK_KEYS;
auto add_zone = [this, &keypad](const std::string &name, double x1, double y1,
double x2, double y2) {
_zones.push_back(StickZone(
*this, "STICK_" + name, ZoneBounds(x1, y1, x2, y2),
ActionPtr(new Action_Keys(keypad, "KEY_" + name))));
};
add_zone("UP", 0.0, 0.1, 1.0, 0.3);
add_zone("DOWN", 0.0, 0.7, 1.0, 0.9);
add_zone("LEFT", 0.0, 0.0, 0.2, 1.0);
add_zone("RIGHT", 0.8, 0.0, 1.0, 1.0);
add_zone("PAGEUP", 0.0, 0.0, 1.0, 0.1);
add_zone("PAGEDOWN", 0.0, 0.9, 1.0, 1.0);
}
StickZone *Stick::zone(const std::string &name, bool create) {
BOOST_FOREACH (StickZone &zone, _zones) {
if (zone.name() == name) {
return &zone;
}
}
if (create) {
_zones.push_back(
StickZone(*this, name, ZoneBounds(0.0, 0.0, 0.0, 0.0)));
return zone(name);
}
return 0;
}
void Stick::set_mode(stick_mode_t m) {
if (m == _stick_mode) {
return;
}
if (_stick_mode == STICK_CALCENTER || _stick_mode == STICK_CALBOUNDS ||
_stick_mode == STICK_CALNORTH) {
_recalc_calibrated();
}
_stick_mode = m;
if (_stick_mode == STICK_CALBOUNDS) {
_bounds.tl = StickCoord(255, 255);
_bounds.br = StickCoord(0, 0);
}
}
void Stick::_recalc_calibrated() {
}
void Stick::remove_zone(const StickZone &zone) {
StickZone target(zone);
_zones.erase(std::remove(_zones.begin(), _zones.end(), target), _zones.end());
}
void Stick::dump(std::ostream &out) const {
BOOST_FOREACH (const StickZone &zone, _zones) {
zone.dump(out);
out << std::endl;
}
}
void StickZone::dump(std::ostream &out) const {
out << " " << std::setw(20) << name() << " " << _bounds << " ";
if (action()) {
action()->dump(out);
} else {
out << " (no action)";
}
}
void StickZone::test(const ZoneCoord &loc) {
if (!_action) return;
bool prior_active = _active;
_active = _bounds.contains(loc);
if (!_active) {
if (prior_active) {
_action->act(false);
}
} else {
_action->act(true);
}
}
StickZone::StickZone(Stick &stick, const std::string &name,
const ZoneBounds &b, ActionPtr action)
: Actionable<Stick>(stick, name),
_active(false),
_bounds(b) {
set_action(action);
}
void Stick::parse_joystick(unsigned char *buf) {
_current_pos.x = buf[1];
_current_pos.y = buf[2];
// update targets if we're in calibration mode
switch (_stick_mode) {
case STICK_CALCENTER:
_center_pos = _current_pos;
return;
case STICK_CALNORTH:
_north_pos = _current_pos;
return;
case STICK_CALBOUNDS:
_bounds.expand(_current_pos);
return;
default:
break;
};
// determine our normalized position
double dx = 0.5;
if (_current_pos.x <= _center_pos.x) {
dx = _current_pos.x - _bounds.tl.x;
dx /= (_center_pos.x - _bounds.tl.x) * 2;
} else {
dx = _bounds.br.x - _current_pos.x;
dx /= (_bounds.br.x - _center_pos.x) * 2;
dx = 1.0 - dx;
}
double dy = 0.5;
if (_current_pos.y <= _center_pos.y) {
dy = _current_pos.y - _bounds.tl.y;
dy /= (_center_pos.y - _bounds.tl.y) * 2;
} else {
dy = _bounds.br.y - _current_pos.y;
dy /= (_bounds.br.y - _center_pos.y) * 2;
dy = 1.0 - dy;
}
G13_LOG(trace, "x=" << _current_pos.x << " y=" << _current_pos.y
<< " dx=" << dx << " dy=" << dy);
ZoneCoord jpos(dx, dy);
if (_stick_mode == STICK_ABSOLUTE) {
_keypad.send_event(EV_ABS, ABS_X, _current_pos.x);
_keypad.send_event(EV_ABS, ABS_Y, _current_pos.y);
} else if (_stick_mode == STICK_KEYS) {
BOOST_FOREACH (StickZone &zone, _zones) { zone.test(jpos); }
return;
}
}
} // namespace G13