combjs

changeset 1:dd02002227a2

- added a few commandline arguments to combjs - trying to make a gui frontend
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 14 Jul 2011 15:40:20 +0300
parents 15293518d92b
children 4e8f2bbe8426
files Makefile combjs.c gui/Makefile gui/combjs-gui.cc gui/combjs.h gui/droplist.cc gui/droplist.h gui/gui.cc gui/gui.h gui/main.ui
diffstat 10 files changed, 733 insertions(+), 37 deletions(-) [+]
line diff
     1.1 --- a/Makefile	Wed Jul 13 07:12:57 2011 +0300
     1.2 +++ b/Makefile	Thu Jul 14 15:40:20 2011 +0300
     1.3 @@ -1,3 +1,5 @@
     1.4 +PREFIX = /usr/local
     1.5 +
     1.6  src = $(wildcard *.c)
     1.7  obj = $(src:.c=.o)
     1.8  bin = combjs
     1.9 @@ -11,3 +13,14 @@
    1.10  .PHONY: clean
    1.11  clean:
    1.12  	rm -f $(obj) $(bin)
    1.13 +
    1.14 +.PHONY: install
    1.15 +install: $(bin)
    1.16 +	mkdir -p $(PREFIX)/bin
    1.17 +	cp $(bin) $(PREFIX)/bin/$(bin)
    1.18 +	chown root $(PREFIX)/bin/$(bin)
    1.19 +	chmod 4775 $(PREFIX)/bin/$(bin)
    1.20 +
    1.21 +.PHONY: uninstall
    1.22 +uninstall:
    1.23 +	rm -f $(PREFIX)/bin/$(bin)
     2.1 --- a/combjs.c	Wed Jul 13 07:12:57 2011 +0300
     2.2 +++ b/combjs.c	Thu Jul 14 15:40:20 2011 +0300
     2.3 @@ -24,6 +24,7 @@
     2.4  #include <signal.h>
     2.5  #include <unistd.h>
     2.6  #include <fcntl.h>
     2.7 +#include <dirent.h>
     2.8  #include <sys/select.h>
     2.9  #include <sys/ioctl.h>
    2.10  #include <linux/joystick.h>
    2.11 @@ -33,6 +34,7 @@
    2.12  #define DBG_MAX_BN	32
    2.13  
    2.14  struct joystick {
    2.15 +	char *devfile;
    2.16  	char *name;
    2.17  	int fd;
    2.18  	int num_bn, num_axes;
    2.19 @@ -45,16 +47,22 @@
    2.20  int create_virt_js(const char *uinput_dev, const char *devname);
    2.21  int handle_event(struct joystick *js, struct js_event *ev);
    2.22  int add_joystick(const char *devfile);
    2.23 +struct joystick *open_joystick(const char *devfile);
    2.24 +void close_joystick(struct joystick *js);
    2.25 +void print_joystick(struct joystick *js, int verbose);
    2.26 +int list_devices(void);
    2.27 +int cmp_jsp(const void *a, const void *b);
    2.28  void sig_handler(int sig);
    2.29  int proc_cmdline(int argc, char **argv);
    2.30  void print_usage(const char *argv0);
    2.31  
    2.32  
    2.33  int vfd = -1;
    2.34 -const char *virt_dev_name = "combjs - virtual multi-joystick combiner";
    2.35 -const char *uinput_dev_name = "/dev/uinput";
    2.36 +const char *virt_name = "combjs - virtual multi-joystick combiner";
    2.37 +const char *uinput_dev = "/dev/uinput";
    2.38  struct joystick *jslist, *jstail;
    2.39  int num_vaxes, num_vbn;
    2.40 +int verbose = 1;
    2.41  
    2.42  
    2.43  int main(int argc, char **argv)
    2.44 @@ -67,11 +75,16 @@
    2.45  		return 1;
    2.46  	}
    2.47  
    2.48 -	if((vfd = create_virt_js(uinput_dev_name, virt_dev_name)) == -1) {
    2.49 +	if((vfd = create_virt_js(uinput_dev, virt_name)) == -1) {
    2.50  		cleanup();
    2.51  		return 1;
    2.52  	}
    2.53  
    2.54 +	/* if we where running suid-root, drop root priviledges */
    2.55 +	if(geteuid() == 0) {
    2.56 +		setuid(getuid());
    2.57 +	}
    2.58 +
    2.59  	for(;;) {
    2.60  		fd_set rdset;
    2.61  		struct joystick *js = jslist;
    2.62 @@ -207,35 +220,9 @@
    2.63  int add_joystick(const char *devfile)
    2.64  {
    2.65  	struct joystick *js;
    2.66 -	char buf[512];
    2.67  
    2.68 -	if(!(js = calloc(1, sizeof *js))) {
    2.69 -		perror("failed to allocate memory");
    2.70 -		goto err;
    2.71 -	}
    2.72 -
    2.73 -	if((js->fd = open(devfile, O_RDONLY | O_NONBLOCK)) == -1) {
    2.74 -		fprintf(stderr, "failed to open %s: %s\n", devfile, strerror(errno));
    2.75 -		goto err;
    2.76 -	}
    2.77 -
    2.78 -	if(ioctl(js->fd, JSIOCGNAME(sizeof buf), buf) == -1) {
    2.79 -		fprintf(stderr, "failed to get joystick name for %s: %s\n", devfile, strerror(errno));
    2.80 -		strcpy(buf, "<unknown>");
    2.81 -	}
    2.82 -	if(!(js->name = malloc(strlen(buf) + 1))) {
    2.83 -		perror("failed to allocate memory");
    2.84 -		goto err;
    2.85 -	}
    2.86 -	strcpy(js->name, buf);
    2.87 -
    2.88 -	if(ioctl(js->fd, JSIOCGBUTTONS, &js->num_bn) == -1) {
    2.89 -		fprintf(stderr, "failed to get joystick %s's number of buttons: %s\n", devfile, strerror(errno));
    2.90 -		goto err;
    2.91 -	}
    2.92 -	if(ioctl(js->fd, JSIOCGAXES, &js->num_axes) == -1) {
    2.93 -		fprintf(stderr, "failed to get joystick %s's number of axes: %s\n", devfile, strerror(errno));
    2.94 -		goto err;
    2.95 +	if(!(js = open_joystick(devfile))) {
    2.96 +		return -1;
    2.97  	}
    2.98  
    2.99  	if(!jstail) {
   2.100 @@ -250,18 +237,141 @@
   2.101  	num_vaxes = js->axis_offset + js->num_axes;
   2.102  	num_vbn = js->bn_offset + js->num_bn;
   2.103  
   2.104 -	printf("added joystick %s: %s\n", devfile, js->name);
   2.105 -	printf("  - %d axes (offset: %d)\n", js->num_axes, js->axis_offset);
   2.106 -	printf("  - %d buttons (offset: %d)\n", js->num_bn, js->bn_offset);
   2.107 +	if(verbose) {
   2.108 +		printf("added ");
   2.109 +		print_joystick(js, 1);
   2.110 +	}
   2.111  	return 0;
   2.112 +}
   2.113  
   2.114 -err:
   2.115 +struct joystick *open_joystick(const char *devfile)
   2.116 +{
   2.117 +	struct joystick *js;
   2.118 +	char buf[512];
   2.119 +
   2.120 +	if(!(js = calloc(1, sizeof *js))) {
   2.121 +		perror("failed to allocate memory");
   2.122 +		close_joystick(js);
   2.123 +		return 0;
   2.124 +	}
   2.125 +
   2.126 +	if(!(js->devfile = malloc(strlen(devfile) + 1))) {
   2.127 +		perror("failed to allocate memory");
   2.128 +		close_joystick(js);
   2.129 +		return 0;
   2.130 +	}
   2.131 +	strcpy(js->devfile, devfile);
   2.132 +
   2.133 +	if((js->fd = open(devfile, O_RDONLY | O_NONBLOCK)) == -1) {
   2.134 +		fprintf(stderr, "failed to open %s: %s\n", devfile, strerror(errno));
   2.135 +		close_joystick(js);
   2.136 +		return 0;
   2.137 +	}
   2.138 +
   2.139 +	if(ioctl(js->fd, JSIOCGNAME(sizeof buf), buf) == -1) {
   2.140 +		fprintf(stderr, "failed to get joystick name for %s: %s\n", devfile, strerror(errno));
   2.141 +		strcpy(buf, "<unknown>");
   2.142 +	}
   2.143 +	if(!(js->name = malloc(strlen(buf) + 1))) {
   2.144 +		perror("failed to allocate memory");
   2.145 +		close_joystick(js);
   2.146 +		return 0;
   2.147 +	}
   2.148 +	strcpy(js->name, buf);
   2.149 +
   2.150 +	if(ioctl(js->fd, JSIOCGBUTTONS, &js->num_bn) == -1) {
   2.151 +		fprintf(stderr, "failed to get joystick %s's number of buttons: %s\n", devfile, strerror(errno));
   2.152 +		close_joystick(js);
   2.153 +		return 0;
   2.154 +	}
   2.155 +	if(ioctl(js->fd, JSIOCGAXES, &js->num_axes) == -1) {
   2.156 +		fprintf(stderr, "failed to get joystick %s's number of axes: %s\n", devfile, strerror(errno));
   2.157 +		close_joystick(js);
   2.158 +		return 0;
   2.159 +	}
   2.160 +	return js;
   2.161 +}
   2.162 +
   2.163 +void close_joystick(struct joystick *js)
   2.164 +{
   2.165  	if(js) {
   2.166  		close(js->fd);
   2.167  		free(js->name);
   2.168  		free(js);
   2.169  	}
   2.170 -	return -1;
   2.171 +}
   2.172 +
   2.173 +void print_joystick(struct joystick *js, int verbose)
   2.174 +{
   2.175 +	if(verbose) {
   2.176 +		printf("joystick %s: %s\n", js->devfile, js->name);
   2.177 +		printf("  - %d axes (offset: %d)\n", js->num_axes, js->axis_offset);
   2.178 +		printf("  - %d buttons (offset: %d)\n", js->num_bn, js->bn_offset);
   2.179 +	} else {
   2.180 +		printf("%s: \"%s\", axes: %d, buttons: %d\n", js->devfile, js->name, js->num_axes, js->num_bn);
   2.181 +	}
   2.182 +}
   2.183 +
   2.184 +int list_devices(void)
   2.185 +{
   2.186 +	DIR *dir;
   2.187 +	struct dirent *dent;
   2.188 +	char buf[PATH_MAX];
   2.189 +	struct joystick **jsp_arr, *js;
   2.190 +	int i, num_js = 0;
   2.191 +
   2.192 +	/* we don't need root priviledges for this */
   2.193 +	if(geteuid() == 0) {
   2.194 +		setuid(getuid());
   2.195 +	}
   2.196 +
   2.197 +	if(!(dir = opendir("/dev/input"))) {
   2.198 +		perror("failed to open /dev/input");
   2.199 +		return -1;
   2.200 +	}
   2.201 +
   2.202 +	while((dent = readdir(dir))) {
   2.203 +		if(strstr(dent->d_name, "js") == dent->d_name) {
   2.204 +			sprintf(buf, "/dev/input/%s", dent->d_name);
   2.205 +
   2.206 +			if(!(js = open_joystick(buf))) {
   2.207 +				continue;
   2.208 +			}
   2.209 +
   2.210 +			if(jslist) {
   2.211 +				js->next = jslist;
   2.212 +			}
   2.213 +			jslist = js;
   2.214 +			num_js++;
   2.215 +		}
   2.216 +	}
   2.217 +	closedir(dir);
   2.218 +
   2.219 +	if(!(jsp_arr = malloc(num_js * sizeof *jsp_arr))) {
   2.220 +		perror("failed to allocate memory");
   2.221 +		return -1;
   2.222 +	}
   2.223 +
   2.224 +	js = jslist;
   2.225 +	for(i=0; i<num_js; i++) {
   2.226 +		jsp_arr[i] = js;
   2.227 +		js = js->next;
   2.228 +	}
   2.229 +
   2.230 +	qsort(jsp_arr, num_js, sizeof *jsp_arr, cmp_jsp);
   2.231 +
   2.232 +	for(i=0; i<num_js; i++) {
   2.233 +		print_joystick(jsp_arr[i], 0);
   2.234 +		close_joystick(jsp_arr[i]);
   2.235 +	}
   2.236 +	free(jsp_arr);
   2.237 +
   2.238 +	return 0;
   2.239 +}
   2.240 +
   2.241 +int cmp_jsp(const void *a, const void *b)
   2.242 +{
   2.243 +	return strcmp((*(struct joystick**)a)->devfile, (*(struct joystick**)b)->devfile);
   2.244  }
   2.245  
   2.246  void sig_handler(int sig)
   2.247 @@ -278,6 +388,24 @@
   2.248  		if(argv[i][0] == '-') {
   2.249  			if(argv[i][2] == 0) {
   2.250  				switch(argv[i][1]) {
   2.251 +				case 'd':
   2.252 +					uinput_dev = argv[++i];
   2.253 +					break;
   2.254 +
   2.255 +				case 'n':
   2.256 +					virt_name = argv[++i];
   2.257 +					break;
   2.258 +
   2.259 +				case 'l':
   2.260 +					if(list_devices() == -1) {
   2.261 +						exit(1);
   2.262 +					}
   2.263 +					exit(0);
   2.264 +
   2.265 +				case 's':
   2.266 +					verbose = 0;
   2.267 +					break;
   2.268 +
   2.269  				case 'h':
   2.270  					print_usage(argv[0]);
   2.271  					exit(0);
   2.272 @@ -309,5 +437,11 @@
   2.273  
   2.274  void print_usage(const char *argv0)
   2.275  {
   2.276 -	printf("usage: %s <dev 0> [dev1] ... [dev n]\n", argv0);
   2.277 +	printf("usage: %s [options] <dev 0> [dev1] ... [dev n]\n", argv0);
   2.278 +	printf("options:\n");
   2.279 +	printf("  -d: uinput device file (default: /dev/uinput)\n");
   2.280 +	printf("  -n: name for the virtual combined joystick\n");
   2.281 +	printf("  -s: silent (reduces verbosity)\n");
   2.282 +	printf("  -l: print a list of all the joystick devices and exit\n");
   2.283 +	printf("  -h: print usage information and exit\n");
   2.284  }
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/gui/Makefile	Thu Jul 14 15:40:20 2011 +0300
     3.3 @@ -0,0 +1,29 @@
     3.4 +src = $(wildcard *.cc) moc_gui.cc moc_droplist.cc
     3.5 +obj = $(src:.cc=.o)
     3.6 +dep = $(obj:.o=.d)
     3.7 +bin = combjs-gui
     3.8 +
     3.9 +uihdr = ui_main.h
    3.10 +
    3.11 +CXX = g++
    3.12 +CXXFLAGS = -Wall -g `pkg-config --cflags QtGui QtDesigner`
    3.13 +LDFLAGS = `pkg-config --libs QtGui QtDesigner`
    3.14 +MOC = moc
    3.15 +UIC = uic
    3.16 +
    3.17 +$(bin): $(uihdr) $(obj)
    3.18 +	$(CXX) -o $@ $(obj) $(LDFLAGS)
    3.19 +
    3.20 +moc_%.cc: %.h
    3.21 +	moc -o $@ $<
    3.22 +
    3.23 +ui_%.h: %.ui
    3.24 +	uic -o $@ $<
    3.25 +
    3.26 +.PHONY: clean
    3.27 +clean:
    3.28 +	rm -f $(obj) $(bin) ui_*.h moc_*.cc
    3.29 +
    3.30 +.PHONY: cleandep
    3.31 +cleandep:
    3.32 +	rm -f $(dep)
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/gui/combjs-gui.cc	Thu Jul 14 15:40:20 2011 +0300
     4.3 @@ -0,0 +1,66 @@
     4.4 +#include <stdio.h>
     4.5 +#include <QApplication>
     4.6 +#include <QMessageBox>
     4.7 +#include "combjs.h"
     4.8 +#include "gui.h"
     4.9 +
    4.10 +MainWindow *main_win;
    4.11 +
    4.12 +int main(int argc, char **argv)
    4.13 +{
    4.14 +	QApplication app(argc, argv);
    4.15 +
    4.16 +	main_win = new MainWindow;
    4.17 +	main_win->show();
    4.18 +
    4.19 +	return app.exec();
    4.20 +}
    4.21 +
    4.22 +int enum_joysticks(std::vector<Joystick> *jsvec)
    4.23 +{
    4.24 +	jsvec->clear();
    4.25 +
    4.26 +	FILE *pipe = popen("combjs -l", "r");
    4.27 +	if(!pipe) {
    4.28 +		QMessageBox::critical(main_win, "Critical error",
    4.29 +				"Failed to execute combjs, make sure it's installed in the path.");
    4.30 +		exit(1);
    4.31 +	}
    4.32 +
    4.33 +	char line[512];
    4.34 +	while(fgets(line, sizeof line, pipe)) {
    4.35 +		Joystick js;
    4.36 +		char *ptr, *end;
    4.37 +
    4.38 +		if(!(ptr = strchr(line, ':'))) {
    4.39 +			goto inval;
    4.40 +		}
    4.41 +		*ptr++ = 0;
    4.42 +
    4.43 +		js.dev = line;
    4.44 +
    4.45 +		if(!(ptr = strchr(ptr, '"')) || !(end = strchr(ptr + 1, '"'))) {
    4.46 +			goto inval;
    4.47 +		}
    4.48 +		*end = 0;
    4.49 +
    4.50 +		js.name = ptr + 1;
    4.51 +		ptr = end + 1;
    4.52 +
    4.53 +		if(sscanf(ptr, ", axes: %d, buttons: %d", &js.num_axes, &js.num_bn) != 2) {
    4.54 +			goto inval;
    4.55 +		}
    4.56 +
    4.57 +		js.isvirt = false;
    4.58 +		jsvec->push_back(js);
    4.59 +	}
    4.60 +	pclose(pipe);
    4.61 +
    4.62 +	return jsvec->size();
    4.63 +
    4.64 +inval:
    4.65 +	QMessageBox::critical(main_win, "Invalid combjs output",
    4.66 +			"The output from combjs is in an unexpected format, version missmatch?");
    4.67 +	exit(1);
    4.68 +	return -1;	/* unreachable (duh) */
    4.69 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/gui/combjs.h	Thu Jul 14 15:40:20 2011 +0300
     5.3 @@ -0,0 +1,16 @@
     5.4 +#ifndef COMBJS_H_
     5.5 +#define COMBJS_H_
     5.6 +
     5.7 +#include <vector>
     5.8 +#include <string>
     5.9 +
    5.10 +struct Joystick {
    5.11 +	std::string dev;
    5.12 +	std::string name;
    5.13 +	int num_axes, num_bn;
    5.14 +	bool isvirt;
    5.15 +};
    5.16 +
    5.17 +int enum_joysticks(std::vector<Joystick> *jsvec);
    5.18 +
    5.19 +#endif	/* COMBJS_H_ */
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/gui/droplist.cc	Thu Jul 14 15:40:20 2011 +0300
     6.3 @@ -0,0 +1,51 @@
     6.4 +#include <stdio.h>
     6.5 +#include <QDragMoveEvent>
     6.6 +#include "droplist.h"
     6.7 +
     6.8 +DropList::DropList(QWidget *parent)
     6.9 +	: QListWidget(parent)
    6.10 +{
    6.11 +	/*setDragEnabled(true);
    6.12 +	viewport()->setAcceptDrops(true);
    6.13 +	setDragDropMode(QAbstractItemView::DragDrop);*/
    6.14 +}
    6.15 +
    6.16 +void DropList::dragMoveEvent(QDragMoveEvent *ev)
    6.17 +{
    6.18 +	printf("%s\n", __func__);
    6.19 +	/*if(ev->source() == this) {
    6.20 +		ev->ignore();
    6.21 +		return;
    6.22 +	}*/
    6.23 +
    6.24 +	/* check if duplicate and then ... */
    6.25 +	ev->accept();
    6.26 +}
    6.27 +
    6.28 +void DropList::dragEnterEvent(QDragEnterEvent *ev)
    6.29 +{
    6.30 +	printf("%s\n", __func__);
    6.31 +	if(ev->source() == this) {
    6.32 +		ev->setDropAction(Qt::MoveAction);
    6.33 +		ev->accept();
    6.34 +	} else {
    6.35 +		ev->acceptProposedAction();
    6.36 +	}
    6.37 +}
    6.38 +
    6.39 +void DropList::dropEvent(QDropEvent *ev)
    6.40 +{
    6.41 +	const QMimeData *mdata = ev->mimeData();
    6.42 +	if(mdata->hasText()) {
    6.43 +		printf("%s: %s\n", __func__, mdata->text().toAscii().data());
    6.44 +	} else {
    6.45 +		printf("%s\n", __func__);
    6.46 +	}
    6.47 +
    6.48 +	if(ev->source() == this) {
    6.49 +		ev->setDropAction(Qt::MoveAction);
    6.50 +		ev->accept();
    6.51 +	} else {
    6.52 +		ev->acceptProposedAction();
    6.53 +	}
    6.54 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/gui/droplist.h	Thu Jul 14 15:40:20 2011 +0300
     7.3 @@ -0,0 +1,18 @@
     7.4 +#ifndef DROPLIST_H_
     7.5 +#define DROPLIST_H_
     7.6 +
     7.7 +#include <QListWidget>
     7.8 +
     7.9 +/* a custom drop-target list for the virtual joystick creation */
    7.10 +class DropList : public QListWidget {
    7.11 +	Q_OBJECT
    7.12 +protected:
    7.13 +	void dragMoveEvent(QDragMoveEvent *ev);
    7.14 +	void dragEnterEvent(QDragEnterEvent *ev);
    7.15 +	void dropEvent(QDropEvent *ev);
    7.16 +
    7.17 +public:
    7.18 +	DropList(QWidget *parent);
    7.19 +};
    7.20 +
    7.21 +#endif	/* DROPLIST_H_ */
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/gui/gui.cc	Thu Jul 14 15:40:20 2011 +0300
     8.3 @@ -0,0 +1,55 @@
     8.4 +#include <stdio.h>
     8.5 +#include <stdlib.h>
     8.6 +#include <QMessageBox>
     8.7 +#include <QCloseEvent>
     8.8 +#include "gui.h"
     8.9 +#include "combjs.h"
    8.10 +
    8.11 +static std::vector<Joystick> jsvec;
    8.12 +
    8.13 +MainWindow::MainWindow(QWidget *parent)
    8.14 +	: QMainWindow(parent)
    8.15 +{
    8.16 +	setupUi(this);
    8.17 +
    8.18 +	int num_js = enum_joysticks(&jsvec);
    8.19 +
    8.20 +	list_js->clear();
    8.21 +	for(int i=0; i<num_js; i++) {
    8.22 +		QListWidgetItem *item = new QListWidgetItem(jsvec[i].name.c_str());
    8.23 +		item->setData(Qt::UserRole, i);
    8.24 +		item->setToolTip(jsvec[i].dev.c_str());
    8.25 +
    8.26 +		list_js->addItem(item);
    8.27 +	}
    8.28 +
    8.29 +	connect(list_js, SIGNAL(itemSelectionChanged()), this, SLOT(jslist_select()));
    8.30 +}
    8.31 +
    8.32 +
    8.33 +void MainWindow::closeEvent(QCloseEvent *ev)
    8.34 +{
    8.35 +	/*const char *msg_text = "Are you sure you want to quit?\n"
    8.36 +		"Quitting this application will destroy any virtual joystick devices you created!"
    8.37 +		"If this wasn't your intention, press cancel and minimize instead of quitting.";
    8.38 +
    8.39 +	if(QMessageBox::question(this, "Quit?", msg_text, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
    8.40 +		ev->accept();
    8.41 +	} else {
    8.42 +		ev->ignore();
    8.43 +	}*/
    8.44 +	ev->accept();
    8.45 +}
    8.46 +
    8.47 +/* slots */
    8.48 +void MainWindow::jslist_select()
    8.49 +{
    8.50 +	QList<QListWidgetItem*> sel_list = list_js->selectedItems();
    8.51 +	QListWidgetItem *item = sel_list.isEmpty() ? 0 : sel_list.first();
    8.52 +
    8.53 +	if(item && jsvec[item->data(Qt::UserRole).toInt()].isvirt) {
    8.54 +		bn_del_virt->setEnabled(true);
    8.55 +	} else {
    8.56 +		bn_del_virt->setEnabled(false);
    8.57 +	}
    8.58 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/gui/gui.h	Thu Jul 14 15:40:20 2011 +0300
     9.3 @@ -0,0 +1,18 @@
     9.4 +#ifndef GUI_H_
     9.5 +#define GUI_H_
     9.6 +
     9.7 +#include "ui_main.h"
     9.8 +
     9.9 +class MainWindow : public QMainWindow, private Ui::MainWindow {
    9.10 +	Q_OBJECT
    9.11 +private slots:
    9.12 +	void jslist_select();
    9.13 +
    9.14 +private:
    9.15 +	void closeEvent(QCloseEvent *ev);
    9.16 +
    9.17 +public:
    9.18 +	MainWindow(QWidget *parent = 0);
    9.19 +};
    9.20 +
    9.21 +#endif	/* GUI_H_ */
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/gui/main.ui	Thu Jul 14 15:40:20 2011 +0300
    10.3 @@ -0,0 +1,296 @@
    10.4 +<?xml version="1.0" encoding="UTF-8"?>
    10.5 +<ui version="4.0">
    10.6 + <class>MainWindow</class>
    10.7 + <widget class="QMainWindow" name="MainWindow">
    10.8 +  <property name="geometry">
    10.9 +   <rect>
   10.10 +    <x>0</x>
   10.11 +    <y>0</y>
   10.12 +    <width>796</width>
   10.13 +    <height>612</height>
   10.14 +   </rect>
   10.15 +  </property>
   10.16 +  <property name="windowTitle">
   10.17 +   <string>Joystick Combiner</string>
   10.18 +  </property>
   10.19 +  <widget class="QWidget" name="centralwidget">
   10.20 +   <layout class="QVBoxLayout" name="verticalLayout_4">
   10.21 +    <item>
   10.22 +     <widget class="QSplitter" name="splitter_3">
   10.23 +      <property name="orientation">
   10.24 +       <enum>Qt::Horizontal</enum>
   10.25 +      </property>
   10.26 +      <widget class="QSplitter" name="splitter_2">
   10.27 +       <property name="orientation">
   10.28 +        <enum>Qt::Vertical</enum>
   10.29 +       </property>
   10.30 +       <widget class="QGroupBox" name="groupBox">
   10.31 +        <property name="title">
   10.32 +         <string>Joystick devices</string>
   10.33 +        </property>
   10.34 +        <layout class="QVBoxLayout" name="verticalLayout_3">
   10.35 +         <item>
   10.36 +          <widget class="QListWidget" name="list_js">
   10.37 +           <property name="dragEnabled">
   10.38 +            <bool>true</bool>
   10.39 +           </property>
   10.40 +           <property name="dragDropMode">
   10.41 +            <enum>QAbstractItemView::DragDrop</enum>
   10.42 +           </property>
   10.43 +          </widget>
   10.44 +         </item>
   10.45 +         <item>
   10.46 +          <layout class="QHBoxLayout" name="horizontalLayout_3">
   10.47 +           <item>
   10.48 +            <spacer name="horizontalSpacer_2">
   10.49 +             <property name="orientation">
   10.50 +              <enum>Qt::Horizontal</enum>
   10.51 +             </property>
   10.52 +             <property name="sizeHint" stdset="0">
   10.53 +              <size>
   10.54 +               <width>40</width>
   10.55 +               <height>20</height>
   10.56 +              </size>
   10.57 +             </property>
   10.58 +            </spacer>
   10.59 +           </item>
   10.60 +           <item>
   10.61 +            <widget class="QPushButton" name="bn_del_virt">
   10.62 +             <property name="enabled">
   10.63 +              <bool>false</bool>
   10.64 +             </property>
   10.65 +             <property name="text">
   10.66 +              <string>Delete virtual device</string>
   10.67 +             </property>
   10.68 +            </widget>
   10.69 +           </item>
   10.70 +          </layout>
   10.71 +         </item>
   10.72 +        </layout>
   10.73 +       </widget>
   10.74 +       <widget class="QGroupBox" name="groupBox_2">
   10.75 +        <property name="title">
   10.76 +         <string>New virtual device</string>
   10.77 +        </property>
   10.78 +        <layout class="QVBoxLayout" name="verticalLayout_2">
   10.79 +         <item>
   10.80 +          <layout class="QHBoxLayout" name="horizontalLayout">
   10.81 +           <item>
   10.82 +            <widget class="QLabel" name="label">
   10.83 +             <property name="text">
   10.84 +              <string>Name</string>
   10.85 +             </property>
   10.86 +            </widget>
   10.87 +           </item>
   10.88 +           <item>
   10.89 +            <widget class="QLineEdit" name="tx_devname"/>
   10.90 +           </item>
   10.91 +          </layout>
   10.92 +         </item>
   10.93 +         <item>
   10.94 +          <widget class="DropList" name="list_newdev">
   10.95 +           <property name="acceptDrops">
   10.96 +            <bool>true</bool>
   10.97 +           </property>
   10.98 +           <property name="dragEnabled">
   10.99 +            <bool>true</bool>
  10.100 +           </property>
  10.101 +           <property name="dragDropOverwriteMode">
  10.102 +            <bool>true</bool>
  10.103 +           </property>
  10.104 +           <property name="dragDropMode">
  10.105 +            <enum>QAbstractItemView::DragDrop</enum>
  10.106 +           </property>
  10.107 +           <property name="defaultDropAction">
  10.108 +            <enum>Qt::CopyAction</enum>
  10.109 +           </property>
  10.110 +           <property name="alternatingRowColors">
  10.111 +            <bool>false</bool>
  10.112 +           </property>
  10.113 +           <property name="modelColumn">
  10.114 +            <number>0</number>
  10.115 +           </property>
  10.116 +          </widget>
  10.117 +         </item>
  10.118 +         <item>
  10.119 +          <layout class="QHBoxLayout" name="horizontalLayout_2">
  10.120 +           <item>
  10.121 +            <widget class="QPushButton" name="pushButton_3">
  10.122 +             <property name="enabled">
  10.123 +              <bool>false</bool>
  10.124 +             </property>
  10.125 +             <property name="text">
  10.126 +              <string>Create</string>
  10.127 +             </property>
  10.128 +            </widget>
  10.129 +           </item>
  10.130 +           <item>
  10.131 +            <spacer name="horizontalSpacer">
  10.132 +             <property name="orientation">
  10.133 +              <enum>Qt::Horizontal</enum>
  10.134 +             </property>
  10.135 +             <property name="sizeHint" stdset="0">
  10.136 +              <size>
  10.137 +               <width>40</width>
  10.138 +               <height>20</height>
  10.139 +              </size>
  10.140 +             </property>
  10.141 +            </spacer>
  10.142 +           </item>
  10.143 +           <item>
  10.144 +            <widget class="QPushButton" name="pushButton_2">
  10.145 +             <property name="enabled">
  10.146 +              <bool>false</bool>
  10.147 +             </property>
  10.148 +             <property name="text">
  10.149 +              <string>Remove</string>
  10.150 +             </property>
  10.151 +            </widget>
  10.152 +           </item>
  10.153 +          </layout>
  10.154 +         </item>
  10.155 +        </layout>
  10.156 +       </widget>
  10.157 +      </widget>
  10.158 +      <widget class="QSplitter" name="splitter">
  10.159 +       <property name="orientation">
  10.160 +        <enum>Qt::Vertical</enum>
  10.161 +       </property>
  10.162 +       <widget class="QGroupBox" name="groupBox_3">
  10.163 +        <property name="sizePolicy">
  10.164 +         <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
  10.165 +          <horstretch>0</horstretch>
  10.166 +          <verstretch>0</verstretch>
  10.167 +         </sizepolicy>
  10.168 +        </property>
  10.169 +        <property name="minimumSize">
  10.170 +         <size>
  10.171 +          <width>0</width>
  10.172 +          <height>347</height>
  10.173 +         </size>
  10.174 +        </property>
  10.175 +        <property name="title">
  10.176 +         <string>Joystick information</string>
  10.177 +        </property>
  10.178 +        <layout class="QVBoxLayout" name="verticalLayout">
  10.179 +         <item>
  10.180 +          <widget class="QListWidget" name="list_joyinfo"/>
  10.181 +         </item>
  10.182 +        </layout>
  10.183 +       </widget>
  10.184 +       <widget class="QGroupBox" name="groupBox_4">
  10.185 +        <property name="sizePolicy">
  10.186 +         <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
  10.187 +          <horstretch>0</horstretch>
  10.188 +          <verstretch>0</verstretch>
  10.189 +         </sizepolicy>
  10.190 +        </property>
  10.191 +        <property name="title">
  10.192 +         <string>Joystick test</string>
  10.193 +        </property>
  10.194 +        <layout class="QVBoxLayout" name="verticalLayout_5">
  10.195 +         <item>
  10.196 +          <widget class="QScrollArea" name="test_area">
  10.197 +           <property name="widgetResizable">
  10.198 +            <bool>true</bool>
  10.199 +           </property>
  10.200 +           <widget class="QWidget" name="scrollAreaWidgetContents">
  10.201 +            <property name="geometry">
  10.202 +             <rect>
  10.203 +              <x>0</x>
  10.204 +              <y>0</y>
  10.205 +              <width>360</width>
  10.206 +              <height>158</height>
  10.207 +             </rect>
  10.208 +            </property>
  10.209 +           </widget>
  10.210 +          </widget>
  10.211 +         </item>
  10.212 +        </layout>
  10.213 +       </widget>
  10.214 +      </widget>
  10.215 +     </widget>
  10.216 +    </item>
  10.217 +   </layout>
  10.218 +  </widget>
  10.219 +  <widget class="QMenuBar" name="menubar">
  10.220 +   <property name="geometry">
  10.221 +    <rect>
  10.222 +     <x>0</x>
  10.223 +     <y>0</y>
  10.224 +     <width>796</width>
  10.225 +     <height>24</height>
  10.226 +    </rect>
  10.227 +   </property>
  10.228 +   <widget class="QMenu" name="menuFile">
  10.229 +    <property name="title">
  10.230 +     <string>Joystick</string>
  10.231 +    </property>
  10.232 +    <addaction name="action_combine"/>
  10.233 +    <addaction name="action_delete"/>
  10.234 +    <addaction name="action_quit"/>
  10.235 +   </widget>
  10.236 +   <widget class="QMenu" name="menuHelp">
  10.237 +    <property name="title">
  10.238 +     <string>Help</string>
  10.239 +    </property>
  10.240 +    <addaction name="action_usage"/>
  10.241 +    <addaction name="action_about"/>
  10.242 +   </widget>
  10.243 +   <addaction name="menuFile"/>
  10.244 +   <addaction name="menuHelp"/>
  10.245 +  </widget>
  10.246 +  <widget class="QStatusBar" name="statusbar"/>
  10.247 +  <action name="action_usage">
  10.248 +   <property name="text">
  10.249 +    <string>Usage</string>
  10.250 +   </property>
  10.251 +  </action>
  10.252 +  <action name="action_about">
  10.253 +   <property name="text">
  10.254 +    <string>About</string>
  10.255 +   </property>
  10.256 +  </action>
  10.257 +  <action name="action_combine">
  10.258 +   <property name="text">
  10.259 +    <string>Combine</string>
  10.260 +   </property>
  10.261 +  </action>
  10.262 +  <action name="action_delete">
  10.263 +   <property name="text">
  10.264 +    <string>Delete</string>
  10.265 +   </property>
  10.266 +  </action>
  10.267 +  <action name="action_quit">
  10.268 +   <property name="text">
  10.269 +    <string>Quit</string>
  10.270 +   </property>
  10.271 +  </action>
  10.272 + </widget>
  10.273 + <customwidgets>
  10.274 +  <customwidget>
  10.275 +   <class>DropList</class>
  10.276 +   <extends>QListWidget</extends>
  10.277 +   <header>droplist.h</header>
  10.278 +  </customwidget>
  10.279 + </customwidgets>
  10.280 + <resources/>
  10.281 + <connections>
  10.282 +  <connection>
  10.283 +   <sender>action_quit</sender>
  10.284 +   <signal>triggered()</signal>
  10.285 +   <receiver>MainWindow</receiver>
  10.286 +   <slot>close()</slot>
  10.287 +   <hints>
  10.288 +    <hint type="sourcelabel">
  10.289 +     <x>-1</x>
  10.290 +     <y>-1</y>
  10.291 +    </hint>
  10.292 +    <hint type="destinationlabel">
  10.293 +     <x>397</x>
  10.294 +     <y>305</y>
  10.295 +    </hint>
  10.296 +   </hints>
  10.297 +  </connection>
  10.298 + </connections>
  10.299 +</ui>