382 lines
9.1 KiB
C
382 lines
9.1 KiB
C
/* $NetBSD: wsmoused.c,v 1.10 2003/03/05 10:51:43 jmmv Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Julio Merino.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. The name authors may not be used to endorse or promote products
|
|
* derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
|
|
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
|
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
#ifndef lint
|
|
__RCSID("$NetBSD: wsmoused.c,v 1.10 2003/03/05 10:51:43 jmmv Exp $");
|
|
#endif /* not lint */
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <sys/tty.h>
|
|
#include <dev/wscons/wsconsio.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <poll.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <syslog.h>
|
|
#include <unistd.h>
|
|
#include <util.h>
|
|
|
|
#include "pathnames.h"
|
|
#include "wsmoused.h"
|
|
|
|
#define IS_MOTION_EVENT(type) (((type) == WSCONS_EVENT_MOUSE_DELTA_X) || \
|
|
((type) == WSCONS_EVENT_MOUSE_DELTA_Y) || \
|
|
((type) == WSCONS_EVENT_MOUSE_DELTA_Z))
|
|
#define IS_BUTTON_EVENT(type) (((type) == WSCONS_EVENT_MOUSE_UP) || \
|
|
((type) == WSCONS_EVENT_MOUSE_DOWN))
|
|
|
|
static struct mouse mouse;
|
|
static char *PidFile = NULL;
|
|
static int XConsole = -1;
|
|
|
|
/*
|
|
* Show program usage information
|
|
*/
|
|
static void
|
|
usage(void)
|
|
{
|
|
(void)fprintf(stderr,
|
|
"Usage: %s [-d device] [-f config_file] [-n]\n",
|
|
getprogname());
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/*
|
|
* Handler for close signals
|
|
*/
|
|
static void
|
|
signal_terminate(int sig)
|
|
{
|
|
mouse_cursor_hide(&mouse);
|
|
config_free();
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* Open the mouse device (i.e. /dev/wsmouse). The argument secs
|
|
* specifies the number of seconds we must wait before opening the
|
|
* device. This is used when returning from X. See mouse_open_tty().
|
|
*/
|
|
static void
|
|
mouse_open_device(struct mouse *m, int secs)
|
|
{
|
|
if (m->fd != -1) return;
|
|
|
|
sleep(secs);
|
|
|
|
/* Open mouse file descriptor */
|
|
m->fd = open(m->device_name,
|
|
O_RDONLY | O_NONBLOCK, 0);
|
|
if (m->fd == -1) {
|
|
err(EXIT_FAILURE, "cannot open %s", m->device_name);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Prepare mouse file descriptors
|
|
*/
|
|
static void
|
|
open_files(void)
|
|
{
|
|
/* Open wsdisplay status device */
|
|
mouse.stat_fd = open(_PATH_TTYSTAT, O_RDONLY | O_NONBLOCK, 0);
|
|
if (mouse.stat_fd == -1)
|
|
err(EXIT_FAILURE, "cannot open %s", mouse.tstat_name);
|
|
|
|
mouse.fd = -1;
|
|
mouse_open_device(&mouse, 0);
|
|
|
|
/* Open FIFO, if wanted */
|
|
mouse.fifo_fd = -1;
|
|
if (mouse.fifo_name != NULL) {
|
|
mouse.fifo_fd = open(mouse.fifo_name, O_RDWR | O_NONBLOCK, 0);
|
|
if (mouse.fifo_fd == -1)
|
|
err(EXIT_FAILURE, "cannot open %s", mouse.fifo_name);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Mouse event loop
|
|
*/
|
|
static void
|
|
event_loop(void)
|
|
{
|
|
int res;
|
|
struct pollfd fds[2];
|
|
struct wscons_event event;
|
|
|
|
fds[0].fd = mouse.stat_fd;
|
|
fds[0].events = POLLIN;
|
|
|
|
for (;;) {
|
|
fds[1].fd = mouse.fd;
|
|
fds[1].events = POLLIN;
|
|
if (mouse.disabled)
|
|
res = poll(fds, 1, INFTIM);
|
|
else
|
|
res = poll(fds, 2, 300);
|
|
|
|
if (res < 0)
|
|
warn("failed to read from devices");
|
|
|
|
if (fds[0].revents & POLLIN) {
|
|
res = read(mouse.stat_fd, &event, sizeof(event));
|
|
if (res != sizeof(event))
|
|
warn("failed to read from mouse stat");
|
|
screen_event(&mouse, &event);
|
|
} else if (fds[1].revents & POLLIN) {
|
|
res = read(mouse.fd, &event, sizeof(event));
|
|
if (res != sizeof(event))
|
|
warn("failed to read from mouse");
|
|
|
|
if (mouse.fifo_fd >= 0) {
|
|
res = write(mouse.fifo_fd, &event,
|
|
sizeof(event));
|
|
if (res != sizeof(event))
|
|
warn("failed to write to fifo");
|
|
}
|
|
|
|
if (IS_MOTION_EVENT(event.type)) {
|
|
mouse_motion_event(&mouse, &event);
|
|
} else if (IS_BUTTON_EVENT(event.type)) {
|
|
mouse_button_event(&mouse, &event);
|
|
} else {
|
|
warn("unknown wsmouse event");
|
|
}
|
|
} else
|
|
if (!mouse.selecting) mouse_cursor_hide(&mouse);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initializes mouse structure coordinate information. The mouse will
|
|
* be displayed at the center of the screen at start.
|
|
*/
|
|
static void
|
|
mouse_init(void)
|
|
{
|
|
struct winsize ws;
|
|
struct wsdisplay_char ch;
|
|
int i;
|
|
|
|
/* Get terminal size */
|
|
if (ioctl(0, TIOCGWINSZ, &ws) < 0)
|
|
err(EXIT_FAILURE, "cannot get terminal size");
|
|
|
|
/* Open current tty */
|
|
ioctl(mouse.stat_fd, WSDISPLAYIO_GETACTIVESCREEN, &i);
|
|
mouse.tty_fd = -1;
|
|
mouse_open_tty(&mouse, i);
|
|
|
|
/* Check if the kernel has character functions */
|
|
ch.row = ch.col = 0;
|
|
if (ioctl(mouse.tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) < 0)
|
|
err(EXIT_FAILURE, "ioctl(WSDISPLAYIO_GETWSCHAR) failed");
|
|
|
|
mouse.max_row = ws.ws_row - 1;
|
|
mouse.max_col = ws.ws_col - 1;
|
|
mouse.row = mouse.max_row / 2;
|
|
mouse.col = mouse.max_col / 2;
|
|
mouse.count_row = 0;
|
|
mouse.count_col = 0;
|
|
mouse.cursor = 0;
|
|
mouse.selecting = 0;
|
|
}
|
|
|
|
/*
|
|
* Hides the mouse cursor
|
|
*/
|
|
void
|
|
mouse_cursor_hide(struct mouse *m)
|
|
{
|
|
if (!m->cursor) return;
|
|
char_invert(m, m->row, m->col);
|
|
m->cursor = 0;
|
|
}
|
|
|
|
/*
|
|
* Shows the mouse cursor
|
|
*/
|
|
void
|
|
mouse_cursor_show(struct mouse *m)
|
|
{
|
|
if (m->cursor) return;
|
|
char_invert(m, m->row, m->col);
|
|
m->cursor = 1;
|
|
}
|
|
|
|
/*
|
|
* Opens the specified tty (we want it for ioctl's). If tty_fd in
|
|
* mouse structure is -1, no close is performed. Otherwise, the old
|
|
* file descriptor is closed and the new one opened.
|
|
*/
|
|
void
|
|
mouse_open_tty(struct mouse *m, int ttyno)
|
|
{
|
|
char buf[20];
|
|
|
|
if (m->tty_fd >= 0) close(m->tty_fd);
|
|
if (ttyno == XConsole) {
|
|
m->disabled = 1;
|
|
(void)close(m->fd);
|
|
m->fd = -1;
|
|
return;
|
|
}
|
|
/* Open with delay. When returning from X, wsmoused keeps busy
|
|
some seconds so we have to wait. */
|
|
mouse_open_device(m, 5);
|
|
(void)snprintf(buf, sizeof(buf), _PATH_TTYPREFIX "%d", ttyno);
|
|
m->tty_fd = open(buf, O_RDONLY | O_NONBLOCK);
|
|
if (m->tty_fd < 0)
|
|
errx(EXIT_FAILURE, "cannot open %s", buf);
|
|
m->disabled = 0;
|
|
}
|
|
|
|
/*
|
|
* Flip the foreground and background colors on char at coordinates
|
|
*/
|
|
void
|
|
char_invert(struct mouse *m, size_t row, size_t col)
|
|
{
|
|
struct wsdisplay_char ch;
|
|
int t;
|
|
|
|
ch.row = row;
|
|
ch.col = col;
|
|
|
|
if (ioctl(m->tty_fd, WSDISPLAYIO_GETWSCHAR, &ch) == -1) {
|
|
warn("ioctl(WSDISPLAYIO_GETWSCHAR) failed");
|
|
return;
|
|
}
|
|
|
|
t = ch.foreground;
|
|
ch.foreground = ch.background;
|
|
ch.background = t;
|
|
|
|
if (ioctl(m->tty_fd, WSDISPLAYIO_PUTWSCHAR, &ch) == -1)
|
|
warn("ioctl(WSDISPLAYIO_PUTWSCHAR) failed");
|
|
}
|
|
|
|
/*
|
|
* Main function
|
|
*/
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
int opt, nodaemon = -1;
|
|
int needconf = 0;
|
|
char *conffile;
|
|
struct block *mode;
|
|
|
|
setprogname(argv[0]);
|
|
|
|
memset(&mouse, 0, sizeof(struct mouse));
|
|
conffile = _PATH_CONF;
|
|
|
|
/* Parse command line options */
|
|
while ((opt = getopt(argc, argv, "d:f:n")) != -1) {
|
|
switch (opt) {
|
|
case 'd': /* Mouse device name */
|
|
mouse.device_name = optarg;
|
|
break;
|
|
case 'f': /* Configuration file name */
|
|
needconf = 1;
|
|
conffile = optarg;
|
|
break;
|
|
case 'n': /* No daemon */
|
|
nodaemon = 1;
|
|
break;
|
|
default:
|
|
usage();
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
|
|
/* Read the configuration file and get our mode configuration */
|
|
config_read(conffile, needconf);
|
|
mode = config_get_mode("sel");
|
|
|
|
/* Set values according to the configuration file */
|
|
if (mouse.device_name == NULL)
|
|
mouse.device_name = block_get_propval(mode, "device",
|
|
_PATH_DEFAULT_MOUSE);
|
|
|
|
if (nodaemon == -1)
|
|
nodaemon = block_get_propval_int(mode, "nodaemon", 0);
|
|
|
|
mouse.slowdown_x = block_get_propval_int(mode, "slowdown_x", 0);
|
|
mouse.slowdown_y = block_get_propval_int(mode, "slowdown_y", 3);
|
|
mouse.tstat_name = block_get_propval(mode, "ttystat", _PATH_TTYSTAT);
|
|
XConsole = block_get_propval_int(mode, "xconsole", -1);
|
|
|
|
if (block_get_propval_int(mode, "lefthanded", 0)) {
|
|
mouse.but_select = 2;
|
|
mouse.but_paste = 0;
|
|
} else {
|
|
mouse.but_select = 0;
|
|
mouse.but_paste = 2;
|
|
}
|
|
|
|
open_files();
|
|
mouse_init();
|
|
mouse_sel_init();
|
|
|
|
/* Setup signal handlers */
|
|
(void)signal(SIGINT, signal_terminate);
|
|
(void)signal(SIGKILL, signal_terminate);
|
|
(void)signal(SIGQUIT, signal_terminate);
|
|
(void)signal(SIGTERM, signal_terminate);
|
|
|
|
if (!nodaemon) {
|
|
/* Become a daemon */
|
|
if (daemon(0, 0) == -1)
|
|
err(EXIT_FAILURE, "failed to become a daemon");
|
|
|
|
/* Create the pidfile, if wanted */
|
|
PidFile = block_get_propval(mode, "pidfile", NULL);
|
|
if (pidfile(PidFile) == -1)
|
|
warn("pidfile %s", PidFile);
|
|
}
|
|
event_loop();
|
|
|
|
/* NOTREACHED */
|
|
return EXIT_SUCCESS;
|
|
}
|