kopia lustrzana https://github.com/FreeSpacenav/spacenavd
merged Ralf Morel's patch for multiple device support
git-svn-id: svn+ssh://svn.code.sf.net/p/spacenav/code/trunk/spacenavd@152 ef983eb1-d774-4af8-acfd-baaf7b16a646pull/1/head
rodzic
18b7357753
commit
a3721ea87d
56
src/client.c
56
src/client.c
|
@ -35,24 +35,14 @@ struct client {
|
|||
#endif
|
||||
|
||||
float sens; /* sensitivity */
|
||||
int dev_idx; /* device index */
|
||||
|
||||
struct client *next;
|
||||
};
|
||||
|
||||
|
||||
static struct client *client_list;
|
||||
static struct client *citer; /* iterator (used by first/next calls) */
|
||||
|
||||
int init_clients(void)
|
||||
{
|
||||
if(!(client_list = malloc(sizeof *client_list))) {
|
||||
perror("failed to allocate client list");
|
||||
return -1;
|
||||
}
|
||||
client_list->next = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct client *client_list = NULL;
|
||||
static struct client *client_iter; /* iterator (used by first/next calls) */
|
||||
|
||||
/* add a client to the list
|
||||
* cdata points to the socket fd for new-protocol clients, or the
|
||||
|
@ -63,9 +53,9 @@ struct client *add_client(int type, void *cdata)
|
|||
struct client *client;
|
||||
|
||||
#ifdef USE_X11
|
||||
if(!cdata || (type != CLIENT_UNIX && type != CLIENT_X11))
|
||||
if(!cdata || (type != CLIENT_UNIX && type != CLIENT_X11))
|
||||
#else
|
||||
if(!cdata || type != CLIENT_UNIX)
|
||||
if(!cdata || type != CLIENT_UNIX)
|
||||
#endif
|
||||
{
|
||||
return 0;
|
||||
|
@ -85,8 +75,14 @@ struct client *add_client(int type, void *cdata)
|
|||
}
|
||||
|
||||
client->sens = 1.0f;
|
||||
client->next = client_list->next;
|
||||
client_list->next = client;
|
||||
client->dev_idx = 0; /* default/first device */
|
||||
|
||||
if(client_list == NULL) {
|
||||
client->next = NULL;
|
||||
return (client_list = client);
|
||||
}
|
||||
client->next = client_list;
|
||||
client_list = client;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
@ -95,6 +91,15 @@ void remove_client(struct client *client)
|
|||
{
|
||||
struct client *iter = client_list;
|
||||
|
||||
if(iter == NULL)
|
||||
return;
|
||||
if(iter == client) {
|
||||
client_list = iter->next;
|
||||
free(iter);
|
||||
if((iter = client_list) == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
while(iter->next) {
|
||||
if(iter->next == client) {
|
||||
struct client *tmp = iter->next;
|
||||
|
@ -133,13 +138,24 @@ float get_client_sensitivity(struct client *client)
|
|||
return client->sens;
|
||||
}
|
||||
|
||||
void set_client_device_index(struct client *client, int dev_idx)
|
||||
{
|
||||
client->dev_idx = dev_idx;
|
||||
}
|
||||
|
||||
int get_client_device_index(struct client *client)
|
||||
{
|
||||
return client->dev_idx;
|
||||
}
|
||||
|
||||
struct client *first_client(void)
|
||||
{
|
||||
return citer = client_list->next;
|
||||
return (client_iter = client_list);
|
||||
}
|
||||
|
||||
struct client *next_client(void)
|
||||
{
|
||||
citer = citer->next;
|
||||
return citer;
|
||||
if(client_iter)
|
||||
client_iter = client_iter->next;
|
||||
return client_iter;
|
||||
}
|
||||
|
|
|
@ -34,8 +34,6 @@ enum {
|
|||
|
||||
struct client;
|
||||
|
||||
int init_clients(void);
|
||||
|
||||
struct client *add_client(int type, void *cdata);
|
||||
void remove_client(struct client *client);
|
||||
|
||||
|
@ -48,6 +46,9 @@ Window get_client_window(struct client *client);
|
|||
void set_client_sensitivity(struct client *client, float sens);
|
||||
float get_client_sensitivity(struct client *client);
|
||||
|
||||
void set_client_device_index(struct client *client, int dev_idx);
|
||||
int get_client_device_index(struct client *client);
|
||||
|
||||
/* these two can be used to iterate over all clients */
|
||||
struct client *first_client(void);
|
||||
struct client *next_client(void);
|
||||
|
|
189
src/dev.c
189
src/dev.c
|
@ -18,67 +18,192 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "dev.h"
|
||||
#include "dev_usb.h"
|
||||
#include "dev_serial.h"
|
||||
#include "event.h" /* remove pending events upon device removal */
|
||||
#include "spnavd.h"
|
||||
|
||||
static struct device dev = {-1, 0};
|
||||
static struct device *add_device(void);
|
||||
static struct device *dev_path_in_use(char const * dev_path);
|
||||
|
||||
int init_dev(void)
|
||||
static struct device *dev_list = NULL;
|
||||
static struct device *dev_iter;
|
||||
|
||||
int init_devices(void)
|
||||
{
|
||||
if(dev.fd != -1) {
|
||||
fprintf(stderr, "init_dev called, but device is already open\n");
|
||||
return -1;
|
||||
struct device *dev_cur;
|
||||
int i, device_added = 0;
|
||||
char **dev_path;
|
||||
|
||||
/* try to open a serial device if specified in the config file */
|
||||
if(cfg.serial_dev[0]) {
|
||||
if(!dev_path_in_use(cfg.serial_dev)) {
|
||||
dev_cur = add_device();
|
||||
strcpy(dev_cur->path, cfg.serial_dev);
|
||||
if(open_dev_serial(dev_cur) == -1) {
|
||||
remove_device(dev_cur);
|
||||
} else {
|
||||
strcpy(dev_cur->name, "serial device");
|
||||
printf("using device: %s\n", cfg.serial_dev);
|
||||
device_added++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(cfg.serial_dev[0]) {
|
||||
/* try to open a serial device if specified in the config file */
|
||||
printf("using device: %s\n", cfg.serial_dev);
|
||||
dev_path = malloc(MAX_DEVICES * sizeof(char *));
|
||||
for(i=0; i<MAX_DEVICES; i++) {
|
||||
dev_path[i] = malloc(PATH_MAX);
|
||||
}
|
||||
|
||||
if(open_dev_serial(&dev, cfg.serial_dev) == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
const char *dev_path;
|
||||
find_usb_devices(dev_path, MAX_DEVICES, PATH_MAX);
|
||||
if(!dev_path[0][0] && !cfg.serial_dev[0]) {
|
||||
fprintf(stderr, "failed to find the any spaceball device files\n");
|
||||
}
|
||||
|
||||
if(!(dev_path = find_usb_device())) {
|
||||
fprintf(stderr, "failed to find the spaceball device file\n");
|
||||
return -1;
|
||||
for(i=0; i<MAX_DEVICES; i++) {
|
||||
if(dev_path[i][0] == 0)
|
||||
break;
|
||||
if(dev_path_in_use(dev_path[i]) != NULL) {
|
||||
if(verbose) {
|
||||
fprintf(stderr, "already using device at: %s\n", dev_path[i]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
printf("using device: %s\n", dev_path);
|
||||
dev_cur = add_device();
|
||||
strcpy(dev_cur->path, dev_path[i]);
|
||||
if(open_dev_usb(dev_cur) == -1) {
|
||||
remove_device(dev_cur);
|
||||
} else {
|
||||
printf("using device: %s\n", dev_path[i]);
|
||||
device_added++;
|
||||
}
|
||||
}
|
||||
|
||||
if(open_dev_usb(&dev, dev_path) == -1) {
|
||||
return -1;
|
||||
}
|
||||
for(i=0; i<8; i++) {
|
||||
free(dev_path[i]);
|
||||
}
|
||||
free(dev_path);
|
||||
|
||||
if(!device_added) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void shutdown_dev(void)
|
||||
static struct device *add_device(void)
|
||||
{
|
||||
if(dev.close) {
|
||||
dev.close(&dev);
|
||||
struct device *dev_new, *iter;
|
||||
|
||||
if((dev_new = malloc(sizeof *dev_new)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("adding device.\n");
|
||||
|
||||
dev_new->fd = -1;
|
||||
dev_new->data = NULL;
|
||||
dev_new->next = NULL;
|
||||
|
||||
if(dev_list == NULL)
|
||||
return (dev_list = dev_new);
|
||||
|
||||
iter = dev_list;
|
||||
while(iter->next) {
|
||||
iter = iter->next;
|
||||
}
|
||||
iter->next = dev_new;
|
||||
return dev_new;
|
||||
}
|
||||
|
||||
void remove_device(struct device *dev)
|
||||
{
|
||||
struct device *iter = dev_list, *tmp;
|
||||
|
||||
if(iter == NULL)
|
||||
return;
|
||||
if(iter == dev) {
|
||||
if(verbose)
|
||||
printf("removing device: %s\n", dev->path);
|
||||
dev_list = iter->next;
|
||||
free(iter);
|
||||
if((iter = dev_list) == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
while(iter->next) {
|
||||
if(iter->next == dev) {
|
||||
if(verbose)
|
||||
printf("removing device: %s\n", dev->path);
|
||||
tmp = iter->next;
|
||||
iter->next = iter->next->next;
|
||||
remove_dev_event(dev);
|
||||
if(tmp->fd >= 0) {
|
||||
close(tmp->fd);
|
||||
}
|
||||
free(tmp);
|
||||
} else {
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_dev_fd(void)
|
||||
static struct device *dev_path_in_use(char const *dev_path)
|
||||
{
|
||||
return dev.fd;
|
||||
struct device *iter = dev_list;
|
||||
while(iter) {
|
||||
if(strcmp(iter->path, dev_path) == 0) {
|
||||
return iter;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int read_dev(struct dev_input *inp)
|
||||
int get_device_fd(struct device *dev)
|
||||
{
|
||||
if(!dev.read) {
|
||||
if(dev == NULL)
|
||||
return -1;
|
||||
}
|
||||
return dev.read(&dev, inp);
|
||||
return dev->fd;
|
||||
}
|
||||
|
||||
void set_led(int state)
|
||||
int get_device_index(struct device *dev)
|
||||
{
|
||||
if(dev.set_led) {
|
||||
dev.set_led(&dev, state);
|
||||
struct device *iter = dev_list;
|
||||
int index = 0;
|
||||
while(iter) {
|
||||
if(dev == iter)
|
||||
return index;
|
||||
index++;
|
||||
iter = iter->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int read_device(struct device *dev, struct dev_input *inp)
|
||||
{
|
||||
if(dev->read == NULL)
|
||||
return -1;
|
||||
return (dev->read(dev, inp));
|
||||
}
|
||||
|
||||
void set_device_led(struct device *dev, int state)
|
||||
{
|
||||
if(dev->set_led)
|
||||
dev->set_led(dev, state);
|
||||
}
|
||||
|
||||
struct device *first_device(void)
|
||||
{
|
||||
return (dev_iter = dev_list);
|
||||
}
|
||||
|
||||
struct device *next_device(void)
|
||||
{
|
||||
if(dev_iter)
|
||||
dev_iter = dev_iter->next;
|
||||
return dev_iter;
|
||||
}
|
||||
|
|
20
src/dev.h
20
src/dev.h
|
@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#ifndef SPNAV_DEV_H_
|
||||
#define SPNAV_DEV_H_
|
||||
|
||||
#include <limits.h>
|
||||
#include "config.h"
|
||||
|
||||
struct dev_input;
|
||||
|
@ -28,19 +29,26 @@ struct device {
|
|||
int fd;
|
||||
void *data;
|
||||
char name[MAX_DEV_NAME];
|
||||
char path[PATH_MAX];
|
||||
|
||||
void (*close)(struct device*);
|
||||
int (*read)(struct device*, struct dev_input*);
|
||||
void (*set_led)(struct device*, int);
|
||||
|
||||
struct device *next;
|
||||
};
|
||||
|
||||
int init_dev(void);
|
||||
void shutdown_dev(void);
|
||||
int get_dev_fd(void);
|
||||
#define is_dev_valid() (get_dev_fd() >= 0)
|
||||
int init_devices(void);
|
||||
|
||||
int read_dev(struct dev_input *inp);
|
||||
void remove_device(struct device *dev);
|
||||
|
||||
void set_led(int state);
|
||||
int get_device_fd(struct device *dev);
|
||||
#define is_device_valid(dev) (get_device_fd(dev) >= 0)
|
||||
int get_device_index(struct device *dev);
|
||||
int read_device(struct device *dev, struct dev_input *inp);
|
||||
void set_device_led(struct device *dev, int state);
|
||||
|
||||
struct device *first_device(void);
|
||||
struct device *next_device(void);
|
||||
|
||||
#endif /* SPNAV_DEV_H_ */
|
||||
|
|
|
@ -25,9 +25,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
static void close_dev_serial(struct device *dev);
|
||||
static int read_dev_serial(struct device *dev, struct dev_input *inp);
|
||||
|
||||
int open_dev_serial(struct device *dev, const char *devfile)
|
||||
int open_dev_serial(struct device *dev)
|
||||
{
|
||||
if(!(dev->data = sball_open(devfile))) {
|
||||
if(!(dev->data = sball_open(dev->path))) {
|
||||
return -1;
|
||||
}
|
||||
dev->fd = sball_get_fd(dev->data);
|
||||
|
|
|
@ -21,6 +21,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
struct device;
|
||||
|
||||
int open_dev_serial(struct device *dev, const char *devfile);
|
||||
int open_dev_serial(struct device *dev);
|
||||
|
||||
#endif /* SPNAV_DEV_SERIAL_H_ */
|
||||
|
|
|
@ -20,7 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
struct device;
|
||||
|
||||
int open_dev_usb(struct device *dev, const char *path);
|
||||
const char *find_usb_device(void);
|
||||
int open_dev_usb(struct device *dev);
|
||||
void find_usb_devices(char **path, int str_n, int char_n);
|
||||
|
||||
#endif /* SPNAV_DEV_USB_H_ */
|
||||
|
|
|
@ -23,12 +23,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#include "dev.h"
|
||||
|
||||
int open_dev_usb(struct device *dev, const char *path)
|
||||
int open_dev_usb(struct device *dev)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *find_usb_device(void)
|
||||
void find_usb_devices(char **path, int str_n, int char_n);
|
||||
{
|
||||
static const int vendor_id = 1133; /* 3dconnexion */
|
||||
static char dev_path[512];
|
||||
|
@ -47,7 +47,8 @@ const char *find_usb_device(void)
|
|||
/* fetch... */
|
||||
if(IOServiceGetMatchingServices(kIOMasterPortDefault, match_dict, &iter) != kIOReturnSuccess) {
|
||||
fprintf(stderr, "failed to retrieve USB HID devices\n");
|
||||
return 0;
|
||||
/* return 0; */
|
||||
return;
|
||||
}
|
||||
|
||||
dev = IOIteratorNext(iter);
|
||||
|
@ -56,7 +57,7 @@ const char *find_usb_device(void)
|
|||
|
||||
IOObjectRelease(dev);
|
||||
IOObjectRelease(iter);
|
||||
return dev_path;
|
||||
/* return dev_path;*/
|
||||
}
|
||||
|
||||
#endif /* __APPLE__ && __MACH__ */
|
||||
|
|
|
@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -54,12 +55,12 @@ static int read_evdev(struct device *dev, struct dev_input *inp);
|
|||
static void set_led_evdev(struct device *dev, int state);
|
||||
|
||||
|
||||
int open_dev_usb(struct device *dev, const char *path)
|
||||
int open_dev_usb(struct device *dev)
|
||||
{
|
||||
/*unsigned char evtype_mask[(EV_MAX + 7) / 8];*/
|
||||
|
||||
if((dev->fd = open(path, O_RDWR)) == -1) {
|
||||
if((dev->fd = open(path, O_RDONLY)) == -1) {
|
||||
if((dev->fd = open(dev->path, O_RDWR)) == -1) {
|
||||
if((dev->fd = open(dev->path, O_RDONLY)) == -1) {
|
||||
perror("failed to open device");
|
||||
return -1;
|
||||
}
|
||||
|
@ -107,6 +108,7 @@ static void close_evdev(struct device *dev)
|
|||
dev->set_led(dev, 0);
|
||||
close(dev->fd);
|
||||
dev->fd = -1;
|
||||
remove_device(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,11 +128,7 @@ static int read_evdev(struct device *dev, struct dev_input *inp)
|
|||
if(rdbytes == -1) {
|
||||
if(errno != EAGAIN) {
|
||||
perror("read error");
|
||||
close(dev->fd);
|
||||
dev->fd = -1;
|
||||
|
||||
/* restart hotplug detection */
|
||||
init_hotplug();
|
||||
remove_device(dev);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -165,7 +163,6 @@ static int read_evdev(struct device *dev, struct dev_input *inp)
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -188,60 +185,97 @@ static void set_led_evdev(struct device *dev, int state)
|
|||
}
|
||||
|
||||
#define PROC_DEV "/proc/bus/input/devices"
|
||||
const char *find_usb_device(void)
|
||||
void find_usb_devices(char **path, int str_n, int char_n)
|
||||
{
|
||||
static char path[PATH_MAX];
|
||||
int path_idx = 0;
|
||||
int i, valid_vendor = 0, valid_str = 0;
|
||||
int skip_section = 0, buf_used, buf_len;
|
||||
char buf[1024];
|
||||
char *buf_pos, *section_start, *next_section = 0, *cur_line, *next_line;
|
||||
FILE *fp;
|
||||
|
||||
if(verbose) {
|
||||
printf("Device detection, parsing " PROC_DEV "\n");
|
||||
}
|
||||
|
||||
for(i=0; i<str_n; i++) {
|
||||
path[i][0] = 0;
|
||||
}
|
||||
|
||||
buf_pos = buf;
|
||||
buf_len = sizeof(buf);
|
||||
if((fp = fopen(PROC_DEV, "r"))) {
|
||||
while(fgets(buf, sizeof buf, fp)) {
|
||||
switch(buf[0]) {
|
||||
case 'I':
|
||||
valid_vendor = strstr(buf, "Vendor=046d") != 0;
|
||||
break;
|
||||
while(fread(buf_pos, sizeof(char), buf_len, fp)) {
|
||||
section_start = buf;
|
||||
|
||||
case 'N':
|
||||
valid_str = strstr(buf, "3Dconnexion") != 0;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
if(valid_str && valid_vendor) {
|
||||
char *ptr, *start;
|
||||
|
||||
if(!(start = strchr(buf, '='))) {
|
||||
continue;
|
||||
}
|
||||
start++;
|
||||
|
||||
if((ptr = strstr(start, "event"))) {
|
||||
start = ptr;
|
||||
}
|
||||
|
||||
if((ptr = strchr(start, ' '))) {
|
||||
*ptr = 0;
|
||||
}
|
||||
if((ptr = strchr(start, '\n'))) {
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
snprintf(path, sizeof path, "/dev/input/%s", start);
|
||||
fclose(fp);
|
||||
return path;
|
||||
for(;;) {
|
||||
next_section = strstr(section_start, "\n\n");
|
||||
if(next_section == NULL) {
|
||||
/* move last (partial) section to start of buf */
|
||||
buf_used = (buf + sizeof(buf)) - section_start;
|
||||
memmove(buf, section_start, buf_used);
|
||||
/* point to end of last section and calc remaining space in buf */
|
||||
buf_pos = buf + buf_used + 1;
|
||||
buf_len = sizeof(buf) - buf_used;
|
||||
/* break to read from file again */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* set second newline to teminating null */
|
||||
*(next_section + sizeof(char)) = 0;
|
||||
/* point to start of next section */
|
||||
next_section += 2 * sizeof(char);
|
||||
|
||||
case '\n':
|
||||
valid_vendor = valid_str = 0;
|
||||
break;
|
||||
valid_vendor = 0;
|
||||
valid_str = 0;
|
||||
cur_line = section_start;
|
||||
while (*cur_line) {
|
||||
next_line = strchr(cur_line, '\n');
|
||||
*next_line = 0;
|
||||
next_line++;
|
||||
switch (*cur_line) {
|
||||
case 'I':
|
||||
valid_vendor = strstr(cur_line, "Vendor=046d") != 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
case 'N':
|
||||
valid_str = strstr(cur_line, "3Dconnexion") != 0;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
if(valid_vendor && valid_str) {
|
||||
char *ptr, *start;
|
||||
|
||||
if(!(start = strchr(cur_line, '='))) {
|
||||
skip_section = 1;
|
||||
break;
|
||||
}
|
||||
start++;
|
||||
|
||||
if((ptr = strstr(start, "event"))) {
|
||||
start = ptr;
|
||||
}
|
||||
|
||||
if((ptr = strchr(start, ' '))) {
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
snprintf(path[path_idx], char_n, "/dev/input/%s", start);
|
||||
path_idx++;
|
||||
if(path_idx == str_n) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
skip_section = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(skip_section) {
|
||||
skip_section = 0;
|
||||
break;
|
||||
}
|
||||
cur_line = next_line;
|
||||
}
|
||||
section_start = next_section;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
@ -251,6 +285,10 @@ const char *find_usb_device(void)
|
|||
}
|
||||
}
|
||||
|
||||
if(path[0][0] != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(verbose) {
|
||||
fprintf(stderr, "trying alternative detection, querying /dev/input/eventX device names...\n");
|
||||
}
|
||||
|
@ -263,26 +301,27 @@ const char *find_usb_device(void)
|
|||
for(;;) {
|
||||
int fd;
|
||||
|
||||
snprintf(path, sizeof path, "/dev/input/event%d", ++i);
|
||||
snprintf(path[path_idx], char_n, "/dev/input/event%d", ++i);
|
||||
|
||||
if(verbose) {
|
||||
fprintf(stderr, " trying \"%s\" ... ", path);
|
||||
fprintf(stderr, " trying \"%s\" ... ", path[path_idx]);
|
||||
}
|
||||
|
||||
if((fd = open(path, O_RDONLY)) == -1) {
|
||||
if((fd = open(path[path_idx], O_RDONLY)) == -1) {
|
||||
if(errno != ENOENT) {
|
||||
fprintf(stderr, "failed to open %s: %s. this might hinder device detection\n",
|
||||
path, strerror(errno));
|
||||
path[path_idx], strerror(errno));
|
||||
continue;
|
||||
} else {
|
||||
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
|
||||
fprintf(stderr, "failed to open %s: %s\n", path[path_idx], strerror(errno));
|
||||
path[path_idx][0] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ioctl(fd, EVIOCGNAME(sizeof buf), buf) == -1) {
|
||||
fprintf(stderr, "failed to get device name for device %s: %s. this might hinder device detection\n",
|
||||
path, strerror(errno));
|
||||
path[path_idx], strerror(errno));
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
|
@ -292,13 +331,15 @@ const char *find_usb_device(void)
|
|||
|
||||
if(strstr(buf, "3Dconnexion")) {
|
||||
close(fd);
|
||||
return path;
|
||||
path_idx++;
|
||||
if(path_idx == str_n) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#endif /* __linux__ */
|
||||
|
|
|
@ -24,13 +24,13 @@ static const char *message =
|
|||
"Unfortunately this version of spacenavd does not support USB devices on your "
|
||||
"platform yet. Make sure you are using the latest version of spacenavd.\n";
|
||||
|
||||
const char *find_usb_device(void)
|
||||
void **find_usb_devices(char **path, int str_n, int char_n)
|
||||
{
|
||||
fputs(message, stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_dev_usb(struct device *dev, const char *path)
|
||||
int open_dev_usb(struct device *dev)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
|
182
src/event.c
182
src/event.c
|
@ -34,12 +34,89 @@ enum {
|
|||
MOT_RX, MOT_RY, MOT_RZ
|
||||
};
|
||||
|
||||
static void dispatch_event(spnav_event *ev);
|
||||
struct dev_event {
|
||||
spnav_event event;
|
||||
struct timeval timeval;
|
||||
struct device *dev;
|
||||
int pending;
|
||||
struct dev_event *next;
|
||||
};
|
||||
|
||||
static struct dev_event *add_dev_event(struct device *dev);
|
||||
static struct dev_event *device_event_in_use(struct device *dev);
|
||||
static void dispatch_event(struct dev_event *dev);
|
||||
static void send_event(spnav_event *ev, struct client *c);
|
||||
static unsigned int msec_dif(struct timeval tv1, struct timeval tv2);
|
||||
|
||||
static spnav_event ev;
|
||||
static int ev_pending;
|
||||
static struct dev_event *dev_ev_list = NULL;
|
||||
|
||||
static struct dev_event *add_dev_event(struct device *dev)
|
||||
{
|
||||
struct dev_event *dev_ev, *iter;
|
||||
int i;
|
||||
|
||||
if((dev_ev = malloc(sizeof *dev_ev)) == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev_ev->event.motion.data = (int*)&dev_ev->event.motion.x;
|
||||
for(i=0; i<6; i++)
|
||||
dev_ev->event.motion.data[i] = 0;
|
||||
gettimeofday(&dev_ev->timeval, 0);
|
||||
dev_ev->dev = dev;
|
||||
dev_ev->next = NULL;
|
||||
|
||||
if(dev_ev_list == NULL)
|
||||
return dev_ev_list = dev_ev;
|
||||
|
||||
iter = dev_ev_list;
|
||||
while(iter->next) {
|
||||
iter = iter->next;
|
||||
}
|
||||
iter->next = dev_ev;
|
||||
return dev_ev;
|
||||
}
|
||||
|
||||
/* remove_dev_event takes a device pointer as argument so that upon removal of
|
||||
* a device the pending event (if any) can be removed.
|
||||
*/
|
||||
void remove_dev_event(struct device *dev)
|
||||
{
|
||||
struct dev_event *iter = dev_ev_list, *tmp;
|
||||
|
||||
if(iter == NULL)
|
||||
return;
|
||||
if(iter->dev == dev) {
|
||||
dev_ev_list = iter->next;
|
||||
free(iter);
|
||||
if((iter = dev_ev_list) == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
while(iter->next) {
|
||||
if(iter->next->dev == dev) {
|
||||
if(verbose)
|
||||
printf("removing device event of: %s\n", dev->path);
|
||||
tmp = iter->next;
|
||||
iter->next = iter->next->next;
|
||||
free(tmp);
|
||||
} else {
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct dev_event *device_event_in_use(struct device *dev)
|
||||
{
|
||||
struct dev_event *iter = dev_ev_list;
|
||||
while(iter) {
|
||||
if(iter->dev == dev) {
|
||||
return iter;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* process_input processes an device input event, and dispatches
|
||||
* spacenav events to the clients by calling dispatch_event.
|
||||
|
@ -47,9 +124,10 @@ static int ev_pending;
|
|||
* we get an INP_FLUSH event. Button events are dispatched immediately
|
||||
* and they implicitly flush any pending motion event.
|
||||
*/
|
||||
void process_input(struct dev_input *inp)
|
||||
void process_input(struct device *dev, struct dev_input *inp)
|
||||
{
|
||||
int sign;
|
||||
struct dev_event *dev_ev;
|
||||
|
||||
switch(inp->type) {
|
||||
case INP_MOTION:
|
||||
|
@ -62,10 +140,17 @@ void process_input(struct dev_input *inp)
|
|||
|
||||
inp->val = (int)((float)inp->val * cfg.sensitivity * (inp->idx < 3 ? cfg.sens_trans[inp->idx] : cfg.sens_rot[inp->idx - 3]));
|
||||
|
||||
ev.type = EVENT_MOTION;
|
||||
ev.motion.data = (int*)&ev.motion.x;
|
||||
ev.motion.data[inp->idx] = sign * inp->val;
|
||||
ev_pending = 1;
|
||||
dev_ev = device_event_in_use(dev);
|
||||
if(verbose && dev_ev == NULL)
|
||||
printf("adding dev event for device: %s\n", dev->path);
|
||||
if(dev_ev == NULL && (dev_ev = add_dev_event(dev)) == NULL) {
|
||||
fprintf(stderr, "failed to get dev_event\n");
|
||||
break;
|
||||
}
|
||||
dev_ev->event.type = EVENT_MOTION;
|
||||
dev_ev->event.motion.data = (int*)&dev_ev->event.motion.x;
|
||||
dev_ev->event.motion.data[inp->idx] = sign * inp->val;
|
||||
dev_ev->pending = 1;
|
||||
break;
|
||||
|
||||
case INP_BUTTON:
|
||||
|
@ -82,26 +167,37 @@ void process_input(struct dev_input *inp)
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(ev_pending) {
|
||||
dispatch_event(&ev);
|
||||
ev_pending = 0;
|
||||
dev_ev = device_event_in_use(dev);
|
||||
if(dev_ev && dev_ev->pending) {
|
||||
dispatch_event(dev_ev);
|
||||
dev_ev->pending = 0;
|
||||
}
|
||||
inp->idx = cfg.map_button[inp->idx];
|
||||
|
||||
/* button events are not queued */
|
||||
{
|
||||
union spnav_event bev;
|
||||
bev.type = EVENT_BUTTON;
|
||||
bev.button.press = inp->val;
|
||||
bev.button.bnum = inp->idx;
|
||||
dispatch_event(&bev);
|
||||
struct dev_event dev_button_event;
|
||||
dev_button_event.dev = dev;
|
||||
dev_button_event.event.type = EVENT_BUTTON;
|
||||
dev_button_event.event.button.press = inp->val;
|
||||
dev_button_event.event.button.bnum = inp->idx;
|
||||
dispatch_event(&dev_button_event);
|
||||
}
|
||||
|
||||
/* to have them replace motion events in the queue uncomment next section */
|
||||
/* dev_ev = add_dev_event(dev);
|
||||
* dev_ev->event.type = EVENT_BUTTON;
|
||||
* dev_ev->event.button.press = inp->val;
|
||||
* dev_ev->event.button.bnum = inp->idx;
|
||||
* dispatch_event(dev_ev);
|
||||
*/
|
||||
break;
|
||||
|
||||
case INP_FLUSH:
|
||||
if(ev_pending) {
|
||||
dispatch_event(&ev);
|
||||
ev_pending = 0;
|
||||
dev_ev = device_event_in_use(dev);
|
||||
if(dev_ev && dev_ev->pending) {
|
||||
dispatch_event(dev_ev);
|
||||
dev_ev->pending = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -110,47 +206,47 @@ void process_input(struct dev_input *inp)
|
|||
}
|
||||
}
|
||||
|
||||
int in_deadzone(void)
|
||||
int in_deadzone(struct device *dev)
|
||||
{
|
||||
int i;
|
||||
if(!ev.motion.data) {
|
||||
ev.motion.data = &ev.motion.x;
|
||||
}
|
||||
|
||||
struct dev_event *dev_ev;
|
||||
if((dev_ev = device_event_in_use(dev)) == NULL)
|
||||
return -1;
|
||||
for(i=0; i<6; i++) {
|
||||
if(ev.motion.data[i] != 0) {
|
||||
if(dev_ev->event.motion.data[i] != 0)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void repeat_last_event(void)
|
||||
void repeat_last_event(struct device *dev)
|
||||
{
|
||||
if(ev.type == EVENT_MOTION) {
|
||||
dispatch_event(&ev);
|
||||
}
|
||||
struct dev_event *dev_ev;
|
||||
if((dev_ev = device_event_in_use(dev)) == NULL)
|
||||
return;
|
||||
dispatch_event(dev_ev);
|
||||
}
|
||||
|
||||
static void dispatch_event(spnav_event *ev)
|
||||
static void dispatch_event(struct dev_event *dev_ev)
|
||||
{
|
||||
struct client *c, *citer;
|
||||
static struct timeval prev_motion_time;
|
||||
struct client *c, *client_iter;
|
||||
int dev_idx;
|
||||
|
||||
if(ev->type == EVENT_MOTION) {
|
||||
if(dev_ev->event.type == EVENT_MOTION) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
|
||||
ev->motion.period = msec_dif(tv, prev_motion_time);
|
||||
prev_motion_time = tv;
|
||||
dev_ev->event.motion.period = msec_dif(tv, dev_ev->timeval);
|
||||
dev_ev->timeval = tv;
|
||||
}
|
||||
|
||||
citer = first_client();
|
||||
while(citer) {
|
||||
c = citer;
|
||||
citer = next_client();
|
||||
|
||||
send_event(ev, c);
|
||||
dev_idx = get_device_index(dev_ev->dev);
|
||||
client_iter = first_client();
|
||||
while(client_iter) {
|
||||
c = client_iter;
|
||||
client_iter = next_client();
|
||||
if(get_client_device_index(c) <= dev_idx) /* use <= until API changes, else == */
|
||||
send_event(&dev_ev->event, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
10
src/event.h
10
src/event.h
|
@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include "config.h"
|
||||
#include <sys/time.h>
|
||||
#include "dev.h"
|
||||
|
||||
enum {
|
||||
EVENT_MOTION,
|
||||
|
@ -47,8 +48,6 @@ typedef union spnav_event {
|
|||
struct event_button button;
|
||||
} spnav_event;
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
INP_MOTION,
|
||||
INP_BUTTON,
|
||||
|
@ -62,14 +61,15 @@ struct dev_input {
|
|||
int val;
|
||||
};
|
||||
|
||||
void remove_dev_event(struct device *dev);
|
||||
|
||||
void process_input(struct dev_input *inp);
|
||||
void process_input(struct device *dev, struct dev_input *inp);
|
||||
|
||||
/* non-zero if the last processed motion event was in the deadzone */
|
||||
int in_deadzone(void);
|
||||
int in_deadzone(struct device *dev);
|
||||
|
||||
/* dispatches the last event */
|
||||
void repeat_last_event(void);
|
||||
void repeat_last_event(struct device *dev);
|
||||
|
||||
|
||||
#endif /* EVENT_H_ */
|
||||
|
|
|
@ -92,12 +92,11 @@ int handle_hotplug(void)
|
|||
char buf[512];
|
||||
read(hotplug_fd, buf, sizeof buf);
|
||||
|
||||
if(get_dev_fd() == -1) {
|
||||
if(init_dev() == -1) {
|
||||
return -1;
|
||||
}
|
||||
shutdown_hotplug();
|
||||
}
|
||||
if(verbose)
|
||||
printf("\nhandle_hotplug called\n");
|
||||
|
||||
if (init_devices() == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
86
src/spnavd.c
86
src/spnavd.c
|
@ -91,10 +91,6 @@ int main(int argc, char **argv)
|
|||
|
||||
read_cfg("/etc/spnavrc", &cfg);
|
||||
|
||||
if(init_clients() == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
signal(SIGSEGV, sig_handler);
|
||||
|
@ -102,9 +98,9 @@ int main(int argc, char **argv)
|
|||
signal(SIGUSR1, sig_handler);
|
||||
signal(SIGUSR2, sig_handler);
|
||||
|
||||
if(init_dev() == -1) {
|
||||
init_hotplug();
|
||||
}
|
||||
init_devices();
|
||||
init_hotplug();
|
||||
|
||||
init_unix();
|
||||
#ifdef USE_X11
|
||||
init_x11();
|
||||
|
@ -115,12 +111,21 @@ int main(int argc, char **argv)
|
|||
for(;;) {
|
||||
fd_set rset;
|
||||
int fd, max_fd = 0;
|
||||
struct client *c;
|
||||
struct client *client_iter;
|
||||
struct device *dev_iter;
|
||||
|
||||
FD_ZERO(&rset);
|
||||
|
||||
/* set the device fd if it's open, otherwise set the hotplug fd */
|
||||
if((fd = get_dev_fd()) != -1 || (fd = get_hotplug_fd()) != -1) {
|
||||
dev_iter = first_device();
|
||||
while(dev_iter) {
|
||||
if((fd = get_device_fd(dev_iter)) != -1) {
|
||||
FD_SET(fd, &rset);
|
||||
if(fd > max_fd) max_fd = fd;
|
||||
}
|
||||
dev_iter = next_device();
|
||||
}
|
||||
|
||||
if((fd = get_hotplug_fd()) != -1) {
|
||||
FD_SET(fd, &rset);
|
||||
if(fd > max_fd) max_fd = fd;
|
||||
}
|
||||
|
@ -132,16 +137,16 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
/* all the UNIX socket clients */
|
||||
c = first_client();
|
||||
while(c) {
|
||||
if(get_client_type(c) == CLIENT_UNIX) {
|
||||
int s = get_client_socket(c);
|
||||
client_iter = first_client();
|
||||
while(client_iter) {
|
||||
if(get_client_type(client_iter) == CLIENT_UNIX) {
|
||||
int s = get_client_socket(client_iter);
|
||||
assert(s >= 0);
|
||||
|
||||
FD_SET(s, &rset);
|
||||
if(s > max_fd) max_fd = s;
|
||||
}
|
||||
c = next_client();
|
||||
client_iter = next_client();
|
||||
}
|
||||
|
||||
/* and the X server socket */
|
||||
|
@ -154,7 +159,8 @@ int main(int argc, char **argv)
|
|||
|
||||
do {
|
||||
struct timeval tv, *timeout = 0;
|
||||
if(is_dev_valid() && cfg.repeat_msec >= 0 && !in_deadzone()) {
|
||||
dev_iter = first_device();
|
||||
if(is_device_valid(dev_iter) && cfg.repeat_msec >= 0 && !in_deadzone(dev_iter)) {
|
||||
tv.tv_sec = cfg.repeat_msec / 1000;
|
||||
tv.tv_usec = cfg.repeat_msec % 1000;
|
||||
timeout = &tv;
|
||||
|
@ -166,8 +172,13 @@ int main(int argc, char **argv)
|
|||
if(ret > 0) {
|
||||
handle_events(&rset);
|
||||
} else {
|
||||
if(cfg.repeat_msec >= 0 && !in_deadzone()) {
|
||||
repeat_last_event();
|
||||
if(cfg.repeat_msec >= 0) {
|
||||
dev_iter = first_device();
|
||||
while(dev_iter) {
|
||||
if(!in_deadzone(dev_iter))
|
||||
repeat_last_event(dev_iter);
|
||||
dev_iter = next_device();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,11 +187,20 @@ int main(int argc, char **argv)
|
|||
|
||||
static void cleanup(void)
|
||||
{
|
||||
struct device *dev_iter, *tmp;
|
||||
#ifdef USE_X11
|
||||
close_x11(); /* call to avoid leaving garbage in the X server's root windows */
|
||||
#endif
|
||||
close_unix();
|
||||
shutdown_dev();
|
||||
|
||||
shutdown_hotplug();
|
||||
|
||||
dev_iter = first_device();
|
||||
while(dev_iter) {
|
||||
tmp = next_device();
|
||||
remove_device(dev_iter);
|
||||
dev_iter = tmp;
|
||||
}
|
||||
remove(PIDFILE);
|
||||
}
|
||||
|
||||
|
@ -263,6 +283,8 @@ static int find_running_daemon(void)
|
|||
static void handle_events(fd_set *rset)
|
||||
{
|
||||
int dev_fd, hotplug_fd;
|
||||
struct device *dev_iter;
|
||||
struct dev_input inp;
|
||||
|
||||
/* handle anything coming through the UNIX socket */
|
||||
handle_uevents(rset);
|
||||
|
@ -273,18 +295,19 @@ static void handle_events(fd_set *rset)
|
|||
#endif
|
||||
|
||||
/* finally read any pending device input data */
|
||||
if((dev_fd = get_dev_fd()) != -1) {
|
||||
if(FD_ISSET(dev_fd, rset)) {
|
||||
struct dev_input inp;
|
||||
|
||||
dev_iter = first_device();
|
||||
while(dev_iter) {
|
||||
if((dev_fd = get_device_fd(dev_iter)) != -1 && FD_ISSET(dev_fd, rset)) {
|
||||
/* read an event from the device ... */
|
||||
while(read_dev(&inp) != -1) {
|
||||
while(read_device(dev_iter, &inp) != -1) {
|
||||
/* ... and process it, possibly dispatching a spacenav event to clients */
|
||||
process_input(&inp);
|
||||
process_input(dev_iter, &inp);
|
||||
}
|
||||
}
|
||||
dev_iter = next_device();
|
||||
}
|
||||
|
||||
} else if((hotplug_fd = get_hotplug_fd()) != -1) {
|
||||
if((hotplug_fd = get_hotplug_fd()) != -1) {
|
||||
if(FD_ISSET(hotplug_fd, rset)) {
|
||||
handle_hotplug();
|
||||
}
|
||||
|
@ -297,13 +320,20 @@ static void handle_events(fd_set *rset)
|
|||
static void sig_handler(int s)
|
||||
{
|
||||
int tmp;
|
||||
struct device *dev_iter;
|
||||
|
||||
switch(s) {
|
||||
case SIGHUP:
|
||||
tmp = cfg.led;
|
||||
read_cfg("/etc/spnavrc", &cfg);
|
||||
if(cfg.led != tmp && get_dev_fd() >= 0) {
|
||||
set_led(cfg.led);
|
||||
dev_iter = first_device();
|
||||
while(dev_iter) {
|
||||
if(cfg.led != tmp && is_device_valid(dev_iter)) {
|
||||
if(verbose)
|
||||
printf("turn led %s, device: %s\n", cfg.led ? "on": "off", dev_iter->name);
|
||||
set_device_led(dev_iter, cfg.led);
|
||||
}
|
||||
dev_iter = next_device();
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#define SOCK_NAME "/var/run/spnav.sock"
|
||||
#define PIDFILE "/var/run/spnavd.pid"
|
||||
#define LOGFILE "/var/log/spnavd.log"
|
||||
/* Multiple devices support */
|
||||
#ifndef MAX_DEVICES
|
||||
#define MAX_DEVICES 8
|
||||
#endif
|
||||
|
||||
struct cfg cfg;
|
||||
int verbose;
|
||||
|
|
Ładowanie…
Reference in New Issue