/* This file is part of the KDE Control Center Module for Joysticks SPDX-FileCopyrightText: 2003 Martin Koller SPDX-License-Identifier: GPL-2.0-or-later */ #include "joydevice.h" #include #include #include #include #include #include #include #include #include #include JoyDevice::JoyDevice(const QString &devicefile) : devName(devicefile) , joyFd(-1) , buttons(0) , axes(0) , amin(nullptr) , amax(nullptr) , corr(nullptr) , origCorr(nullptr) { } QString JoyDevice::errText(ErrorCode code) const { switch (code) { case SUCCESS: return QString(); case OPEN_FAILED: { return i18n("The given device %1 could not be opened: %2", devName, strerror(errno)); } case NO_JOYSTICK: { return i18n("The given device %1 is not a joystick.", devName); } case ERR_GET_VERSION: { return i18n("Could not get kernel driver version for joystick device %1: %2", devName, strerror(errno)); } case WRONG_VERSION: { int version = 0; int fd = ::open(devName.toLatin1(), O_RDONLY); if (fd != -1) { ::ioctl(fd, JSIOCGVERSION, &version); ::close(fd); } KLocalizedString loc = ki18n("The current running kernel driver version (%1.%2.%3) is not the one this module was compiled for (%4.%5.%6)."); loc = loc.subs(version >> 16); loc = loc.subs((version >> 8) & 0xFF); loc = loc.subs(version & 0xFF); loc = loc.subs(JS_VERSION >> 16); loc = loc.subs((JS_VERSION >> 8) & 0xFF); loc = loc.subs(JS_VERSION & 0xFF); return loc.toString(); } case ERR_GET_BUTTONS: { return i18n("Could not get number of buttons for joystick device %1: %2", devName, strerror(errno)); } case ERR_GET_AXES: { return i18n("Could not get number of axes for joystick device %1: %2", devName, strerror(errno)); } case ERR_GET_CORR: { return i18n("Could not get calibration values for joystick device %1: %2", devName, strerror(errno)); } case ERR_RESTORE_CORR: { return i18n("Could not restore calibration values for joystick device %1: %2", devName, strerror(errno)); } case ERR_INIT_CAL: { return i18n("Could not initialize calibration values for joystick device %1: %2", devName, strerror(errno)); } case ERR_APPLY_CAL: { return i18n("Could not apply calibration values for joystick device %1: %2", devName, strerror(errno)); } default: return i18n("internal error - code %1 unknown", int(code)); } } JoyDevice::ErrorCode JoyDevice::open() { if (joyFd != -1) return JoyDevice::SUCCESS; // already open int fd = ::open(devName.toLatin1(), O_RDONLY); if (fd == -1) return JoyDevice::OPEN_FAILED; // we could open the devicefile, now check if a joystick is attached char name[128]; if (::ioctl(fd, JSIOCGNAME(sizeof(name)), &name) == -1) { ::close(fd); return JoyDevice::NO_JOYSTICK; } // check the kernel driver version int version; if (::ioctl(fd, JSIOCGVERSION, &version) == -1) { ::close(fd); return JoyDevice::ERR_GET_VERSION; } if (version != JS_VERSION) { ::close(fd); return JoyDevice::WRONG_VERSION; } char bt = 0, ax = 0; if (::ioctl(fd, JSIOCGBUTTONS, &bt) == -1) { ::close(fd); return JoyDevice::ERR_GET_BUTTONS; } if (::ioctl(fd, JSIOCGAXES, &ax) == -1) { ::close(fd); return JoyDevice::ERR_GET_AXES; } struct js_corr *oldCorr = new struct js_corr[ax]; if (::ioctl(fd, JSIOCGCORR, oldCorr) == -1) { ::close(fd); delete[] oldCorr; return JoyDevice::ERR_GET_CORR; } if (bt < 0) { ::close(fd); delete[] oldCorr; return JoyDevice::ERR_GET_BUTTONS; } descr = name; joyFd = fd; axes = ax; buttons = bt; origCorr = oldCorr; corr = new struct js_corr[axes]; amin = new int[axes]; amax = new int[axes]; int i; for (i = 0; i < axes; i++) resetMinMax(i); return JoyDevice::SUCCESS; } void JoyDevice::close() { if (joyFd == -1) return; ::close(joyFd); joyFd = -1; descr = QString(); delete[] amin; delete[] amax; amin = nullptr; amax = nullptr; delete[] corr; corr = nullptr; delete[] origCorr; origCorr = nullptr; } int JoyDevice::axisMin(int axis) const { if ((axis < 0) || (axis >= axes)) return 0; return amin[axis]; } int JoyDevice::axisMax(int axis) const { if ((axis < 0) || (axis >= axes)) return 0; return amax[axis]; } JoyDevice::ErrorCode JoyDevice::initCalibration() { if (joyFd == -1) return JoyDevice::ERR_INIT_CAL; int i; // Reset all current correction values for (i = 0; i < axes; i++) { corr[i].type = JS_CORR_NONE; corr[i].prec = 0; } if (::ioctl(joyFd, JSIOCSCORR, corr) == -1) return JoyDevice::ERR_INIT_CAL; for (i = 0; i < axes; i++) corr[i].type = JS_CORR_BROKEN; return JoyDevice::SUCCESS; } JoyDevice::ErrorCode JoyDevice::applyCalibration() { if (joyFd == -1) return JoyDevice::ERR_APPLY_CAL; if (::ioctl(joyFd, JSIOCSCORR, corr) == -1) return JoyDevice::ERR_APPLY_CAL; return JoyDevice::SUCCESS; } void JoyDevice::resetMinMax(int axis, int value) { amin[axis] = value; amax[axis] = value; } void JoyDevice::calcPrecision() { if (!corr) return; int i; for (i = 0; i < axes; i++) { corr[i].prec = amax[i] - amin[i]; qDebug() << "Precision for axis: " << i << ": " << corr[i].prec; } } JoyDevice::ErrorCode JoyDevice::restoreCorr() { if (joyFd == -1) return JoyDevice::SUCCESS; if (::ioctl(joyFd, JSIOCSCORR, origCorr) == -1) return JoyDevice::ERR_RESTORE_CORR; else return JoyDevice::SUCCESS; } JoyDevice::~JoyDevice() { close(); } bool JoyDevice::getEvent(JoyDevice::EventType &type, int &number, int &value) { number = value = 0; int ret; fd_set readSet; FD_ZERO(&readSet); FD_SET(joyFd, &readSet); struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 10000; ret = ::select(joyFd + 1, &readSet, nullptr, nullptr, &timeout); if (ret == 1) // got an event from the joystick { struct js_event e; if (::read(joyFd, &e, sizeof(struct js_event)) == sizeof(struct js_event)) { if (e.type & JS_EVENT_BUTTON) { type = JoyDevice::BUTTON; value = e.value; number = e.number; return true; } if (e.type & JS_EVENT_AXIS) { type = JoyDevice::AXIS; value = e.value; number = e.number; // store min, max values if (e.value < amin[number]) amin[number] = e.value; if (e.value > amax[number]) amax[number] = e.value; return true; } } } return false; // no event } void JoyDevice::calcCorrection(int axis, int *min, int *center, int *max) { const int MIN = 0; const int MAX = 1; double a, b, c, d; a = center[MIN]; // inputs.cmin[1]; b = center[MAX]; // inputs.cmax[1]; c = 32767.0 / (center[MIN] - min[MAX]); // (inputs.cmin[1] - inputs.cmax[0]); d = 32767.0 / (max[MIN] - center[MAX]); // (inputs.cmin[2] - inputs.cmax[1]); corr[axis].coef[0] = (int)rint(a); corr[axis].coef[1] = (int)rint(b); corr[axis].coef[2] = (int)rint(c * 16384.0); corr[axis].coef[3] = (int)rint(d * 16384.0); qDebug() << "min min: " << min[0] << " max: " << min[1]; qDebug() << "max min: " << max[0] << " max: " << max[1]; qDebug() << "Correction values for axis: " << axis << ": " << corr[axis].coef[0] << ", " << corr[axis].coef[1] << ", " << corr[axis].coef[2] << ", " << corr[axis].coef[3] << Qt::endl; }