* apps/graphics/input/getevent/getevent.c
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <debug.h>
#include <syslog.h>
#include <signal.h>
#include <dirent.h>
#include <nuttx/input/keyboard.h>
#include <nuttx/input/mouse.h>
#include <nuttx/input/touchscreen.h>
* Pre-processor Definitions
****************************************************************************/
#define GETEVENT_INFO(format, ...) \
syslog(LOG_WARNING, "[getevent]: " format, ##__VA_ARGS__)
* Private Types
****************************************************************************/
struct input_device_s;
typedef CODE int (*input_init_cb)(FAR struct input_device_s *);
typedef CODE void (*input_read_cb)(FAR struct input_device_s *);
struct touch_priv_s
{
uint8_t maxpoint;
struct touch_sample_s sample[];
};
struct input_device_s
{
int fd;
input_init_cb init_cb;
input_read_cb read_cb;
FAR void *priv;
FAR struct input_device_s *next;
char path[];
};
struct input_devices_ctx_s
{
FAR struct input_device_s *head;
};
* Private Function Prototypes
****************************************************************************/
* Private Data
****************************************************************************/
* Public Data
****************************************************************************/
* Private Functions
****************************************************************************/
* Name: open_device
****************************************************************************/
static int open_device(FAR struct input_device_s *dev)
{
GETEVENT_INFO("opening %s\n", dev->path);
dev->fd = open(dev->path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (dev->fd < 0)
{
GETEVENT_INFO("open %s failed, errno: %d\n", dev->path, errno);
return -errno;
}
if (dev->init_cb)
{
return dev->init_cb(dev);
}
return 0;
}
* Name: touch_init
****************************************************************************/
static int touch_init(FAR struct input_device_s *dev)
{
FAR struct touch_priv_s *priv;
uint8_t maxpoint;
int ret;
ret = ioctl(dev->fd, TSIOC_GETMAXPOINTS, &maxpoint);
if (ret < 0)
{
GETEVENT_INFO("ioctl GETMAXPOINTS failed: %d, "
"errno: %d\n", ret, errno);
return -errno;
}
priv = calloc(1, sizeof(struct touch_priv_s) +
SIZEOF_TOUCH_SAMPLE_S(maxpoint));
if (!priv)
{
GETEVENT_INFO("Memory allocation failed for touch_priv_s\n");
return -ENOMEM;
}
priv->maxpoint = maxpoint;
dev->priv = priv;
GETEVENT_INFO("ioctl TSIOC_GETMAXPOINTS: %d\n", maxpoint);
return ret;
}
* Name: read_mouse_event
****************************************************************************/
static void read_mouse_event(FAR struct input_device_s *dev)
{
struct mouse_report_s sample;
ssize_t nbytes;
nbytes = read(dev->fd, &sample, sizeof(struct mouse_report_s));
if (nbytes == sizeof(struct mouse_report_s))
{
GETEVENT_INFO("mouse event: %s\n", dev->path);
GETEVENT_INFO(" buttons : %02" PRIx8 "\n", sample.buttons);
GETEVENT_INFO(" x : %d\n", sample.x);
GETEVENT_INFO(" y : %d\n", sample.y);
#ifdef CONFIG_INPUT_MOUSE_WHEEL
GETEVENT_INFO(" wheel : %d\n", sample.wheel);
#endif
}
}
* Name: read_touch_event
****************************************************************************/
static void read_touch_event(FAR struct input_device_s *dev)
{
FAR struct touch_priv_s *priv = (FAR struct touch_priv_s *)dev->priv;
ssize_t nbytes;
size_t i;
nbytes = read(dev->fd, priv->sample,
SIZEOF_TOUCH_SAMPLE_S(priv->maxpoint));
if (nbytes == SIZEOF_TOUCH_SAMPLE_S(priv->maxpoint))
{
GETEVENT_INFO("touch event: %s\n", dev->path);
GETEVENT_INFO(" npoints : %" PRId32 "\n", priv->sample->npoints);
for (i = 0; i < priv->maxpoint; i++)
{
if (priv->sample->point[i].flags == 0)
{
break;
}
GETEVENT_INFO("Point : %d\n", priv->sample->point[i].id);
GETEVENT_INFO(" flags : %02x\n", priv->sample->point[i].flags);
GETEVENT_INFO(" x : %d\n", priv->sample->point[i].x);
GETEVENT_INFO(" y : %d\n", priv->sample->point[i].y);
#ifdef CONFIG_GRAPHICS_INPUT_GETEVENT_DETAIL_INFO
GETEVENT_INFO(" h : %d\n", priv->sample->point[i].h);
GETEVENT_INFO(" w : %d\n", priv->sample->point[i].w);
GETEVENT_INFO(" pressure : %d\n",
priv->sample->point[i].pressure);
#endif
GETEVENT_INFO(" timestamp : %" PRIu64"\n",
priv->sample->point[i].timestamp);
}
}
}
* Name: read_keyboard_event
****************************************************************************/
static void read_keyboard_event(FAR struct input_device_s *dev)
{
struct keyboard_event_s sample;
ssize_t nbytes;
nbytes = read(dev->fd, &sample, sizeof(struct keyboard_event_s));
if (nbytes == sizeof(struct keyboard_event_s))
{
GETEVENT_INFO("keyboard event: %s\n", dev->path);
GETEVENT_INFO(" type : %" PRIu32 "\n", sample.type);
GETEVENT_INFO(" code : %" PRIu32 "\n", sample.code);
}
}
* Name: cleanup_input_devices
****************************************************************************/
static void cleanup_input_devices(FAR struct input_devices_ctx_s *ctx)
{
FAR struct input_device_s *dev = ctx->head;
FAR struct input_device_s *next;
while (dev)
{
next = dev->next;
if (dev->fd >= 0)
{
close(dev->fd);
}
free(dev->priv);
free(dev);
dev = next;
}
ctx->head = NULL;
}
* Name: signal_handler
****************************************************************************/
static void
signal_handler(int signum, FAR siginfo_t *info, FAR void *context)
{
FAR volatile sig_atomic_t *running = info->si_user;
*running = 0;
}
* Name: run_event_loop
****************************************************************************/
static void run_event_loop(FAR struct input_devices_ctx_s *ctx)
{
FAR struct input_device_s *dev;
FAR struct pollfd *fds = NULL;
volatile sig_atomic_t running = 1;
struct sigaction sa;
int fd_count = 0;
int timeout = 500;
int i = 0;
int ret;
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_user = (FAR void *)&running;
sigaction(SIGINT, &sa, NULL);
for (dev = ctx->head; dev; dev = dev->next)
{
if (dev->fd >= 0)
{
fd_count++;
}
}
fds = calloc(fd_count, sizeof(struct pollfd));
if (!fds)
{
GETEVENT_INFO("Memory allocation failed for fds\n");
return;
}
for (dev = ctx->head; dev; dev = dev->next)
{
if (dev->fd >= 0)
{
fds[i].fd = dev->fd;
fds[i].events = POLLIN;
fds[i].revents = 0;
i++;
}
}
while (running)
{
ret = poll(fds, fd_count, timeout);
if (ret < 0 && errno != EINTR)
{
GETEVENT_INFO("poll error: %d\n", errno);
break;
}
for (i = 0; i < fd_count; i++)
{
if (!(fds[i].revents & POLLIN))
{
continue;
}
for (dev = ctx->head; dev; dev = dev->next)
{
if (dev->fd == fds[i].fd)
{
dev->read_cb(dev);
break;
}
}
}
}
free(fds);
}
* Name: show_usage
****************************************************************************/
static void show_usage(void)
{
GETEVENT_INFO("Usage: getevent [OPTIONS]\n");
GETEVENT_INFO("Options:\n");
GETEVENT_INFO(" -h Show this help message\n");
GETEVENT_INFO(" -m /dev/mouse -- mouse device path\n");
GETEVENT_INFO(" -t /dev/input -- touch device path\n");
GETEVENT_INFO(" -k /dev/keyboard -- keyboard device path\n");
GETEVENT_INFO("No options: Auto detect devices in /dev\n");
}
* Name: alloc_input_device
****************************************************************************/
static FAR struct input_device_s *
alloc_input_device(FAR struct input_devices_ctx_s *ctx,
FAR const char *path)
{
FAR struct input_device_s *dev;
FAR struct input_device_s *cur;
size_t path_len = strlen(path) + 1;
dev = calloc(1, sizeof(struct input_device_s) + path_len);
if (!dev)
{
GETEVENT_INFO("Memory allocation failed for device\n");
return NULL;
}
memcpy(dev->path, path, path_len);
if (!ctx->head)
{
ctx->head = dev;
}
else
{
cur = ctx->head;
while (cur->next)
{
cur = cur->next;
}
cur->next = dev;
}
return dev;
}
* Name: add_input_device
****************************************************************************/
static int add_input_device(FAR struct input_devices_ctx_s *ctx,
input_init_cb init_cb,
input_read_cb read_cb,
FAR const char *path)
{
FAR struct input_device_s *dev = alloc_input_device(ctx, path);
if (!dev)
{
return -ENOMEM;
}
dev->fd = -1;
dev->init_cb = init_cb;
dev->read_cb = read_cb;
return open_device(dev);
}
* Name: detect_devices
****************************************************************************/
static int detect_devices(FAR struct input_devices_ctx_s *ctx)
{
FAR struct dirent *entry;
char path[PATH_MAX];
FAR DIR *dir;
int ret = 0;
dir = opendir("/dev");
if (!dir)
{
GETEVENT_INFO("Failed to open /dev directory, errno: %d\n", errno);
return -errno;
}
while ((entry = readdir(dir)))
{
if (entry->d_type == DT_CHR)
{
if (snprintf(path, sizeof(path), "/dev/%s", entry->d_name) < 0)
{
GETEVENT_INFO("Memory allocation failed for path\n");
continue;
}
if (strncmp(entry->d_name, "mouse", 5) == 0)
{
ret = add_input_device(ctx, NULL, read_mouse_event, path);
}
else if (strncmp(entry->d_name, "input", 5) == 0)
{
ret = add_input_device(ctx, touch_init, read_touch_event,
path);
}
else if (strncmp(entry->d_name, "kbd", 3) == 0)
{
ret = add_input_device(ctx, NULL, read_keyboard_event, path);
}
if (ret < 0)
{
break;
}
}
}
closedir(dir);
return ret;
}
* Name: parse_commandline
****************************************************************************/
static int parse_commandline(FAR struct input_devices_ctx_s *ctx,
int argc, FAR char **argv)
{
int ret = -EINVAL;
int ch;
if (argc == 1)
{
return detect_devices(ctx);
}
while ((ch = getopt(argc, argv, "hn:m:t:k:")) != -1)
{
switch (ch)
{
case 'm':
ret = add_input_device(ctx, NULL, read_mouse_event, optarg);
break;
case 't':
ret = add_input_device(ctx, touch_init, read_touch_event, optarg);
break;
case 'k':
ret = add_input_device(ctx, NULL, read_keyboard_event, optarg);
break;
case '?':
case 'h':
default:
show_usage();
break;
}
if (ret < 0)
{
break;
}
}
return ret;
}
* Name: main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
struct input_devices_ctx_s ctx;
int ret;
memset(&ctx, 0, sizeof(ctx));
ret = parse_commandline(&ctx, argc, argv);
if (ret < 0)
{
goto cleanup;
}
run_event_loop(&ctx);
cleanup:
cleanup_input_devices(&ctx);
GETEVENT_INFO("Terminating!\n");
return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}