# HG changeset patch # User John Tsiombikas # Date 1310647220 -10800 # Node ID dd02002227a2c40ece5a94d70b0e7e2307b964d1 # Parent 15293518d92b003ea6c0ccce309713293729fd71 - added a few commandline arguments to combjs - trying to make a gui frontend diff -r 15293518d92b -r dd02002227a2 Makefile --- a/Makefile Wed Jul 13 07:12:57 2011 +0300 +++ b/Makefile Thu Jul 14 15:40:20 2011 +0300 @@ -1,3 +1,5 @@ +PREFIX = /usr/local + src = $(wildcard *.c) obj = $(src:.c=.o) bin = combjs @@ -11,3 +13,14 @@ .PHONY: clean clean: rm -f $(obj) $(bin) + +.PHONY: install +install: $(bin) + mkdir -p $(PREFIX)/bin + cp $(bin) $(PREFIX)/bin/$(bin) + chown root $(PREFIX)/bin/$(bin) + chmod 4775 $(PREFIX)/bin/$(bin) + +.PHONY: uninstall +uninstall: + rm -f $(PREFIX)/bin/$(bin) diff -r 15293518d92b -r dd02002227a2 combjs.c --- a/combjs.c Wed Jul 13 07:12:57 2011 +0300 +++ b/combjs.c Thu Jul 14 15:40:20 2011 +0300 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ #define DBG_MAX_BN 32 struct joystick { + char *devfile; char *name; int fd; int num_bn, num_axes; @@ -45,16 +47,22 @@ int create_virt_js(const char *uinput_dev, const char *devname); int handle_event(struct joystick *js, struct js_event *ev); int add_joystick(const char *devfile); +struct joystick *open_joystick(const char *devfile); +void close_joystick(struct joystick *js); +void print_joystick(struct joystick *js, int verbose); +int list_devices(void); +int cmp_jsp(const void *a, const void *b); void sig_handler(int sig); int proc_cmdline(int argc, char **argv); void print_usage(const char *argv0); int vfd = -1; -const char *virt_dev_name = "combjs - virtual multi-joystick combiner"; -const char *uinput_dev_name = "/dev/uinput"; +const char *virt_name = "combjs - virtual multi-joystick combiner"; +const char *uinput_dev = "/dev/uinput"; struct joystick *jslist, *jstail; int num_vaxes, num_vbn; +int verbose = 1; int main(int argc, char **argv) @@ -67,11 +75,16 @@ return 1; } - if((vfd = create_virt_js(uinput_dev_name, virt_dev_name)) == -1) { + if((vfd = create_virt_js(uinput_dev, virt_name)) == -1) { cleanup(); return 1; } + /* if we where running suid-root, drop root priviledges */ + if(geteuid() == 0) { + setuid(getuid()); + } + for(;;) { fd_set rdset; struct joystick *js = jslist; @@ -207,35 +220,9 @@ int add_joystick(const char *devfile) { struct joystick *js; - char buf[512]; - if(!(js = calloc(1, sizeof *js))) { - perror("failed to allocate memory"); - goto err; - } - - if((js->fd = open(devfile, O_RDONLY | O_NONBLOCK)) == -1) { - fprintf(stderr, "failed to open %s: %s\n", devfile, strerror(errno)); - goto err; - } - - if(ioctl(js->fd, JSIOCGNAME(sizeof buf), buf) == -1) { - fprintf(stderr, "failed to get joystick name for %s: %s\n", devfile, strerror(errno)); - strcpy(buf, ""); - } - if(!(js->name = malloc(strlen(buf) + 1))) { - perror("failed to allocate memory"); - goto err; - } - strcpy(js->name, buf); - - if(ioctl(js->fd, JSIOCGBUTTONS, &js->num_bn) == -1) { - fprintf(stderr, "failed to get joystick %s's number of buttons: %s\n", devfile, strerror(errno)); - goto err; - } - if(ioctl(js->fd, JSIOCGAXES, &js->num_axes) == -1) { - fprintf(stderr, "failed to get joystick %s's number of axes: %s\n", devfile, strerror(errno)); - goto err; + if(!(js = open_joystick(devfile))) { + return -1; } if(!jstail) { @@ -250,18 +237,141 @@ num_vaxes = js->axis_offset + js->num_axes; num_vbn = js->bn_offset + js->num_bn; - printf("added joystick %s: %s\n", devfile, js->name); - printf(" - %d axes (offset: %d)\n", js->num_axes, js->axis_offset); - printf(" - %d buttons (offset: %d)\n", js->num_bn, js->bn_offset); + if(verbose) { + printf("added "); + print_joystick(js, 1); + } return 0; +} -err: +struct joystick *open_joystick(const char *devfile) +{ + struct joystick *js; + char buf[512]; + + if(!(js = calloc(1, sizeof *js))) { + perror("failed to allocate memory"); + close_joystick(js); + return 0; + } + + if(!(js->devfile = malloc(strlen(devfile) + 1))) { + perror("failed to allocate memory"); + close_joystick(js); + return 0; + } + strcpy(js->devfile, devfile); + + if((js->fd = open(devfile, O_RDONLY | O_NONBLOCK)) == -1) { + fprintf(stderr, "failed to open %s: %s\n", devfile, strerror(errno)); + close_joystick(js); + return 0; + } + + if(ioctl(js->fd, JSIOCGNAME(sizeof buf), buf) == -1) { + fprintf(stderr, "failed to get joystick name for %s: %s\n", devfile, strerror(errno)); + strcpy(buf, ""); + } + if(!(js->name = malloc(strlen(buf) + 1))) { + perror("failed to allocate memory"); + close_joystick(js); + return 0; + } + strcpy(js->name, buf); + + if(ioctl(js->fd, JSIOCGBUTTONS, &js->num_bn) == -1) { + fprintf(stderr, "failed to get joystick %s's number of buttons: %s\n", devfile, strerror(errno)); + close_joystick(js); + return 0; + } + if(ioctl(js->fd, JSIOCGAXES, &js->num_axes) == -1) { + fprintf(stderr, "failed to get joystick %s's number of axes: %s\n", devfile, strerror(errno)); + close_joystick(js); + return 0; + } + return js; +} + +void close_joystick(struct joystick *js) +{ if(js) { close(js->fd); free(js->name); free(js); } - return -1; +} + +void print_joystick(struct joystick *js, int verbose) +{ + if(verbose) { + printf("joystick %s: %s\n", js->devfile, js->name); + printf(" - %d axes (offset: %d)\n", js->num_axes, js->axis_offset); + printf(" - %d buttons (offset: %d)\n", js->num_bn, js->bn_offset); + } else { + printf("%s: \"%s\", axes: %d, buttons: %d\n", js->devfile, js->name, js->num_axes, js->num_bn); + } +} + +int list_devices(void) +{ + DIR *dir; + struct dirent *dent; + char buf[PATH_MAX]; + struct joystick **jsp_arr, *js; + int i, num_js = 0; + + /* we don't need root priviledges for this */ + if(geteuid() == 0) { + setuid(getuid()); + } + + if(!(dir = opendir("/dev/input"))) { + perror("failed to open /dev/input"); + return -1; + } + + while((dent = readdir(dir))) { + if(strstr(dent->d_name, "js") == dent->d_name) { + sprintf(buf, "/dev/input/%s", dent->d_name); + + if(!(js = open_joystick(buf))) { + continue; + } + + if(jslist) { + js->next = jslist; + } + jslist = js; + num_js++; + } + } + closedir(dir); + + if(!(jsp_arr = malloc(num_js * sizeof *jsp_arr))) { + perror("failed to allocate memory"); + return -1; + } + + js = jslist; + for(i=0; inext; + } + + qsort(jsp_arr, num_js, sizeof *jsp_arr, cmp_jsp); + + for(i=0; idevfile, (*(struct joystick**)b)->devfile); } void sig_handler(int sig) @@ -278,6 +388,24 @@ if(argv[i][0] == '-') { if(argv[i][2] == 0) { switch(argv[i][1]) { + case 'd': + uinput_dev = argv[++i]; + break; + + case 'n': + virt_name = argv[++i]; + break; + + case 'l': + if(list_devices() == -1) { + exit(1); + } + exit(0); + + case 's': + verbose = 0; + break; + case 'h': print_usage(argv[0]); exit(0); @@ -309,5 +437,11 @@ void print_usage(const char *argv0) { - printf("usage: %s [dev1] ... [dev n]\n", argv0); + printf("usage: %s [options] [dev1] ... [dev n]\n", argv0); + printf("options:\n"); + printf(" -d: uinput device file (default: /dev/uinput)\n"); + printf(" -n: name for the virtual combined joystick\n"); + printf(" -s: silent (reduces verbosity)\n"); + printf(" -l: print a list of all the joystick devices and exit\n"); + printf(" -h: print usage information and exit\n"); } diff -r 15293518d92b -r dd02002227a2 gui/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui/Makefile Thu Jul 14 15:40:20 2011 +0300 @@ -0,0 +1,29 @@ +src = $(wildcard *.cc) moc_gui.cc moc_droplist.cc +obj = $(src:.cc=.o) +dep = $(obj:.o=.d) +bin = combjs-gui + +uihdr = ui_main.h + +CXX = g++ +CXXFLAGS = -Wall -g `pkg-config --cflags QtGui QtDesigner` +LDFLAGS = `pkg-config --libs QtGui QtDesigner` +MOC = moc +UIC = uic + +$(bin): $(uihdr) $(obj) + $(CXX) -o $@ $(obj) $(LDFLAGS) + +moc_%.cc: %.h + moc -o $@ $< + +ui_%.h: %.ui + uic -o $@ $< + +.PHONY: clean +clean: + rm -f $(obj) $(bin) ui_*.h moc_*.cc + +.PHONY: cleandep +cleandep: + rm -f $(dep) diff -r 15293518d92b -r dd02002227a2 gui/combjs-gui.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui/combjs-gui.cc Thu Jul 14 15:40:20 2011 +0300 @@ -0,0 +1,66 @@ +#include +#include +#include +#include "combjs.h" +#include "gui.h" + +MainWindow *main_win; + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + main_win = new MainWindow; + main_win->show(); + + return app.exec(); +} + +int enum_joysticks(std::vector *jsvec) +{ + jsvec->clear(); + + FILE *pipe = popen("combjs -l", "r"); + if(!pipe) { + QMessageBox::critical(main_win, "Critical error", + "Failed to execute combjs, make sure it's installed in the path."); + exit(1); + } + + char line[512]; + while(fgets(line, sizeof line, pipe)) { + Joystick js; + char *ptr, *end; + + if(!(ptr = strchr(line, ':'))) { + goto inval; + } + *ptr++ = 0; + + js.dev = line; + + if(!(ptr = strchr(ptr, '"')) || !(end = strchr(ptr + 1, '"'))) { + goto inval; + } + *end = 0; + + js.name = ptr + 1; + ptr = end + 1; + + if(sscanf(ptr, ", axes: %d, buttons: %d", &js.num_axes, &js.num_bn) != 2) { + goto inval; + } + + js.isvirt = false; + jsvec->push_back(js); + } + pclose(pipe); + + return jsvec->size(); + +inval: + QMessageBox::critical(main_win, "Invalid combjs output", + "The output from combjs is in an unexpected format, version missmatch?"); + exit(1); + return -1; /* unreachable (duh) */ +} diff -r 15293518d92b -r dd02002227a2 gui/combjs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui/combjs.h Thu Jul 14 15:40:20 2011 +0300 @@ -0,0 +1,16 @@ +#ifndef COMBJS_H_ +#define COMBJS_H_ + +#include +#include + +struct Joystick { + std::string dev; + std::string name; + int num_axes, num_bn; + bool isvirt; +}; + +int enum_joysticks(std::vector *jsvec); + +#endif /* COMBJS_H_ */ diff -r 15293518d92b -r dd02002227a2 gui/droplist.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui/droplist.cc Thu Jul 14 15:40:20 2011 +0300 @@ -0,0 +1,51 @@ +#include +#include +#include "droplist.h" + +DropList::DropList(QWidget *parent) + : QListWidget(parent) +{ + /*setDragEnabled(true); + viewport()->setAcceptDrops(true); + setDragDropMode(QAbstractItemView::DragDrop);*/ +} + +void DropList::dragMoveEvent(QDragMoveEvent *ev) +{ + printf("%s\n", __func__); + /*if(ev->source() == this) { + ev->ignore(); + return; + }*/ + + /* check if duplicate and then ... */ + ev->accept(); +} + +void DropList::dragEnterEvent(QDragEnterEvent *ev) +{ + printf("%s\n", __func__); + if(ev->source() == this) { + ev->setDropAction(Qt::MoveAction); + ev->accept(); + } else { + ev->acceptProposedAction(); + } +} + +void DropList::dropEvent(QDropEvent *ev) +{ + const QMimeData *mdata = ev->mimeData(); + if(mdata->hasText()) { + printf("%s: %s\n", __func__, mdata->text().toAscii().data()); + } else { + printf("%s\n", __func__); + } + + if(ev->source() == this) { + ev->setDropAction(Qt::MoveAction); + ev->accept(); + } else { + ev->acceptProposedAction(); + } +} diff -r 15293518d92b -r dd02002227a2 gui/droplist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui/droplist.h Thu Jul 14 15:40:20 2011 +0300 @@ -0,0 +1,18 @@ +#ifndef DROPLIST_H_ +#define DROPLIST_H_ + +#include + +/* a custom drop-target list for the virtual joystick creation */ +class DropList : public QListWidget { + Q_OBJECT +protected: + void dragMoveEvent(QDragMoveEvent *ev); + void dragEnterEvent(QDragEnterEvent *ev); + void dropEvent(QDropEvent *ev); + +public: + DropList(QWidget *parent); +}; + +#endif /* DROPLIST_H_ */ diff -r 15293518d92b -r dd02002227a2 gui/gui.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui/gui.cc Thu Jul 14 15:40:20 2011 +0300 @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include "gui.h" +#include "combjs.h" + +static std::vector jsvec; + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent) +{ + setupUi(this); + + int num_js = enum_joysticks(&jsvec); + + list_js->clear(); + for(int i=0; isetData(Qt::UserRole, i); + item->setToolTip(jsvec[i].dev.c_str()); + + list_js->addItem(item); + } + + connect(list_js, SIGNAL(itemSelectionChanged()), this, SLOT(jslist_select())); +} + + +void MainWindow::closeEvent(QCloseEvent *ev) +{ + /*const char *msg_text = "Are you sure you want to quit?\n" + "Quitting this application will destroy any virtual joystick devices you created!" + "If this wasn't your intention, press cancel and minimize instead of quitting."; + + if(QMessageBox::question(this, "Quit?", msg_text, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { + ev->accept(); + } else { + ev->ignore(); + }*/ + ev->accept(); +} + +/* slots */ +void MainWindow::jslist_select() +{ + QList sel_list = list_js->selectedItems(); + QListWidgetItem *item = sel_list.isEmpty() ? 0 : sel_list.first(); + + if(item && jsvec[item->data(Qt::UserRole).toInt()].isvirt) { + bn_del_virt->setEnabled(true); + } else { + bn_del_virt->setEnabled(false); + } +} diff -r 15293518d92b -r dd02002227a2 gui/gui.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui/gui.h Thu Jul 14 15:40:20 2011 +0300 @@ -0,0 +1,18 @@ +#ifndef GUI_H_ +#define GUI_H_ + +#include "ui_main.h" + +class MainWindow : public QMainWindow, private Ui::MainWindow { + Q_OBJECT +private slots: + void jslist_select(); + +private: + void closeEvent(QCloseEvent *ev); + +public: + MainWindow(QWidget *parent = 0); +}; + +#endif /* GUI_H_ */ diff -r 15293518d92b -r dd02002227a2 gui/main.ui --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui/main.ui Thu Jul 14 15:40:20 2011 +0300 @@ -0,0 +1,296 @@ + + + MainWindow + + + + 0 + 0 + 796 + 612 + + + + Joystick Combiner + + + + + + + Qt::Horizontal + + + + Qt::Vertical + + + + Joystick devices + + + + + + true + + + QAbstractItemView::DragDrop + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Delete virtual device + + + + + + + + + + New virtual device + + + + + + + + Name + + + + + + + + + + + + true + + + true + + + true + + + QAbstractItemView::DragDrop + + + Qt::CopyAction + + + false + + + 0 + + + + + + + + + false + + + Create + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Remove + + + + + + + + + + + Qt::Vertical + + + + + 0 + 0 + + + + + 0 + 347 + + + + Joystick information + + + + + + + + + + + 0 + 0 + + + + Joystick test + + + + + + true + + + + + 0 + 0 + 360 + 158 + + + + + + + + + + + + + + + + 0 + 0 + 796 + 24 + + + + + Joystick + + + + + + + + Help + + + + + + + + + + + Usage + + + + + About + + + + + Combine + + + + + Delete + + + + + Quit + + + + + + DropList + QListWidget +
droplist.h
+
+
+ + + + action_quit + triggered() + MainWindow + close() + + + -1 + -1 + + + 397 + 305 + + + + +