Files
thunderpad/src/joypad.cpp
John Toman 0b9132b0f0 adds a better debug output function should clean up a lot of 'statement has no effect' warnings
git-svn-id: svn://svn.code.sf.net/p/qjoypad/code/trunk@114 c05e91a0-76c8-4ec0-b377-ef19ce7cc080
2009-09-02 22:42:11 +00:00

294 lines
8.8 KiB
C++

#include "unistd.h"
#include "joypad.h"
#include <stdio.h>
#include <fcntl.h>
#include<stdint.h>
#include <poll.h>
#include <QApplication>
JoyPad::JoyPad( int i, int dev ) {
debug_mesg("Constructing the joypad device with index %d and fd %d\n", i, dev);
//remember the index,
index = i;
//load data from the joystick device, if available.
joydevFileHandle = NULL;
if(dev > 0) {
debug_mesg("Valid file handle, setting up handlers and reading axis configs...\n");
resetToDev(dev);
debug_mesg("done resetting and setting up device index %d\n", i);
} else {
debug_mesg("This joypad does not have a valid file handle, not setting up event listeners\n");
}
//there is no JoyPadWidget yet.
jpw = NULL;
debug_mesg("Done constructing the joypad device %d\n", i);
}
void JoyPad::resetToDev(int dev ) {
debug_mesg("resetting to dev\n");
//remember the device file descriptor
joydev = dev;
//read in the number of axes / buttons
axes = 0;
ioctl (joydev, JSIOCGAXES, &axes);
buttons = 0;
ioctl (joydev, JSIOCGBUTTONS, &buttons);
//make sure that we have the axes we need.
//if one that we need doesn't yet exist, add it in.
//Note: if the current layout has a key assigned to an axis that did not
//have a real joystick axis mapped to it, and this function suddenly brings
//that axis into use, the key assignment will not be lost because the axis
//will already exist and no new axis will be created.
for (int i = 0; i < axes; i++) {
if (Axes[i] == 0) Axes.insert(i, new Axis( i ));
}
for (int i = 0; i < buttons; i++) {
if (Buttons[i] == 0) Buttons.insert(i, new Button( i ));
}
struct pollfd read_struct;
read_struct.fd = joydev;
read_struct.events = POLLIN;
char buf[10];
while(poll(&read_struct, 1, 5)!=0) {
debug_mesg("reading junk data\n");
read(joydev, buf, 10);
}
setupJoyDeviceListener(dev);
debug_mesg("done resetting to dev\n");
}
void JoyPad::setupJoyDeviceListener(int dev) {
debug_mesg("Setting up joyDeviceListeners\n");
joydevFileHandle = new QSocketNotifier(dev, QSocketNotifier::Read, this);
connect(joydevFileHandle, SIGNAL(activated(int)), this, SLOT(handleJoyEvents(int)));
joydevFileException = new QSocketNotifier(dev, QSocketNotifier::Exception, this);
connect(joydevFileException, SIGNAL(activated(int)), this, SLOT(errorRead(int)));
debug_mesg("Done setting up joyDeviceListeners\n");
}
void JoyPad::toDefault() {
//to reset the whole, reset all the parts.
do
{
QHashIterator<int, Axis*> it( Axes );
while (it.hasNext())
{
it.next();
it.value()->toDefault();
}
} while (0);
do
{
QHashIterator<int, Button*> it( Buttons );
while (it.hasNext())
{
it.next();
it.value()->toDefault();
}
} while (0);
}
bool JoyPad::isDefault() {
//if any of the parts are not at default, then the whole isn't either.
do {
QHashIterator<int, Axis*> it( Axes );
while (it.hasNext())
{
it.next();
if (!it.value()->isDefault()) return false;
}
} while (0);
do {
QHashIterator<int, Button*> it( Buttons );
while (it.hasNext())
{
it.next();
if (!it.value()->isDefault()) return false;
}
} while (0);
return true;
}
bool JoyPad::readConfig( QTextStream* stream ) {
toDefault();
QString word;
QChar dump;
int num;
*stream >> word;
while (word != NULL && word != "}") {
word = word.toLower();
if (word == "button") {
*stream >> num;
if (num > 0) {
*stream >> dump;
if (dump != ':') {
error("Layout file error", "Expected ':', found '" + QString(dump) + "'.");
return false;
}
if (Buttons[num-1] == 0) {
Buttons.insert(num-1,new Button(num-1));
}
if (!Buttons[num-1]->read( stream )) {
error("Layout file error", "Error reading Button " + QString::number(num));
return false;
}
}
else {
stream->readLine();
}
}
else if (word == "axis") {
*stream >> num;
if (num > 0) {
*stream >> dump;
if (dump != ':') {
error("Layout file error", "Expected ':', found '" + QString(dump) + "'.");
return false;
}
if (Axes[num-1] == 0) {
Axes.insert(num-1,new Axis(num-1));
}
if (!Axes[num-1]->read(stream)) {
error("Layout file error", "Error reading Axis " + QString::number(num));
return false;
}
}
}
else {
error( "Layout file error", "Error while reading layout. Unrecognized word: " + word );
return false;
}
*stream >> word;
}
return true;
}
//only actually writes something if this JoyPad is NON DEFAULT.
void JoyPad::write( QTextStream* stream ) {
int i = 0; //use to test if this is default or not.
QString result;
QTextStream* s = new QTextStream(&result, QIODevice::WriteOnly);
*s << getName() << " {\n";
do {
QHashIterator<int, Axis*> it( Axes );
while (it.hasNext()) {
it.next();
if (!it.value()->isDefault()) {
it.value()->write( s );
++i;
}
}
} while (0);
QHashIterator<int, Button*> it( Buttons );
while (it.hasNext()) {
it.next();
if (!it.value()->isDefault()) {
it.value()->write( s );
++i;
}
}
if (i > 0) {
*stream << result << "}\n\n";
}
}
void JoyPad::release() {
do {
QHashIterator<int, Axis*> it( Axes );
while (it.hasNext()) {
it.next();
it.value()->release();
}
} while (0);
do {
QHashIterator<int, Button*> it( Buttons );
while (it.hasNext()) {
it.next();
it.value()->release();
}
} while (0);
}
void JoyPad::jsevent( js_event msg ) {
//if there is a JoyPadWidget around, ie, if the joypad is being edited
if (jpw != NULL) {
//tell the dialog there was an event. It will use this to flash
//the appropriate button, if necesary.
jpw->jsevent(msg);
return;
}
//if the dialog is open, stop here. We don't want to signal ourselves with
//the input we generate.
if (qApp->activeWindow() != 0 && qApp->activeModalWidget() != 0) return;
//otherwise, lets create us a fake event! Pass on the event to whichever
//Button or Axis was pressed and let them decide what to do with it.
if (msg.type & JS_EVENT_AXIS) {
debug_mesg("DEBUG: passing on an axis event\n");
debug_mesg("DEBUG: %d %d\n", msg.number, msg.value);
Axes[msg.number]->jsevent(msg.value);
}
else {
debug_mesg("DEBUG: passing on a button event\n");
debug_mesg("DEBUG: %d %d\n", msg.number, msg.value);
Buttons[msg.number]->jsevent(msg.value);
}
}
JoyPadWidget* JoyPad::widget( QWidget* parent, int i) {
//create the widget and remember it.
jpw = new JoyPadWidget(this, i, parent);
return jpw;
}
void JoyPad::handleJoyEvents(int fd) {
js_event msg;
int len;
len = read( joydev, &msg, sizeof(js_event));
//if there was a real event waiting,
if (len == (int) sizeof(js_event)) {
//pass that event on to the joypad!
jsevent(msg);
}
//sleep for a moment. This is just to keep us from throwing all the
//available processer power into madly checking for new events.
//usleep(10000);
}
void JoyPad::releaseWidget() {
//this is how we know that there is no longer a JoyPadWidget around.
jpw = NULL;
}
void JoyPad::unsetDev() {
close(joydev);
joydev = -1;
if(joydevFileHandle != NULL) {
delete joydevFileHandle;
}
}
void JoyPad::errorRead(int fd) {
debug_mesg("There was an error reading off of the device with fd %d, disabling\n", fd);
joydevFileHandle->blockSignals(true);
joydevFileHandle->setEnabled(false);
close(joydev);
if(disconnect(joydevFileHandle , 0, 0, 0)) {
joydevFileHandle->deleteLater();
joydevFileHandle = NULL;
}
if(disconnect(joydevFileException, 0, 0, 0)) {
joydevFileException->setEnabled(false);
joydevFileException->deleteLater();
joydevFileException = NULL;
}
joydev = -1;
debug_mesg("Done disabling device with fd %d\n", fd);
}