Commit 113bd85c authored by Your Name's avatar Your Name
Browse files

first version of lslhider

parent fdaa1de2
......@@ -8,7 +8,7 @@ INSTALL=install -v
all clean: $(SUBDIRS)
install: libs/install/lsl libs/install/azmq
install: libs/install/lsl libs/install/azmq libs/install/libevdev
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
......@@ -48,6 +48,7 @@ libs/install/azmq:
libs/install/libevdev:
$(MAKE) -C libevdev install
ldconfig
.PHONY: labstreaminglayer azmq libevdev $(SUBDIRS)
LSLBASE=../labstreaminglayer/build/install
CC=gcc
CFLAGS+=-Wall -I../libevdev
LDLIBS+=-levdev
LDFLAGS+=-static
CXXFLAGS+=-std=c++11 -Wall -Wno-sign-compare -I$(LSLBASE)/include -I../libevdev
all: libevdev-events
LDLIBS+=-levdev -lboost_program_options -llsl32
LDFLAGS+=-L$(LSLBASE)/lib
all: libevdev-events lslhider
lslhider: lslhider.cc quiet.h
/*
* Copyright © 2013 Red Hat, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/*
* Portions Copyright 2020 Günter Windau
* LSLHIDER - LSL Human Interface Device Event Recorder
*
* Based on libevdev-events.c from the libevdev library, this program
* sends HID events recorded on one of the input devices to an LSL outlet.
*/
#include "config.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "libevdev/libevdev.h"
#include <iostream>
#include <lsl_cpp.h>
#include <boost/program_options.hpp>
#include "quiet.h"
using namespace std;
using namespace boost;
using namespace lsl;
stream_outlet *outlet;
string info_name, info_type, info_sourceid;
string event_dev;
static int verbose = 0;
void parse_options(int argc, const char *argv[]) {
namespace po = boost::program_options;
// Declare the supported options.
po::options_description desc("Usage:");
desc.add_options()("help,h", "show this message")(
"event-dev,d", po::value<string>(), "input device to read events from")(
"lsl-name", po::value<string>(), "set the name of the LSL stream")(
"lsl-type", po::value<string>(), "set the type of the LSL stream")(
"lsl-sourceid", po::value<string>(),
"set the sourceid of the LSL stream")("verbose,v",
"enable verbose output");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help")) {
cout << desc << "\n";
exit(0);
}
if (vm.count("verbose")) {
verbose = 1;
}
if (vm.count("event-dev"))
event_dev = vm["event-dev"].as<string>();
else
event_dev = "/dev/input/event0";
if (verbose)
cout << "Event input device: " << event_dev << endl;
if (vm.count("lsl-name"))
info_name = vm["lsl-name"].as<string>();
else
info_name = "Raspberry Pi HID Events";
if (verbose)
cout << "LSL name is: " << info_name << endl;
if (vm.count("lsl-type"))
info_type = vm["lsl-type"].as<string>();
else {
char hostname[255];
gethostname(hostname, 255);
ostringstream s;
s << "HID Events @ " << hostname;
info_type = s.str();
}
if (verbose)
cout << "LSL type is: " << info_type << endl;
if (vm.count("lsl-sourceid"))
info_sourceid = vm["lsl-sourceid"].as<string>();
else {
char hostname[255];
gethostname(hostname, 255);
ostringstream s;
s << argv[0] << "@" << hostname;
info_sourceid = s.str();
}
if (verbose)
cout << "LSL sourceid is: " << info_sourceid << endl;
}
static void print_abs_bits(struct libevdev *dev, int axis) {
const struct input_absinfo *abs;
if (!libevdev_has_event_code(dev, EV_ABS, axis))
return;
abs = libevdev_get_abs_info(dev, axis);
printf(" Value %6d\n", abs->value);
printf(" Min %6d\n", abs->minimum);
printf(" Max %6d\n", abs->maximum);
if (abs->fuzz)
printf(" Fuzz %6d\n", abs->fuzz);
if (abs->flat)
printf(" Flat %6d\n", abs->flat);
if (abs->resolution)
printf(" Resolution %6d\n", abs->resolution);
}
static void print_code_bits(struct libevdev *dev, unsigned int type,
unsigned int max) {
unsigned int i;
for (i = 0; i <= max; i++) {
if (!libevdev_has_event_code(dev, type, i))
continue;
printf(" Event code %i (%s)\n", i,
libevdev_event_code_get_name(type, i));
if (type == EV_ABS)
print_abs_bits(dev, i);
}
}
static void print_bits(struct libevdev *dev) {
unsigned int i;
printf("Supported events:\n");
for (i = 0; i <= EV_MAX; i++) {
if (libevdev_has_event_type(dev, i))
printf(" Event type %d (%s)\n", i,
libevdev_event_type_get_name(i));
switch (i) {
case EV_KEY:
print_code_bits(dev, EV_KEY, KEY_MAX);
break;
case EV_REL:
print_code_bits(dev, EV_REL, REL_MAX);
break;
case EV_ABS:
print_code_bits(dev, EV_ABS, ABS_MAX);
break;
case EV_LED:
print_code_bits(dev, EV_LED, LED_MAX);
break;
}
}
}
static void print_props(struct libevdev *dev) {
unsigned int i;
printf("Properties:\n");
for (i = 0; i <= INPUT_PROP_MAX; i++) {
if (libevdev_has_property(dev, i))
printf(" Property type %d (%s)\n", i,
libevdev_property_get_name(i));
}
}
static int print_event(struct input_event *ev) {
if (ev->type == EV_SYN)
printf(
"Event: time %ld.%06ld, ++++++++++++++++++++ %s +++++++++++++++\n",
ev->input_event_sec, ev->input_event_usec,
libevdev_event_type_get_name(ev->type));
else {
char marker[1024];
snprintf(marker, sizeof(marker), "%s %s %d\n",
libevdev_event_type_get_name(ev->type),
libevdev_event_code_get_name(ev->type, ev->code),
ev->value);
string smarker=marker;
outlet->push_sample(&smarker);
printf("Sent LSL marker: %s\n", marker);
printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n",
ev->input_event_sec, ev->input_event_usec, ev->type,
libevdev_event_type_get_name(ev->type), ev->code,
libevdev_event_code_get_name(ev->type, ev->code), ev->value);
}
return 0;
}
static int print_sync_event(struct input_event *ev) {
printf("SYNC: ");
print_event(ev);
return 0;
}
int main(int argc, const char *argv[]) {
struct libevdev *dev = NULL;
int fd;
int rc = 1;
parse_options(argc, argv);
if (!verbose)
suppress_stdout();
fd = open(event_dev.c_str(), O_RDONLY);
if (fd < 0) {
perror("Failed to open device");
libevdev_free(dev);
return 1;
}
rc = libevdev_new_from_fd(fd, &dev);
if (rc < 0) {
fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc));
libevdev_free(dev);
return 1;
}
// make a new stream_info and open an outlet with it
stream_info info(info_name.c_str(), info_type.c_str(), 1,
lsl::IRREGULAR_RATE, lsl::cf_string,
info_sourceid.c_str());
outlet = new stream_outlet(info);
printf("Input device ID: bus %#x vendor %#x product %#x\n",
libevdev_get_id_bustype(dev), libevdev_get_id_vendor(dev),
libevdev_get_id_product(dev));
printf("Evdev version: %x\n", libevdev_get_driver_version(dev));
printf("Input device name: \"%s\"\n", libevdev_get_name(dev));
printf("Phys location: %s\n", libevdev_get_phys(dev));
printf("Uniq identifier: %s\n", libevdev_get_uniq(dev));
print_bits(dev);
print_props(dev);
do {
struct input_event ev;
rc = libevdev_next_event(
dev, LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_BLOCKING, &ev);
if (rc == LIBEVDEV_READ_STATUS_SYNC) {
printf("::::::::::::::::::::: dropped ::::::::::::::::::::::\n");
while (rc == LIBEVDEV_READ_STATUS_SYNC) {
print_sync_event(&ev);
rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_SYNC, &ev);
}
printf("::::::::::::::::::::: re-synced ::::::::::::::::::::::\n");
}
else if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
print_event(&ev);
} while (rc == LIBEVDEV_READ_STATUS_SYNC ||
rc == LIBEVDEV_READ_STATUS_SUCCESS || rc == -EAGAIN);
if (rc != LIBEVDEV_READ_STATUS_SUCCESS && rc != -EAGAIN)
fprintf(stderr, "Failed to handle events: %s\n", strerror(-rc));
rc = 0;
libevdev_free(dev);
return rc;
}
/*
* quiet.h -- functions to (temporarily) suppress all output to stdout and stderr
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
inline int suppress_stdout() {
fflush(stdout);
int ret = dup(1);
int nullfd = open("/dev/null", O_WRONLY);
// check nullfd for error omitted
dup2(nullfd, 1);
close(nullfd);
return ret;
}
inline void resume_stdout(int fd) {
fflush(stdout);
dup2(fd, 1);
close(fd);
}
inline int suppress_stderr() {
fflush(stderr);
int ret = dup(1);
int nullfd = open("/dev/null", O_WRONLY);
// check nullfd for error omitted
dup2(nullfd, 1);
close(nullfd);
return ret;
}
inline void resume_stderr(int fd) {
fflush(stderr);
dup2(fd, 1);
close(fd);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment