You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
5.8 KiB
C
182 lines
5.8 KiB
C
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <assert.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <error.h>
|
|
#include <time.h>
|
|
#include <linux/input.h>
|
|
#include <libevdev-1.0/libevdev/libevdev.h>
|
|
#include <linux/uinput.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <dirent.h>
|
|
#include "pdcfb.h"
|
|
|
|
/* Code to use the Linux 'evdev' system to read the mouse (and, eventually,
|
|
keyboard) in the console. Built largely from information at
|
|
|
|
https://thehackerdiary.wordpress.com/2017/04/21/exploring-devinput-1/
|
|
https://stackoverflow.com/questions/26693280/linux-uinput-simple-example /
|
|
https://cgit.freedesktop.org/evtest/tree/evtest.c
|
|
|
|
Mouse and keyboard data can be found in one of the /dev/input/event# files. The
|
|
only way I've found to determine which files to use is to look at all
|
|
of them sequentially until you find one that supports the BTN_LEFT (left
|
|
mouse button) event for the mouse, or a KEY_A event for the keyboard.
|
|
(A one-button mouse returns a left click.)
|
|
|
|
Also note that to get this access, you must be a member of the 'input'
|
|
group (or run with root privileges, but that'd be overdoing things.) */
|
|
|
|
#define bits_per_long (sizeof( long) << 3)
|
|
#define test_bit(bit, array) ((array[bit / bits_per_long] >> (bit % bits_per_long)) & 1)
|
|
|
|
/* Unfortunately, Curses has a _lot_ of overlapping #defines with the
|
|
Linux input system. So we can't #include <curses.h> here. Instead, the
|
|
following #defines are cherry-picked. If they're ever re-defined in Curses,
|
|
chaos will ensue. */
|
|
|
|
#define BUTTON_RELEASED 0x0000
|
|
#define BUTTON_PRESSED 0x0001
|
|
#define BUTTON_MOVED 0x0005 /* PDCurses */
|
|
#define PDC_MOUSE_WHEEL_UP 0x0020
|
|
#define PDC_MOUSE_WHEEL_DOWN 0x0040
|
|
#define PDC_MOUSE_WHEEL_LEFT 0x0080
|
|
#define PDC_MOUSE_WHEEL_RIGHT 0x0100
|
|
|
|
#define PDC_KEY_MODIFIER_SHIFT 1
|
|
#define PDC_KEY_MODIFIER_CONTROL 2
|
|
#define PDC_KEY_MODIFIER_ALT 4
|
|
#define PDC_KEY_MODIFIER_NUMLOCK 8
|
|
#define PDC_KEY_MODIFIER_REPEAT 16
|
|
|
|
|
|
static int _get_mouse_or_keyboard_fds( int *return_fds, const int is_keyboard)
|
|
{
|
|
int fd, n_found = 0;
|
|
const char *directory = "/dev/input";
|
|
DIR *dir_ptr = opendir( directory);
|
|
struct dirent *direntp;
|
|
|
|
if( !dir_ptr)
|
|
return( -1);
|
|
while( NULL != (direntp = readdir( dir_ptr)))
|
|
if( !memcmp( direntp->d_name, "event", 5))
|
|
{
|
|
unsigned long bits[KEY_MAX / sizeof( long) + 1];
|
|
char full_name[60];
|
|
|
|
strcpy( full_name, directory);
|
|
strcat( full_name, "/");
|
|
assert( strlen( direntp->d_name) < 30);
|
|
strcat( full_name, direntp->d_name);
|
|
fd = open( full_name, O_RDONLY | O_NONBLOCK);
|
|
assert( fd > 0);
|
|
if( fd > 0)
|
|
{
|
|
memset( bits, 0, sizeof( bits));
|
|
ioctl(fd, EVIOCGBIT( 0, EV_MAX), bits);
|
|
if( test_bit( EV_KEY, bits))
|
|
{
|
|
const int bit_to_test = (is_keyboard ? KEY_A : BTN_LEFT);
|
|
|
|
ioctl( fd, EVIOCGBIT( EV_KEY, KEY_MAX), bits);
|
|
|
|
if( test_bit( bit_to_test, bits))
|
|
return_fds[n_found++] = fd;
|
|
}
|
|
else
|
|
close( fd);
|
|
}
|
|
}
|
|
closedir( dir_ptr);
|
|
return n_found;
|
|
}
|
|
|
|
int PDC_get_modifiers( void)
|
|
{
|
|
static int n_fds = -1, fds[20];
|
|
int i;
|
|
static int modifiers = 0;
|
|
|
|
if( n_fds == -1)
|
|
n_fds = _get_mouse_or_keyboard_fds( fds, 1);
|
|
for( i = 0; i < n_fds; i++)
|
|
{
|
|
struct input_event ev = {0};
|
|
|
|
while( read(fds[i], &ev, sizeof(ev)) == sizeof( ev))
|
|
if( EV_KEY == ev.type && (ev.value == 0 || ev.value == 1))
|
|
{
|
|
int mask;
|
|
|
|
switch( ev.code)
|
|
{
|
|
case KEY_LEFTSHIFT:
|
|
case KEY_RIGHTSHIFT:
|
|
mask = PDC_KEY_MODIFIER_SHIFT;
|
|
break;
|
|
case KEY_LEFTALT:
|
|
case KEY_RIGHTALT:
|
|
mask = PDC_KEY_MODIFIER_ALT;
|
|
break;
|
|
case KEY_LEFTCTRL:
|
|
case KEY_RIGHTCTRL:
|
|
mask = PDC_KEY_MODIFIER_CONTROL;
|
|
break;
|
|
default:
|
|
mask = 0;
|
|
}
|
|
if( mask)
|
|
{
|
|
if( ev.value)
|
|
modifiers |= mask;
|
|
else
|
|
modifiers &= ~mask;
|
|
}
|
|
}
|
|
}
|
|
return( modifiers);
|
|
}
|
|
|
|
int PDC_update_mouse( int *button)
|
|
{
|
|
static int n_fds = -1, fds[20];
|
|
int i, rval = -1;
|
|
|
|
if( n_fds == -1)
|
|
n_fds = _get_mouse_or_keyboard_fds( fds, 0);
|
|
for( i = 0; rval < 0 && i < n_fds; i++)
|
|
{
|
|
struct input_event ev = {0};
|
|
|
|
while( rval < 0 && sizeof( ev) == read(fds[i], &ev, sizeof(ev)))
|
|
if( EV_REL == ev.type &&
|
|
(ev.code == REL_X || ev.code == REL_Y))
|
|
{
|
|
if( ev.code == REL_X)
|
|
PDC_mouse_x += ev.value;
|
|
else if( ev.code == REL_Y)
|
|
PDC_mouse_y += ev.value;
|
|
/* else it's a scroll-wheel event */
|
|
rval = BUTTON_MOVED;
|
|
}
|
|
else if( EV_KEY == ev.type &&
|
|
ev.code >= BTN_LEFT && ev.code <= BTN_TASK)
|
|
{
|
|
*button = ev.code - BTN_LEFT + 1;
|
|
if( *button == 2 || *button == 3) /* Linux input system swaps */
|
|
*button = 5 - *button; /* these buttons relative to curses */
|
|
rval = (ev.value ? BUTTON_PRESSED : BUTTON_RELEASED);
|
|
}
|
|
else if( EV_REL == ev.type && ev.code == REL_WHEEL_HI_RES)
|
|
rval = (ev.value > 0 ? PDC_MOUSE_WHEEL_UP : PDC_MOUSE_WHEEL_DOWN);
|
|
else if( EV_REL == ev.type && ev.code == REL_HWHEEL_HI_RES)
|
|
rval = (ev.value > 0 ? PDC_MOUSE_WHEEL_RIGHT : PDC_MOUSE_WHEEL_LEFT);
|
|
}
|
|
return( rval);
|
|
}
|