summaryrefslogtreecommitdiff
path: root/plugins/dfinput/pad.c
diff options
context:
space:
mode:
authorSND\weimingzhi_cp <SND\weimingzhi_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2009-04-16 06:22:51 +0000
committerSND\weimingzhi_cp <SND\weimingzhi_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2009-04-16 06:22:51 +0000
commit8139fbf8204882663446bcb06f68789353597820 (patch)
tree6ea1f39932b33faee84d603e956470e37f135804 /plugins/dfinput/pad.c
downloadpcsxr-8139fbf8204882663446bcb06f68789353597820.tar.gz
git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@23061 e17a0e51-4ae3-4d35-97c3-1a29b211df97
Diffstat (limited to 'plugins/dfinput/pad.c')
-rw-r--r--plugins/dfinput/pad.c989
1 files changed, 989 insertions, 0 deletions
diff --git a/plugins/dfinput/pad.c b/plugins/dfinput/pad.c
new file mode 100644
index 00000000..dd564479
--- /dev/null
+++ b/plugins/dfinput/pad.c
@@ -0,0 +1,989 @@
+/*
+ * Pad for Psemu Pro like Emulators
+ * This is the plugin
+ *
+ * Modified for PCSX-df by Ryan Schultz
+ *
+ * Written by Erich Kitzmuller <ammoq@ammoq.com>
+ * Based on padXwin by linuzappz <linuzappz@hotmail.com>
+ *
+ * Copyright 2002,2003 by Erich Kitzmuller
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#ifdef __linux__
+#include <linux/joystick.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <X11/XKBlib.h>
+#include <pthread.h>
+#include <errno.h>
+#include "padjoy.h"
+
+#ifdef __linux__
+char *LibName = "Gamepad/Keyboard Input";
+#else
+char *LibName = "Keyboard Input";
+#endif
+
+const unsigned char version = VERSION;
+const unsigned char revision = REVISION;
+const unsigned char build = BUILD;
+
+// Prototypes
+static void loadConfig();
+static void *thread_check_joydevice(void *arg);
+static void initPadtime();
+static PadJoyEvent *EventCode2PadJoyEvent(EventCode p_e);
+
+// Filenames for device files, e.g. "/dev/input/js0"
+static char devicefilename[MAXDEVICES][FILENAME_MAX+1] = {"/dev/input/js0", "/dev/input/js1"};
+
+// File desciptors for device files
+static int devicefile[MAXDEVICES] = { -1, -1 };
+
+// Use Threading for joy device input?
+static int use_threads = 1;
+static pthread_t joy_thread;
+static int die_thread_die = 0;
+
+// Emulate Dualshock(TM) analog pad?
+static int use_analog = 0;
+
+// any joydevice open?
+static int joydevice_open = 0;
+
+// initialisation already done?
+static int init_done = 0;
+
+// calibration data
+int minzero[MAXAXES];
+int maxzero[MAXAXES];
+
+// axes status - so only changing status are reported
+int axestatus[MAXDEVICES][MAXAXES];
+
+// Assignment of PSX buttons to Events
+static EventCode PadButtons[MAXDEVICES][MAXPSXBUTTONS] =
+{
+ {
+ KEY_EVENT(XK_e), // L2
+ KEY_EVENT(XK_t), // R2
+ KEY_EVENT(XK_w), // L1
+ KEY_EVENT(XK_r), // R1
+ KEY_EVENT(XK_d), // Triangle
+ KEY_EVENT(XK_x), // Circle
+ KEY_EVENT(XK_z), // Cross
+ KEY_EVENT(XK_s), // Square
+ KEY_EVENT(XK_c), // Select
+ NO_EVENT, // Left Analog
+ NO_EVENT, // Right Analog
+ KEY_EVENT(XK_v), // Start
+ KEY_EVENT(XK_Up), // Up
+ KEY_EVENT(XK_Right), // Right
+ KEY_EVENT(XK_Down), // Down
+ KEY_EVENT(XK_Left), // Left
+ NO_EVENT, // Left Analog X
+ NO_EVENT, // Left Analog Y
+ NO_EVENT, // Right Analog X
+ NO_EVENT // Right Analog Y
+ },
+ {
+ NO_EVENT, // L2
+ NO_EVENT, // R2
+ NO_EVENT, // L1
+ NO_EVENT, // R1
+ NO_EVENT, // Triangle
+ NO_EVENT, // Circle
+ NO_EVENT, // Cross
+ NO_EVENT, // Square
+ NO_EVENT, // Select
+ NO_EVENT, // Left Analog
+ NO_EVENT, // Right Analog
+ NO_EVENT, // Start
+ NO_EVENT, // Up
+ NO_EVENT, // Right
+ NO_EVENT, // Down
+ NO_EVENT, // Left
+ NO_EVENT, // Left Analog X
+ NO_EVENT, // Left Analog Y
+ NO_EVENT, // Right Analog X
+ NO_EVENT // Right Analog Y
+ }
+};
+
+static Display *Dsp;
+static Atom wmprotocols, wmdelwindow;
+
+static EventCode macroLaunch[MAXDEVICES][MAXMACROS];
+static EventCode macroEvents[MAXDEVICES][MAXMACROS][MAXMACROLENGTH];
+static long macroInterval[MAXDEVICES][MAXMACROS][MAXMACROLENGTH];
+static int macroActive[MAXDEVICES];
+static int macroIndex[MAXDEVICES];
+static long macroNext[MAXDEVICES];
+
+unsigned short PadStat[MAXDEVICES] = {0xffff, 0xffff};
+
+int AnalogValue[MAXDEVICES][MAXPSXBUTTONS-4] = {{127,127,127,127}, {127,127,127,127}};
+
+char *PSEgetLibName(void) {
+ return LibName;
+}
+
+uint32_t PSEgetLibType(void) {
+ return 8; // PSE_LT_PAD
+}
+
+uint32_t PSEgetLibVersion(void) {
+ return version<<16|revision<<8|build;
+}
+
+void init_macros() {
+ int i,j;
+
+ for (i=0; i<MAXDEVICES; i++) {
+ for (j=0; j<MAXMACROS; j++) {
+ macroLaunch[i][j] = NO_EVENT;
+ macroEvents[i][j][0] = NO_EVENT;
+ macroInterval[i][j][0] = 0;
+ }
+ macroActive[i] = -1;
+ macroIndex[i] = 0;
+ macroNext[i] = 0;
+ }
+}
+
+long PADinit(long flags) {
+ int i,j;
+
+ init_macros();
+ initPadtime();
+ for (i = 0; i < MAXDEVICES; i++) {
+ maxzero[i] = 250;
+ minzero[i] = -250;
+
+ for (j = 0; j < MAXAXES; j++) {
+ axestatus[i][j] = AXESTS_UNKNOWN;
+ }
+ }
+ loadConfig();
+
+ return 0;
+}
+
+long PADshutdown(void) {
+ return 0;
+}
+
+long PADopen(unsigned long *Disp) {
+ int i,j;
+ int res;
+ PadJoyEvent *pje;
+
+ if (init_done) {
+// fprintf(stderr, "DFInput warning: device already initialized.\n");
+ return 0;
+ }
+
+ Dsp = (Display *)*Disp;
+ XkbSetDetectableAutoRepeat(Dsp, 1, NULL);
+
+ // TODO: find a way to grab the window, and set protocol WM_DELETE_WINDOW if not already set by the video plugin
+ wmprotocols = XInternAtom(Dsp,"WM_PROTOCOLS",0);
+ wmdelwindow = XInternAtom(Dsp,"WM_DELETE_WINDOW",0);
+ //XSetWMProtocols(Dsp, window, &wmdelwindow, 1); //need window!
+
+ joydevice_open = 0;
+
+#ifdef __linux__
+ for (i = 0; i < MAXDEVICES; i++) {
+ if (devicefilename[i][0]) {
+ devicefile[i] = open(devicefilename[i], O_RDONLY);
+ if (devicefile[i] == -1) {
+ fprintf(stderr, "DFInput error: could not open device %s!\n", devicefilename[i]);
+ }
+ else {
+ joydevice_open = 1;
+ }
+ }
+ else {
+ devicefile [i] = -1;
+ }
+ }
+#endif
+
+ for (i = 0; i < MAXDEVICES; i++) {
+ for (j = 0; j < MAXAXES; j++) {
+ axestatus[i][j] = AXESTS_UNUSED;
+ }
+ }
+
+ for (i=0; i<MAXDEVICES; i++) {
+ for (j = 0; j < MAXPSXBUTTONS; j++) {
+ pje = EventCode2PadJoyEvent(PadButtons[i][j]);
+
+ if (pje->event_type == EVENTTYPE_AXISPLUS || pje->event_type == EVENTTYPE_AXISMINUS) {
+ axestatus[pje->pad][pje->no] = AXESTS_UNKNOWN;
+ }
+#ifdef __linux__
+ else if (pje->event_type == EVENTTYPE_ANALOG && use_analog) {
+ axestatus[pje->pad][pje->no] = AXESTS_ANALOG;
+ }
+#endif
+ }
+ }
+
+#ifdef __linux__
+ if (use_threads) {
+ die_thread_die = 0;
+ if (joydevice_open) {
+ fprintf(stderr, "DFInput: starting thread...\n");
+ sleep(1);
+ res = pthread_create(&joy_thread, NULL, thread_check_joydevice, (void *) NULL);
+
+ if (res!=0) {
+ fprintf(stderr, "DFInput warning: thread failure, switching to polling!\n");
+ use_threads = 0;
+ }
+ }
+ }
+#endif
+
+ init_done = 1;
+
+ return 0;
+}
+
+long PADclose(void) {
+ int i;
+
+#ifdef __linux__
+ for (i=0; i<2; i++) {
+ if (devicefile[i] > -1) {
+ close (devicefile[i]);
+ }
+ }
+
+ if (use_threads) {
+ die_thread_die = 1;
+ if (joydevice_open) {
+ pthread_join(joy_thread, (void **) NULL);
+ }
+ }
+#endif
+
+ init_done=0;
+
+ XAutoRepeatOn(Dsp);
+
+ return 0;
+}
+
+long PADquery(void) {
+ return 3; // both pads
+}
+
+static long firstsecond = 0;
+
+static void initPadtime() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ firstsecond = tv.tv_sec;
+}
+
+// construct a time on our own
+long getPadtime() {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec-firstsecond)*10000+tv.tv_usec/100;
+}
+
+// get pending events
+static int getPendingEvents(int millisecondstowait, EventCode *events, int maxevents, int checkJoydevice, int checkXKeyboard, long *timing) {
+ fd_set rfds;
+ int retval;
+ int i;
+ int md;
+ int eventsread=0;
+ XEvent xe;
+ XClientMessageEvent *xce;
+ int cntopen;
+ struct timeval tv;
+ int oldstatus;
+
+#ifdef __linux__
+ struct js_event je;
+
+ if (checkJoydevice) {
+ FD_ZERO(&rfds);
+ md = -1;
+ cntopen=0;
+ for (i=0; i<MAXDEVICES; i++) {
+ if (devicefile[i] > -1) {
+ FD_SET(devicefile[i], &rfds);
+ cntopen++;
+ }
+ if (devicefile[i] > md) md = devicefile[i];
+ }
+ tv.tv_sec = millisecondstowait / 1000;
+ tv.tv_usec = 1000 * (millisecondstowait % 1000);
+
+ retval = select(md + 1, &rfds, NULL, NULL, &tv);
+
+ while (retval && eventsread < maxevents - 2 * checkXKeyboard) {
+ for (i = 0; i < MAXDEVICES; i++) {
+ if (devicefile[i] > -1 && FD_ISSET(devicefile[i], &rfds)) {
+ read (devicefile[i], &je, 8);
+
+ if (je.type == JS_EVENT_AXIS && je.number < MAXAXES) {
+ if (axestatus[i][je.number] == AXESTS_ANALOG) {
+ /* this axe should be reported analog */
+ events[eventsread++] = ANALOGAXIS_EVENT(i,je.number, (je.value + 32768) >> 8);
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+
+ }
+ else if (je.value > maxzero[i]) {
+ if (axestatus[i][je.number] != AXESTS_PLUS &&
+ axestatus[i][je.number] != AXESTS_UNUSED) {
+
+ oldstatus = axestatus[i][je.number];
+
+ axestatus[i][je.number] = AXESTS_PLUS;
+
+ events[eventsread++] = AXISPLUS_EVENT(i, je.number);
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread==maxevents) return eventsread;
+
+ if (oldstatus == AXESTS_MINUS) {
+ events[eventsread++] = RELEASE_EVENT + AXISMINUS_EVENT(i, je.number);
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+ }
+
+ }
+ }
+ else if (je.value < minzero[i]) {
+ if (axestatus[i][je.number] != AXESTS_MINUS &&
+ axestatus[i][je.number] != AXESTS_UNUSED) {
+
+ oldstatus = axestatus[i][je.number];
+
+ axestatus[i][je.number] = AXESTS_MINUS;
+
+ events[eventsread++] = AXISMINUS_EVENT(i, je.number);
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+
+ if (oldstatus == AXESTS_PLUS) {
+ events[eventsread++] = RELEASE_EVENT+AXISPLUS_EVENT(i, je.number);
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+ }
+ }
+ }
+ else {
+ if (axestatus[i][je.number] != AXESTS_CENTER &&
+ axestatus[i][je.number] != AXESTS_UNUSED) {
+
+ oldstatus = axestatus[i][je.number];
+
+ axestatus[i][je.number] = AXESTS_CENTER;
+
+ if (oldstatus == AXESTS_PLUS) {
+ events[eventsread++] = RELEASE_EVENT+AXISPLUS_EVENT(i,je.number);
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+ }
+ else if (oldstatus == AXESTS_MINUS) {
+ events[eventsread++] = RELEASE_EVENT+AXISMINUS_EVENT(i,je.number);
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+ }
+ }
+ }
+ }
+ else if (je.type == JS_EVENT_BUTTON && je.number<MAXBUTTONS) {
+ events[eventsread++] = (je.value ? 0 : RELEASE_EVENT) + BUTTON_EVENT(i, je.number);
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+ }
+ }
+ }
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ retval = select(md + 1, &rfds, NULL, NULL, &tv);
+ }
+
+ }
+#endif
+
+ if (checkXKeyboard) {
+ while ((i = XPending(Dsp))) {
+ while (i--) {
+ XNextEvent(Dsp, &xe);
+ switch (xe.type) {
+ case KeyPress:
+ events[eventsread++] = KEY_EVENT(XLookupKeysym((XKeyEvent *)&xe, 0));
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+ break;
+ case KeyRelease:
+ events[eventsread++] = RELEASE_EVENT + KEY_EVENT(XLookupKeysym((XKeyEvent *)&xe, 0));
+ if (timing) {
+ (*timing) = getPadtime();
+ timing++;
+ }
+ if (eventsread == maxevents) return eventsread;
+ break;
+ case ClientMessage:
+ xce = (XClientMessageEvent *)&xe;
+ if (xce->message_type == wmprotocols && (Atom)xce->data.l[0] == wmdelwindow) {
+ events[eventsread++] = KEY_EVENT(XK_Escape);
+ if (eventsread == maxevents) return eventsread;
+ }
+ break;
+/*
+ case FocusIn:
+ XAutoRepeatOff(Dsp);
+ break;
+ case FocusOut:
+ XAutoRepeatOn(Dsp);
+ break;
+*/
+ }
+ }
+ }
+ }
+
+ return eventsread;
+}
+
+// Key Event not used...
+static EventCode keyLeftOver = NO_EVENT;
+
+static void CheckPads(int checkJoydevice, int checkXKeyboard, int blocking) {
+ EventCode events[MAXCNT];
+ int cnt;
+ int release;
+ EventCode e;
+ int i,j,k,l;
+ int notfound;
+ long now;
+ int v;
+
+ if (checkJoydevice || checkXKeyboard) {
+ cnt = getPendingEvents(blocking<<8, events, MAXCNT, checkJoydevice, checkXKeyboard, NULL);
+ }
+ else {
+ cnt = 0;
+ }
+
+ // more events come from the macros
+ // only process makros when blocking is not set, since
+ // this cannot be done by the joy device thread
+
+ if (!blocking) {
+ now= -1;
+ for (j = 0; j < MAXDEVICES; j++) {
+ if (macroActive[j] > -1) {
+ if (now < 0) {
+ now = getPadtime();
+ }
+
+ while (now >= macroNext[j] && cnt < MAXCNT && macroActive[j] > -1) {
+ events[cnt++]=macroEvents[j][macroActive[j]][macroIndex[j]];
+ macroIndex[j]++;
+ if (macroIndex[j] == MAXMACROLENGTH || macroEvents[j][macroActive[j]][macroIndex[j]] == NO_EVENT) {
+ macroActive[j] = -1;
+ }
+ else {
+ macroNext[j] += macroInterval[j][macroActive[j]][macroIndex[j]];
+ }
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < cnt; i++) {
+ e = events[i];
+ if (e >= RELEASE_EVENT) {
+ release = 1;
+ e -= RELEASE_EVENT;
+ }
+ else {
+ release = 0;
+ }
+
+ notfound = 1;
+ if (e >= FIRST_ANALOG_EVENT) {
+ v = e & 0xff;
+ e -= v;
+ for (j = 0; j < MAXDEVICES && notfound; j++) {
+ for (k = 16; k < MAXPSXBUTTONS && notfound; k++) {
+ if (PadButtons[j][k] == e) {
+ AnalogValue[j][k - 16] = v;
+ notfound = 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (j=0; j<MAXDEVICES && notfound; j++) {
+ for (k=0; k<MAXPSXBUTTONS && notfound; k++) {
+ if (PadButtons[j][k] == e) {
+ notfound = 0;
+ if (release) {
+ PadStat[j]|=(1<<k);
+ }
+ else {
+ PadStat[j]&=~(1<<k);
+ }
+ }
+ }
+ for (k=0; k<MAXMACROS && notfound; k++) {
+ if (macroLaunch[j][k] == e) {
+ notfound=0;
+ if (release) {
+ // release all buttons pressed by the macro
+ for (l=macroIndex[j]; l<MAXMACROLENGTH && macroEvents[j][macroActive[j]][l] != NO_EVENT; l++) {
+ if (macroEvents[j][macroActive[j]][l] >= RELEASE_EVENT) {
+ if (cnt<MAXCNT) {
+ events[cnt++]=macroEvents[j][macroActive[j]][l];
+ }
+ }
+
+ }
+
+ macroActive[j]= -1; // stop Makro from running
+ }
+ else {
+ macroActive[j]=k;
+ macroIndex[j]=0;
+ macroNext[j]=getPadtime();
+ }
+ }
+ }
+ }
+ }
+ if (notfound && e < FIRST_JOY_EVENT) {
+ keyLeftOver = e + (release << 30);
+ }
+ }
+}
+
+
+long PADreadPort1(PadDataS *pad) {
+ if (!use_threads) {
+ CheckPads(joydevice_open, 1, 0);
+ }
+ else {
+ CheckPads(0, 1, 0);
+ }
+
+ pad->buttonStatus = PadStat[0];
+#ifdef __linux__
+ if (use_analog) {
+ pad->controllerType = 7; // analog Pad
+ pad->leftJoyX = AnalogValue[0][0];
+ pad->leftJoyY = AnalogValue[0][1];
+ pad->rightJoyX = AnalogValue[0][2];
+ pad->rightJoyY = AnalogValue[0][3];
+ }
+ else {
+#endif
+ pad->controllerType = 4; // standard
+#ifdef __linux__
+ }
+#endif
+ // ePSXe different from pcsx, swap bytes
+ pad->buttonStatus = (pad->buttonStatus>>8)|(pad->buttonStatus<<8);
+
+ return 0;
+}
+
+long PADreadPort2(PadDataS *pad) {
+ if (!use_threads) {
+ CheckPads(joydevice_open, 1, 0);
+ }
+ else {
+ CheckPads(0, 1, 0);
+ }
+
+ pad->buttonStatus = PadStat[1];
+#ifdef __linux__
+ if (use_analog) {
+ pad->controllerType = 7; // analog Pad
+ pad->leftJoyX = AnalogValue[1][0];
+ pad->leftJoyY = AnalogValue[1][1];
+ pad->rightJoyX = AnalogValue[1][2];
+ pad->rightJoyY = AnalogValue[1][3];
+ }
+ else {
+#endif
+ pad->controllerType = 4; // standard
+#ifdef __linux__
+ }
+#endif
+
+ // ePSXe different from pcsx, swap bytes
+ pad->buttonStatus = (pad->buttonStatus>>8)|(pad->buttonStatus<<8);
+
+ return 0;
+}
+
+long PADkeypressed(void) {
+ int ksym;
+
+ CheckPads(0, 1, 1);
+
+ if (keyLeftOver == NO_EVENT) return 0;
+
+ ksym = keyLeftOver-FIRST_KEY_EVENT;
+ keyLeftOver = NO_EVENT;
+
+ return ksym;
+}
+
+#ifdef __linux__
+
+static void *thread_check_joydevice(void *arg) {
+ while (!die_thread_die) {
+ CheckPads(1, 0, 1);
+ }
+ return NULL;
+}
+
+#endif
+
+// analyse Eventcode
+static PadJoyEvent *EventCode2PadJoyEvent(EventCode p_e) {
+ static PadJoyEvent event;
+ EventCode e;
+ int i,p;
+
+ event.event_type = EVENTTYPE_NONE;
+ event.pad = 0;
+ event.no = 0;
+ event.value = 0;
+
+ if (!p_e) {
+ return &event;
+ }
+
+ e = p_e;
+
+ if (e > RELEASE_EVENT) {
+ event.value = 0;
+ e -= RELEASE_EVENT;
+ }
+ else {
+ event.value = 1;
+ }
+
+ if (e && e<FIRST_JOY_EVENT) {
+ event.event_type = EVENTTYPE_KEY;
+ event.no = e;
+ return &event;
+ }
+
+ if (e >= FIRST_ANALOG_EVENT) {
+ event.event_type = EVENTTYPE_ANALOG;
+ event.pad = (e-FIRST_ANALOG_EVENT)/(256*MAXAXES);
+ event.no = (e-ANALOGAXIS_EVENT(event.pad,0,0))/256;
+ event.value = e & 0xff;
+ return &event;
+ }
+
+
+ for (p=0; p<MAXDEVICES; p++) {
+ for (i=0; i<MAXAXES; i++) {
+ if (e == AXISPLUS_EVENT(p,i)) {
+ event.event_type = EVENTTYPE_AXISPLUS;
+ event.pad = p;
+ event.no = i;
+ return &event;
+ }
+ if (e == AXISMINUS_EVENT(p,i)) {
+ event.event_type = EVENTTYPE_AXISMINUS;
+ event.pad = p;
+ event.no = i;
+ return &event;
+ }
+ }
+
+ for (i=0; i<MAXBUTTONS; i++) {
+ if (e == BUTTON_EVENT(p,i)) {
+ event.event_type = EVENTTYPE_BUTTON;
+ event.pad = p;
+ event.no = i;
+ return &event;
+ }
+ }
+ }
+
+ return &event;
+}
+
+
+// reversal of EventCode2String
+static EventCode String2EventCode(char *s) {
+ static char buffer[256];
+ int i,p;
+ char *q;
+ char push_release;
+ EventCode e;
+
+ if (s[0] >= '0' && s[0] <= '9') return atoi(s); // allow numeric input
+
+ e=0;
+ push_release = 'P';
+
+ switch(s[0]) {
+ case 'K':
+ push_release = s[1];
+ strncpy(buffer, s + 3, 255);
+ q=buffer;
+ i=1;
+ while (*q) {
+ if (*q=='"') i = !i;
+ if (*q==' ' && !i)
+ *q='\0';
+ else
+ q++;
+ }
+ if (s[2]=='"' && buffer[0] && buffer[strlen(buffer)-1]=='"') {
+ buffer[strlen(buffer)-1] = '\0';
+ e = KEY_EVENT(XStringToKeysym(buffer));
+ }
+ break;
+ case 'A':
+ if (s[1] >= '0' && s[1] <= '1' && strlen(s) >= 5) {
+ p = s[1] - '0';
+ push_release = s[2];
+ i = atoi(s+3);
+ q=s+3;
+ while (*q && *q != '+' && *q != '-') q++;
+ if (*q == '+')
+ e = AXISPLUS_EVENT(p,i);
+ else if (*q == '-')
+ e = AXISMINUS_EVENT(p,i);
+ }
+ break;
+ case 'B':
+ if (s[1] >= '0' && s[1] <= '1' && strlen(s) >= 4) {
+ p = s[1] - '0';
+ push_release = s[2];
+ i = atoi(s + 3);
+ e = BUTTON_EVENT(p, i);
+ }
+ break;
+ case 'X':
+ if (s[1] >= '0' && s[1] <= '1' && strlen(s) >= 5) {
+ p = s[1] - '0';
+ i = atoi(s + 3);
+ q = s + 3;
+ while (*q && *q != 'v') q++;
+ if (*q == 'v')
+ e = ANALOGAXIS_EVENT(p,i,atoi(q + 1));
+ }
+ break;
+ }
+
+ if (push_release == 'R')
+ return e + RELEASE_EVENT;
+ else
+ return e;
+}
+
+static void loadConfig() {
+ FILE *f;
+ int i;
+ char line[FILENAME_MAX+30];
+ int pad=0;
+ int macronr=0;
+ char *val;
+
+ f = fopen("dfinput.cfg", "r");
+ if (f == NULL) {
+// fprintf(stderr, "DFInput warning: config file not found.\n");
+ return;
+ }
+
+ while(!feof(f)) {
+ fgets(line, FILENAME_MAX+29, f);
+ i=strlen(line)-1;
+ while (i>0 && line[i]<32) line[i--]='\0';
+
+ val=NULL;
+ while(i>0) {
+ if (line[i]=='=') val = line+(i+1);
+ i--;
+ }
+ if (val) {
+ while (*val==' ') val++;
+ }
+
+ if (!strcmp(line, "[general]")) {
+ // nothing to do
+ }
+ else if (!strncmp(line, "use_threads", 11)) {
+ use_threads = atoi(val);
+ }
+ else if (!strncmp(line, "use_analog", 10)) {
+ use_analog = atoi(val);
+ }
+
+ else if (!strcmp(line, "[pad 1]")) {
+ pad = 0;
+ }
+ else if (!strcmp(line, "[pad 2]")) {
+ pad = 1;
+ }
+ else if (!strncmp(line, "[macro ", 7)) {
+ macronr = atoi(line+7)-1;
+ if (macronr<0 || macronr>=MAXMACROS) macronr=0;
+ }
+ else if (!strncmp(line, "devicefilename", 14)) {
+ strcpy(devicefilename[pad], val);
+ }
+ else if (!strncmp(line, "minzero", 7)) {
+ minzero[pad] = atoi(val);
+ }
+ else if (!strncmp(line, "maxzero", 7)) {
+ maxzero[pad] = atoi(val);
+ }
+ else if (!strncmp(line, "event_l2", 8)) PadButtons[pad][0] = String2EventCode(val);
+ else if (!strncmp(line, "event_r2", 8)) PadButtons[pad][1] = String2EventCode(val);
+ else if (!strncmp(line, "event_l1", 8)) PadButtons[pad][2] = String2EventCode(val);
+ else if (!strncmp(line, "event_r1", 8)) PadButtons[pad][3] = String2EventCode(val);
+ else if (!strncmp(line, "event_triangle", 14)) PadButtons[pad][4] = String2EventCode(val);
+ else if (!strncmp(line, "event_circle", 12)) PadButtons[pad][5] = String2EventCode(val);
+ else if (!strncmp(line, "event_cross", 11)) PadButtons[pad][6] = String2EventCode(val);
+ else if (!strncmp(line, "event_square", 12)) PadButtons[pad][7] = String2EventCode(val);
+ else if (!strncmp(line, "event_select", 12)) PadButtons[pad][8] = String2EventCode(val);
+ else if (!strncmp(line, "event_lanalog", 13)) PadButtons[pad][9] = String2EventCode(val);
+ else if (!strncmp(line, "event_ranalog", 13)) PadButtons[pad][10] = String2EventCode(val);
+ else if (!strncmp(line, "event_start", 11)) PadButtons[pad][11] = String2EventCode(val);
+ else if (!strncmp(line, "event_up", 8)) PadButtons[pad][12] = String2EventCode(val);
+ else if (!strncmp(line, "event_right", 11)) PadButtons[pad][13] = String2EventCode(val);
+ else if (!strncmp(line, "event_down", 10)) PadButtons[pad][14] = String2EventCode(val);
+ else if (!strncmp(line, "event_left", 10)) PadButtons[pad][15] = String2EventCode(val);
+ else if (!strncmp(line, "event_lanax", 11)) PadButtons[pad][16] = String2EventCode(val);
+ else if (!strncmp(line, "event_lanay", 11)) PadButtons[pad][17] = String2EventCode(val);
+ else if (!strncmp(line, "event_ranax", 11)) PadButtons[pad][18] = String2EventCode(val);
+ else if (!strncmp(line, "event_ranay", 11)) PadButtons[pad][19] = String2EventCode(val);
+ else if (!strncmp(line, "event_launch", 12)) macroLaunch[pad][macronr] = String2EventCode(val);
+ else if (!strncmp(line, "events", 6)) {
+ i=0;
+ while (*val) {
+ macroEvents[pad][macronr][i++]=String2EventCode(val);
+ while (*val && *val!=' ') val++;
+ if (*val==' ') val++;
+ }
+ macroEvents[pad][macronr][i]=NO_EVENT;
+ }
+ else if (!strncmp(line, "interval", 8)) {
+ i=0;
+ while (*val) {
+ macroInterval[pad][macronr][i++]=atol(val);
+ while (*val && *val!=' ') val++;
+ if (*val==' ') val++;
+ }
+ }
+// else fprintf(stderr, "DFInput error: can't interpret %s\n", line);
+ }
+}
+
+long PADconfigure(void) {
+ system("cfg/cfgDFInput");
+ return 0;
+}
+
+
+/*---------------------------------------------------------------------*/
+/* About dialogue stuff */
+/*---------------------------------------------------------------------*/
+
+
+void PADabout(void) {
+ system("cfg/cfgDFInput -about");
+}
+
+#ifdef __linux__
+
+long PADtest(void) {
+ int i;
+ int f;
+
+ int r=1;
+
+ loadConfig();
+ for (i=0; i<2; i++) {
+ if (devicefilename[i][0]) {
+ r = 0;
+ f = open(devicefilename[i], O_RDONLY);
+ if (f == -1) {
+ return -1;
+ }
+ close (f);
+ }
+ }
+
+ return r;
+}
+
+#endif