You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1521 lines
31 KiB
1521 lines
31 KiB
/* -- uinput.c -- */
|
|
|
|
#include "x11vnc.h"
|
|
#include "cleanup.h"
|
|
#include "scan.h"
|
|
#include "xinerama.h"
|
|
#include "screen.h"
|
|
#include "pointer.h"
|
|
#include "keyboard.h"
|
|
#include "allowed_input_t.h"
|
|
|
|
#if LIBVNCSERVER_HAVE_SYS_IOCTL_H
|
|
#if LIBVNCSERVER_HAVE_LINUX_INPUT_H
|
|
#if LIBVNCSERVER_HAVE_LINUX_UINPUT_H
|
|
#define UINPUT_OK
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef UINPUT_OK
|
|
#include <sys/ioctl.h>
|
|
#include <linux/input.h>
|
|
#include <linux/uinput.h>
|
|
|
|
#if !defined(EV_SYN) || !defined(SYN_REPORT)
|
|
#undef UINPUT_OK
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
int check_uinput(void);
|
|
int initialize_uinput(void);
|
|
int set_uinput_accel(char *str);
|
|
int set_uinput_thresh(char *str);
|
|
void set_uinput_reset(int ms);
|
|
void set_uinput_always(int);
|
|
void set_uinput_touchscreen(int);
|
|
void set_uinput_abs(int);
|
|
char *get_uinput_accel();
|
|
char *get_uinput_thresh();
|
|
int get_uinput_reset();
|
|
int get_uinput_always();
|
|
int get_uinput_touchscreen();
|
|
int get_uinput_abs();
|
|
void parse_uinput_str(char *str);
|
|
void uinput_pointer_command(int mask, int x, int y, rfbClientPtr client);
|
|
void uinput_key_command(int down, int keysym, rfbClientPtr client);
|
|
|
|
static void init_key_tracker(void);
|
|
static int mod_is_down(void);
|
|
static int key_is_down(void);
|
|
static void set_uinput_accel_xy(double fx, double fy);
|
|
static void shutdown_uinput(void);
|
|
static void ptr_move(int dx, int dy);
|
|
static void ptr_rel(int dx, int dy);
|
|
static void button_click(int down, int btn);
|
|
static int lookup_code(int keysym);
|
|
|
|
static int fd = -1;
|
|
static int db = 0;
|
|
static int bmask = 0;
|
|
|
|
static char *injectable = NULL;
|
|
static char *uinput_dev = NULL;
|
|
static int uinput_touchscreen = 0;
|
|
static int uinput_abs = 0;
|
|
static int abs_x = 0, abs_y = 0;
|
|
|
|
static char *devs[] = {
|
|
"/dev/misc/uinput",
|
|
"/dev/input/uinput",
|
|
"/dev/uinput",
|
|
NULL
|
|
};
|
|
|
|
|
|
/*
|
|
* User may need to do:
|
|
modprode uinput
|
|
mknod /dev/input/uinput c 10 223
|
|
*/
|
|
|
|
int check_uinput(void) {
|
|
int i;
|
|
#ifndef UINPUT_OK
|
|
return 0;
|
|
#else
|
|
if (UT.release) {
|
|
int maj, min;
|
|
/* guard against linux 2.4 */
|
|
if (sscanf(UT.release, "%d.%d.", &maj, &min) == 2) {
|
|
if (maj < 2) {
|
|
return 0;
|
|
} else if (maj == 2) {
|
|
/* hmmm IPAQ 2.4.19-rmk6-pxa1-hh37 works... */
|
|
#if 0
|
|
if (min < 6) {
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
fd = -1;
|
|
i = 0;
|
|
while (devs[i] != NULL) {
|
|
if ( (fd = open(devs[i++], O_RDWR)) >= 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (fd < 0) {
|
|
return 0;
|
|
}
|
|
close(fd);
|
|
fd = -1;
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
static int key_pressed[256];
|
|
static int key_ismod[256];
|
|
|
|
static void init_key_tracker(void) {
|
|
int i;
|
|
for (i = 0; i < 256; i++) {
|
|
key_pressed[i] = 0;
|
|
key_ismod[i] = 0;
|
|
}
|
|
i = lookup_code(XK_Shift_L); if (0<=i && i<256) key_ismod[i] = 1;
|
|
i = lookup_code(XK_Shift_R); if (0<=i && i<256) key_ismod[i] = 1;
|
|
i = lookup_code(XK_Control_L); if (0<=i && i<256) key_ismod[i] = 1;
|
|
i = lookup_code(XK_Control_R); if (0<=i && i<256) key_ismod[i] = 1;
|
|
i = lookup_code(XK_Alt_L); if (0<=i && i<256) key_ismod[i] = 1;
|
|
i = lookup_code(XK_Alt_R); if (0<=i && i<256) key_ismod[i] = 1;
|
|
i = lookup_code(XK_Meta_L); if (0<=i && i<256) key_ismod[i] = 1;
|
|
i = lookup_code(XK_Meta_R); if (0<=i && i<256) key_ismod[i] = 1;
|
|
}
|
|
|
|
static int mod_is_down(void) {
|
|
int i;
|
|
if (0) {key_is_down();}
|
|
for (i = 0; i < 256; i++) {
|
|
if (key_pressed[i] && key_ismod[i]) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int key_is_down(void) {
|
|
int i;
|
|
for (i = 0; i < 256; i++) {
|
|
if (key_pressed[i]) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void shutdown_uinput(void) {
|
|
#ifdef UINPUT_OK
|
|
ioctl(fd, UI_DEV_DESTROY);
|
|
#endif
|
|
}
|
|
|
|
int initialize_uinput(void) {
|
|
#ifndef UINPUT_OK
|
|
return 0;
|
|
#else
|
|
int i;
|
|
struct uinput_user_dev udev;
|
|
|
|
if (fd >= 0) {
|
|
shutdown_uinput();
|
|
close(fd);
|
|
fd = -1;
|
|
}
|
|
|
|
if (getenv("X11VNC_UINPUT_DEBUG")) {
|
|
db = atoi(getenv("X11VNC_UINPUT_DEBUG"));
|
|
rfbLog("set uinput debug to: %d\n", db);
|
|
}
|
|
|
|
init_key_tracker();
|
|
|
|
if (uinput_dev) {
|
|
fd = open(uinput_dev, O_RDWR);
|
|
rfbLog("initialize_uinput: using: %s %d\n", uinput_dev, fd);
|
|
} else {
|
|
i = 0;
|
|
while (devs[i] != NULL) {
|
|
if ( (fd = open(devs[i], O_RDWR)) >= 0) {
|
|
rfbLog("initialize_uinput: using: %s %d\n",
|
|
devs[i], fd);
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
if (fd < 0) {
|
|
rfbLog("initialize_uinput: could not open an uinput device.\n");
|
|
rfbLogPerror("open");
|
|
clean_up_exit(1);
|
|
}
|
|
|
|
memset(&udev, 0, sizeof(udev));
|
|
|
|
strncpy(udev.name, "x11vnc injector", UINPUT_MAX_NAME_SIZE);
|
|
|
|
udev.id.bustype = BUS_USB; /* Matters? */
|
|
udev.id.version = 4;
|
|
|
|
ioctl(fd, UI_SET_EVBIT, EV_REL);
|
|
ioctl(fd, UI_SET_RELBIT, REL_X);
|
|
ioctl(fd, UI_SET_RELBIT, REL_Y);
|
|
|
|
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
|
|
|
for (i=0; i < 256; i++) {
|
|
ioctl(fd, UI_SET_KEYBIT, i);
|
|
}
|
|
|
|
ioctl(fd, UI_SET_KEYBIT, BTN_MOUSE);
|
|
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
|
|
ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
|
|
ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
|
|
ioctl(fd, UI_SET_KEYBIT, BTN_FORWARD);
|
|
ioctl(fd, UI_SET_KEYBIT, BTN_BACK);
|
|
|
|
if (uinput_touchscreen) {
|
|
ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
|
|
rfbLog("uinput: touchscreen enabled.\n");
|
|
}
|
|
if (uinput_touchscreen || uinput_abs) {
|
|
int gw = abs_x, gh = abs_y;
|
|
if (! gw || ! gh) {
|
|
gw = fb_x; gh = fb_y;
|
|
}
|
|
if (! gw || ! gh) {
|
|
gw = dpy_x; gh = dpy_y;
|
|
}
|
|
abs_x = gw;
|
|
abs_y = gh;
|
|
ioctl(fd, UI_SET_EVBIT, EV_ABS);
|
|
ioctl(fd, UI_SET_ABSBIT, ABS_X);
|
|
ioctl(fd, UI_SET_ABSBIT, ABS_Y);
|
|
udev.absmin[ABS_X] = 0;
|
|
udev.absmax[ABS_X] = gw;
|
|
udev.absfuzz[ABS_X] = 0;
|
|
udev.absflat[ABS_X] = 0;
|
|
udev.absmin[ABS_Y] = 0;
|
|
udev.absmax[ABS_Y] = gh;
|
|
udev.absfuzz[ABS_Y] = 0;
|
|
udev.absflat[ABS_Y] = 0;
|
|
rfbLog("uinput: absolute pointer enabled at %dx%d.\n", abs_x, abs_y);
|
|
set_uinput_accel_xy(1.0, 1.0);
|
|
}
|
|
|
|
write(fd, &udev, sizeof(udev));
|
|
|
|
if (ioctl(fd, UI_DEV_CREATE) != 0) {
|
|
rfbLog("ioctl(fd, UI_DEV_CREATE) failed.\n");
|
|
rfbLogPerror("ioctl");
|
|
close(fd);
|
|
clean_up_exit(1);
|
|
}
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
/* these defaults are based on qt-embedded 7/2006 */
|
|
static double fudge_x = 0.5; /* accel=2.0 */
|
|
static double fudge_y = 0.5;
|
|
|
|
static int thresh = 5;
|
|
static int thresh_or = 1;
|
|
|
|
static double resid_x = 0.0;
|
|
static double resid_y = 0.0;
|
|
|
|
static double zero_delay = 0.15;
|
|
static double last_button_click = 0.0;
|
|
|
|
static int uinput_always = 0;
|
|
|
|
static void set_uinput_accel_xy(double fx, double fy) {
|
|
fudge_x = 1.0/fx;
|
|
fudge_y = 1.0/fy;
|
|
rfbLog("set_uinput_accel: fx=%.5f fy=%.5f\n", fx, fy);
|
|
rfbLog("set_uinput_accel: ix=%.5f iy=%.5f\n", fudge_x, fudge_y);
|
|
}
|
|
|
|
static char *uinput_accel_str = NULL;
|
|
static char *uinput_thresh_str = NULL;
|
|
|
|
int set_uinput_accel(char *str) {
|
|
double fx, fy;
|
|
rfbLog("set_uinput_accel: str=%s\n", str);
|
|
if (sscanf(str, "%lf+%lf", &fx, &fy) == 2) {
|
|
set_uinput_accel_xy(fx, fy);
|
|
} else if (sscanf(str, "%lf", &fx) == 1) {
|
|
set_uinput_accel_xy(fx, fx);
|
|
} else {
|
|
rfbLog("invalid UINPUT accel= option: %s\n", str);
|
|
return 0;
|
|
}
|
|
if (uinput_accel_str) {
|
|
free(uinput_accel_str);
|
|
}
|
|
uinput_accel_str = strdup(str);
|
|
return 1;
|
|
}
|
|
|
|
int set_uinput_thresh(char *str) {
|
|
rfbLog("set_uinput_thresh: str=%s\n", str);
|
|
if (str[0] == '+') {
|
|
thresh_or = 0;
|
|
}
|
|
thresh = atoi(str);
|
|
if (uinput_thresh_str) {
|
|
free(uinput_thresh_str);
|
|
}
|
|
uinput_thresh_str = strdup(str);
|
|
return 1;
|
|
}
|
|
|
|
void set_uinput_reset(int ms) {
|
|
zero_delay = (double) ms/1000.;
|
|
rfbLog("set_uinput_reset: %d\n", ms);
|
|
}
|
|
|
|
void set_uinput_always(int a) {
|
|
uinput_always = a;
|
|
}
|
|
|
|
void set_uinput_touchscreen(int b) {
|
|
uinput_touchscreen = b;
|
|
}
|
|
|
|
void set_uinput_abs(int b) {
|
|
uinput_abs = b;
|
|
}
|
|
|
|
char *get_uinput_accel(void) {
|
|
return uinput_accel_str;
|
|
}
|
|
char *get_uinput_thresh(void) {
|
|
return uinput_thresh_str;
|
|
}
|
|
int get_uinput_reset(void) {
|
|
return (int) (1000 * zero_delay);
|
|
}
|
|
|
|
int get_uinput_always(void) {
|
|
return uinput_always;
|
|
}
|
|
|
|
int get_uinput_touchscreen(void) {
|
|
return uinput_touchscreen;
|
|
}
|
|
|
|
int get_uinput_abs(void) {
|
|
return uinput_abs;
|
|
}
|
|
|
|
void parse_uinput_str(char *in) {
|
|
char *p, *q, *str = strdup(in);
|
|
|
|
if (injectable) {
|
|
free(injectable);
|
|
injectable = strdup("KMB");
|
|
}
|
|
|
|
uinput_touchscreen = 0;
|
|
uinput_abs = 0;
|
|
abs_x = abs_y = 0;
|
|
|
|
p = strtok(str, ",");
|
|
while (p) {
|
|
if (p[0] == '/') {
|
|
if (uinput_dev) {
|
|
free(uinput_dev);
|
|
}
|
|
uinput_dev = strdup(p);
|
|
} else if (strstr(p, "accel=") == p) {
|
|
q = p + strlen("accel=");
|
|
if (! set_uinput_accel(q)) {
|
|
clean_up_exit(1);
|
|
}
|
|
} else if (strstr(p, "thresh=") == p) {
|
|
q = p + strlen("thresh=");
|
|
set_uinput_thresh(q);
|
|
|
|
} else if (strstr(p, "reset=") == p) {
|
|
int n = atoi(p + strlen("reset="));
|
|
set_uinput_reset(n);
|
|
} else if (strstr(p, "always=") == p) {
|
|
int n = atoi(p + strlen("always="));
|
|
set_uinput_always(n);
|
|
} else if (strpbrk(p, "KMB") == p) {
|
|
if (injectable) {
|
|
free(injectable);
|
|
}
|
|
injectable = strdup(p);
|
|
} else if (strstr(p, "touch") == p) {
|
|
int gw, gh;
|
|
q = strchr(p, '=');
|
|
set_uinput_touchscreen(1);
|
|
set_uinput_abs(1);
|
|
if (q && sscanf(q+1, "%dx%d", &gw, &gh) == 2) {
|
|
abs_x = gw;
|
|
abs_y = gh;
|
|
}
|
|
} else if (strstr(p, "abs") == p) {
|
|
int gw, gh;
|
|
q = strchr(p, '=');
|
|
set_uinput_abs(1);
|
|
if (q && sscanf(q+1, "%dx%d", &gw, &gh) == 2) {
|
|
abs_x = gw;
|
|
abs_y = gh;
|
|
}
|
|
|
|
} else {
|
|
rfbLog("invalid UINPUT option: %s\n", p);
|
|
clean_up_exit(1);
|
|
}
|
|
p = strtok(NULL, ",");
|
|
}
|
|
free(str);
|
|
}
|
|
|
|
static void ptr_move(int dx, int dy) {
|
|
#ifdef UINPUT_OK
|
|
struct input_event ev;
|
|
|
|
if (injectable && strchr(injectable, 'M') == NULL) {
|
|
return;
|
|
}
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
|
|
gettimeofday(&ev.time, NULL);
|
|
ev.type = EV_REL;
|
|
ev.code = REL_Y;
|
|
ev.value = dy;
|
|
write(fd, &ev, sizeof(ev));
|
|
|
|
ev.type = EV_REL;
|
|
ev.code = REL_X;
|
|
ev.value = dx;
|
|
write(fd, &ev, sizeof(ev));
|
|
|
|
ev.type = EV_SYN;
|
|
ev.code = SYN_REPORT;
|
|
ev.value = 0;
|
|
write(fd, &ev, sizeof(ev));
|
|
#endif
|
|
}
|
|
|
|
static void ptr_abs(int x, int y) {
|
|
#ifdef UINPUT_OK
|
|
struct input_event ev;
|
|
|
|
if (injectable && strchr(injectable, 'M') == NULL) {
|
|
return;
|
|
}
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
|
|
if (db) fprintf(stderr, "ptr_abs(%d, %d)\n", x, y);
|
|
|
|
gettimeofday(&ev.time, NULL);
|
|
ev.type = EV_ABS;
|
|
ev.code = ABS_Y;
|
|
ev.value = y;
|
|
write(fd, &ev, sizeof(ev));
|
|
|
|
ev.type = EV_ABS;
|
|
ev.code = ABS_X;
|
|
ev.value = x;
|
|
write(fd, &ev, sizeof(ev));
|
|
|
|
ev.type = EV_SYN;
|
|
ev.code = SYN_REPORT;
|
|
ev.value = 0;
|
|
write(fd, &ev, sizeof(ev));
|
|
#endif
|
|
}
|
|
|
|
static int inside_thresh(int dx, int dy, int thr) {
|
|
if (thresh_or) {
|
|
/* this is peeking at qt-embedded qmouse_qws.cpp */
|
|
if (nabs(dx) <= thresh && nabs(dy) <= thr) {
|
|
return 1;
|
|
}
|
|
} else {
|
|
/* this is peeking at xfree/xorg xf86Xinput.c */
|
|
if (nabs(dx) + nabs(dy) < thr) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void ptr_rel(int dx, int dy) {
|
|
int dxf, dyf, nx, ny, k;
|
|
int accel, thresh_high, thresh_mid;
|
|
double fx, fy;
|
|
static int try_threshes = -1;
|
|
|
|
if (try_threshes < 0) {
|
|
if (getenv("X11VNC_UINPUT_THRESHOLDS")) {
|
|
try_threshes = 1;
|
|
} else {
|
|
try_threshes = 0;
|
|
}
|
|
}
|
|
|
|
if (try_threshes) {
|
|
thresh_high = (int) ( (double) thresh/fudge_x );
|
|
thresh_mid = (int) ( (double) (thresh + thresh_high) / 2.0 );
|
|
|
|
if (thresh_mid <= thresh) {
|
|
thresh_mid = thresh + 1;
|
|
}
|
|
if (thresh_high <= thresh_mid) {
|
|
thresh_high = thresh_mid + 1;
|
|
}
|
|
|
|
if (inside_thresh(dx, dy, thresh)) {
|
|
accel = 0;
|
|
} else {
|
|
accel = 1;
|
|
}
|
|
nx = nabs(dx);
|
|
ny = nabs(dy);
|
|
|
|
} else {
|
|
accel = 1;
|
|
thresh_high = 0;
|
|
nx = ny = 1;
|
|
}
|
|
|
|
if (accel && nx + ny > 0 ) {
|
|
if (thresh_high > 0 && inside_thresh(dx, dy, thresh_high)) {
|
|
double alpha, t;
|
|
/* XXX */
|
|
if (1 || inside_thresh(dx, dy, thresh_mid)) {
|
|
t = thresh;
|
|
accel = 2;
|
|
} else {
|
|
accel = 3;
|
|
t = thresh_high;
|
|
}
|
|
if (thresh_or) {
|
|
if (nx > ny) {
|
|
fx = t;
|
|
fy = ((double) ny / (double) nx) * t;
|
|
} else {
|
|
fx = ((double) nx / (double) ny) * t;
|
|
fy = t;
|
|
}
|
|
dxf = (int) fx;
|
|
dyf = (int) fy;
|
|
fx = dx;
|
|
fy = dy;
|
|
|
|
} else {
|
|
if (t > 1) {
|
|
/* XXX */
|
|
t = t - 1.0;
|
|
}
|
|
alpha = t/(nx + ny);
|
|
fx = alpha * dx;
|
|
fy = alpha * dy;
|
|
dxf = (int) fx;
|
|
dyf = (int) fy;
|
|
fx = dx;
|
|
fy = dy;
|
|
}
|
|
} else {
|
|
fx = fudge_x * (double) dx;
|
|
fy = fudge_y * (double) dy;
|
|
dxf = (int) fx;
|
|
dyf = (int) fy;
|
|
}
|
|
} else {
|
|
fx = dx;
|
|
fy = dy;
|
|
dxf = dx;
|
|
dyf = dy;
|
|
}
|
|
|
|
if (db > 1) fprintf(stderr, "old dx dy: %d %d\n", dx, dy);
|
|
if (db > 1) fprintf(stderr, "new dx dy: %d %d accel: %d\n", dxf, dyf, accel);
|
|
|
|
ptr_move(dxf, dyf);
|
|
|
|
resid_x += fx - dxf;
|
|
resid_y += fy - dyf;
|
|
|
|
for (k = 0; k < 4; k++) {
|
|
if (resid_x <= -1.0 || resid_x >= 1.0 || resid_y <= -1.0 || resid_y >= 1.0) {
|
|
dxf = 0;
|
|
dyf = 0;
|
|
if (resid_x >= 1.0) {
|
|
dxf = (int) resid_x;
|
|
dxf = 1;
|
|
} else if (resid_x <= -1.0) {
|
|
dxf = -((int) (-resid_x));
|
|
dxf = -1;
|
|
}
|
|
resid_x -= dxf;
|
|
if (resid_y >= 1.0) {
|
|
dyf = (int) resid_y;
|
|
dyf = 1;
|
|
} else if (resid_y <= -1.0) {
|
|
dyf = -((int) (-resid_y));
|
|
dyf = -1;
|
|
}
|
|
resid_y -= dyf;
|
|
|
|
if (db > 1) fprintf(stderr, "*%s resid: dx dy: %d %d %f %f\n", accel > 1 ? "*" : " ", dxf, dyf, resid_x, resid_y);
|
|
if (0) {usleep(100*1000)};
|
|
ptr_move(dxf, dyf);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void button_click(int down, int btn) {
|
|
#ifdef UINPUT_OK
|
|
struct input_event ev;
|
|
|
|
if (injectable && strchr(injectable, 'B') == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (db) fprintf(stderr, "button_click: btn %d %s\n", btn, down ? "down" : "up");
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
gettimeofday(&ev.time, NULL);
|
|
ev.type = EV_KEY;
|
|
ev.value = down;
|
|
|
|
if (uinput_touchscreen) {
|
|
ev.code = BTN_TOUCH;
|
|
if (db) fprintf(stderr, "set code to BTN_TOUCH\n");
|
|
} else if (btn == 1) {
|
|
ev.code = BTN_LEFT;
|
|
} else if (btn == 2) {
|
|
ev.code = BTN_MIDDLE;
|
|
} else if (btn == 3) {
|
|
ev.code = BTN_RIGHT;
|
|
} else if (btn == 4) {
|
|
ev.code = BTN_FORWARD;
|
|
} else if (btn == 5) {
|
|
ev.code = BTN_BACK;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
write(fd, &ev, sizeof(ev));
|
|
|
|
ev.type = EV_SYN;
|
|
ev.code = SYN_REPORT;
|
|
ev.value = 0;
|
|
write(fd, &ev, sizeof(ev));
|
|
|
|
last_button_click = dnow();
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
void uinput_pointer_command(int mask, int x, int y, rfbClientPtr client) {
|
|
static int last_x = -1, last_y = -1, last_mask = -1;
|
|
static double last_zero = 0.0;
|
|
allowed_input_t input;
|
|
int do_reset, reset_lower_right = 1;
|
|
double now;
|
|
static int first = 1;
|
|
|
|
if (first) {
|
|
if (getenv("RESET_ALWAYS")) {
|
|
set_uinput_always(1);
|
|
} else {
|
|
set_uinput_always(0);
|
|
}
|
|
}
|
|
first = 0;
|
|
|
|
if (db) fprintf(stderr, "uinput_pointer_command: %d %d - %d\n", x, y, mask);
|
|
|
|
if (view_only) {
|
|
return;
|
|
}
|
|
get_allowed_input(client, &input);
|
|
|
|
now = dnow();
|
|
|
|
do_reset = 1;
|
|
if (mask || bmask) {
|
|
do_reset = 0; /* do not do reset if mouse button down */
|
|
} else if (! input.motion) {
|
|
do_reset = 0;
|
|
} else if (now < last_zero + zero_delay) {
|
|
do_reset = 0;
|
|
}
|
|
if (do_reset) {
|
|
if (mod_is_down()) {
|
|
do_reset = 0;
|
|
} else if (now < last_button_click + 0.25) {
|
|
do_reset = 0;
|
|
}
|
|
}
|
|
|
|
if (uinput_always && !mask && !bmask && input.motion) {
|
|
do_reset = 1;
|
|
}
|
|
if (uinput_abs) {
|
|
#if 0
|
|
/* this is a bad idea... need to do something else */
|
|
if (do_reset) {
|
|
ptr_abs(dpy_x, dpy_y);
|
|
usleep(10*1000);
|
|
ptr_abs(x, y);
|
|
usleep(10*1000);
|
|
}
|
|
#endif
|
|
do_reset = 0;
|
|
}
|
|
|
|
if (do_reset) {
|
|
static int first = 1;
|
|
|
|
if (zero_delay > 0.0 || first) {
|
|
/* try to push it to 0,0 */
|
|
int tx, ty, bigjump = 1;
|
|
|
|
if (reset_lower_right) {
|
|
tx = fudge_x * (dpy_x - last_x);
|
|
ty = fudge_y * (dpy_y - last_y);
|
|
} else {
|
|
tx = fudge_x * last_x;
|
|
ty = fudge_y * last_y;
|
|
}
|
|
|
|
tx += 50;
|
|
ty += 50;
|
|
|
|
if (bigjump) {
|
|
if (reset_lower_right) {
|
|
ptr_move(0, +ty);
|
|
usleep(2*1000);
|
|
ptr_move(+tx, +ty);
|
|
ptr_move(+tx, +ty);
|
|
} else {
|
|
ptr_move(0, -ty);
|
|
usleep(2*1000);
|
|
ptr_move(-tx, -ty);
|
|
ptr_move(-tx, -ty);
|
|
}
|
|
} else {
|
|
int i, step, n = 20;
|
|
step = dpy_x / n;
|
|
|
|
if (step < 100) step = 100;
|
|
|
|
for (i=0; i < n; i++) {
|
|
if (reset_lower_right) {
|
|
ptr_move(+step, +step);
|
|
} else {
|
|
ptr_move(-step, -step);
|
|
}
|
|
}
|
|
for (i=0; i < n; i++) {
|
|
if (reset_lower_right) {
|
|
ptr_move(+1, +1);
|
|
} else {
|
|
ptr_move(-1, -1);
|
|
}
|
|
}
|
|
}
|
|
if (db) {
|
|
if (reset_lower_right) {
|
|
fprintf(stderr, "uinput_pointer_command: reset -> (W,H) (%d,%d) [%d,%d]\n", x, y, tx, ty);
|
|
} else {
|
|
fprintf(stderr, "uinput_pointer_command: reset -> (0,0) (%d,%d) [%d,%d]\n", x, y, tx, ty);
|
|
}
|
|
}
|
|
|
|
/* rest a bit for system to absorb the change */
|
|
if (uinput_always) {
|
|
static double last_sleep = 0.0;
|
|
double nw = dnow(), delay = zero_delay;
|
|
if (delay <= 0.0) delay = 0.1;
|
|
if (nw > last_sleep + delay) {
|
|
usleep(10*1000);
|
|
last_sleep = nw;
|
|
} else {
|
|
usleep(1*1000);
|
|
}
|
|
|
|
} else {
|
|
usleep(30*1000);
|
|
}
|
|
|
|
/* now jump back out */
|
|
if (reset_lower_right) {
|
|
ptr_rel(x - dpy_x, y - dpy_y);
|
|
} else {
|
|
ptr_rel(x, y);
|
|
}
|
|
if (1) {usleep(10*1000)};
|
|
|
|
last_x = x;
|
|
last_y = y;
|
|
resid_x = 0.0;
|
|
resid_y = 0.0;
|
|
|
|
first = 0;
|
|
}
|
|
last_zero = dnow();
|
|
}
|
|
|
|
if (input.motion) {
|
|
if (x != last_x || y != last_y) {
|
|
if (uinput_abs) {
|
|
ptr_abs(x, y);
|
|
} else {
|
|
ptr_rel(x - last_x, y - last_y);
|
|
}
|
|
last_x = x;
|
|
last_y = y;
|
|
}
|
|
}
|
|
|
|
if (! input.button) {
|
|
return;
|
|
}
|
|
|
|
if (last_mask < 0) {
|
|
last_mask = mask;
|
|
}
|
|
|
|
if (db > 2) {
|
|
fprintf(stderr, "mask: %s\n", bitprint(mask, 16));
|
|
fprintf(stderr, "bmask: %s\n", bitprint(bmask, 16));
|
|
fprintf(stderr, "last_mask: %s\n", bitprint(last_mask, 16));
|
|
fprintf(stderr, "button_mask: %s\n", bitprint(button_mask, 16));
|
|
}
|
|
|
|
if (mask != last_mask) {
|
|
int i;
|
|
for (i=1; i <= MAX_BUTTONS; i++) {
|
|
int down, b = 1 << (i-1);
|
|
if ( (last_mask & b) == (mask & b)) {
|
|
continue;
|
|
}
|
|
if (mask & b) {
|
|
down = 1;
|
|
} else {
|
|
down = 0;
|
|
}
|
|
button_click(down, i);
|
|
}
|
|
last_mask = mask;
|
|
}
|
|
bmask = mask;
|
|
}
|
|
|
|
void uinput_key_command(int down, int keysym, rfbClientPtr client) {
|
|
#ifdef UINPUT_OK
|
|
struct input_event ev;
|
|
int scancode;
|
|
allowed_input_t input;
|
|
|
|
if (injectable && strchr(injectable, 'K') == NULL) {
|
|
return;
|
|
}
|
|
if (view_only) {
|
|
return;
|
|
}
|
|
get_allowed_input(client, &input);
|
|
if (! input.keystroke) {
|
|
return;
|
|
}
|
|
|
|
scancode = lookup_code(keysym);
|
|
|
|
if (scancode < 0) {
|
|
return;
|
|
}
|
|
if (db) fprintf(stderr, "uinput_key_command: %d -> %d %s\n", keysym, scancode, down ? "down" : "up");
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
gettimeofday(&ev.time, NULL);
|
|
ev.type = EV_KEY;
|
|
ev.code = (unsigned char) scancode;
|
|
ev.value = down;
|
|
|
|
write(fd, &ev, sizeof(ev));
|
|
|
|
ev.type = EV_SYN;
|
|
ev.code = SYN_REPORT;
|
|
ev.value = 0;
|
|
write(fd, &ev, sizeof(ev));
|
|
|
|
if (0 <= scancode && scancode < 256) {
|
|
key_pressed[scancode] = down ? 1 : 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static int lookup_code(int keysym) {
|
|
|
|
if (keysym == NoSymbol) {
|
|
return -1;
|
|
}
|
|
|
|
switch(keysym) {
|
|
#ifdef UINPUT_OK
|
|
case XK_Escape: return KEY_ESC;
|
|
case XK_1: return KEY_1;
|
|
case XK_2: return KEY_2;
|
|
case XK_3: return KEY_3;
|
|
case XK_4: return KEY_4;
|
|
case XK_5: return KEY_5;
|
|
case XK_6: return KEY_6;
|
|
case XK_7: return KEY_7;
|
|
case XK_8: return KEY_8;
|
|
case XK_9: return KEY_9;
|
|
case XK_0: return KEY_0;
|
|
case XK_exclam: return KEY_1;
|
|
case XK_at: return KEY_2;
|
|
case XK_numbersign: return KEY_3;
|
|
case XK_dollar: return KEY_4;
|
|
case XK_percent: return KEY_5;
|
|
case XK_asciicircum: return KEY_6;
|
|
case XK_ampersand: return KEY_7;
|
|
case XK_asterisk: return KEY_8;
|
|
case XK_parenleft: return KEY_9;
|
|
case XK_parenright: return KEY_0;
|
|
case XK_minus: return KEY_MINUS;
|
|
case XK_underscore: return KEY_MINUS;
|
|
case XK_equal: return KEY_EQUAL;
|
|
case XK_plus: return KEY_EQUAL;
|
|
case XK_BackSpace: return KEY_BACKSPACE;
|
|
case XK_Tab: return KEY_TAB;
|
|
case XK_q: return KEY_Q;
|
|
case XK_Q: return KEY_Q;
|
|
case XK_w: return KEY_W;
|
|
case XK_W: return KEY_W;
|
|
case XK_e: return KEY_E;
|
|
case XK_E: return KEY_E;
|
|
case XK_r: return KEY_R;
|
|
case XK_R: return KEY_R;
|
|
case XK_t: return KEY_T;
|
|
case XK_T: return KEY_T;
|
|
case XK_y: return KEY_Y;
|
|
case XK_Y: return KEY_Y;
|
|
case XK_u: return KEY_U;
|
|
case XK_U: return KEY_U;
|
|
case XK_i: return KEY_I;
|
|
case XK_I: return KEY_I;
|
|
case XK_o: return KEY_O;
|
|
case XK_O: return KEY_O;
|
|
case XK_p: return KEY_P;
|
|
case XK_P: return KEY_P;
|
|
case XK_braceleft: return KEY_LEFTBRACE;
|
|
case XK_braceright: return KEY_RIGHTBRACE;
|
|
case XK_bracketleft: return KEY_LEFTBRACE;
|
|
case XK_bracketright: return KEY_RIGHTBRACE;
|
|
case XK_Return: return KEY_ENTER;
|
|
case XK_Control_L: return KEY_LEFTCTRL;
|
|
case XK_a: return KEY_A;
|
|
case XK_A: return KEY_A;
|
|
case XK_s: return KEY_S;
|
|
case XK_S: return KEY_S;
|
|
case XK_d: return KEY_D;
|
|
case XK_D: return KEY_D;
|
|
case XK_f: return KEY_F;
|
|
case XK_F: return KEY_F;
|
|
case XK_g: return KEY_G;
|
|
case XK_G: return KEY_G;
|
|
case XK_h: return KEY_H;
|
|
case XK_H: return KEY_H;
|
|
case XK_j: return KEY_J;
|
|
case XK_J: return KEY_J;
|
|
case XK_k: return KEY_K;
|
|
case XK_K: return KEY_K;
|
|
case XK_l: return KEY_L;
|
|
case XK_L: return KEY_L;
|
|
case XK_semicolon: return KEY_SEMICOLON;
|
|
case XK_colon: return KEY_SEMICOLON;
|
|
case XK_apostrophe: return KEY_APOSTROPHE;
|
|
case XK_quotedbl: return KEY_APOSTROPHE;
|
|
case XK_grave: return KEY_GRAVE;
|
|
case XK_asciitilde: return KEY_GRAVE;
|
|
case XK_Shift_L: return KEY_LEFTSHIFT;
|
|
case XK_backslash: return KEY_BACKSLASH;
|
|
case XK_bar: return KEY_BACKSLASH;
|
|
case XK_z: return KEY_Z;
|
|
case XK_Z: return KEY_Z;
|
|
case XK_x: return KEY_X;
|
|
case XK_X: return KEY_X;
|
|
case XK_c: return KEY_C;
|
|
case XK_C: return KEY_C;
|
|
case XK_v: return KEY_V;
|
|
case XK_V: return KEY_V;
|
|
case XK_b: return KEY_B;
|
|
case XK_B: return KEY_B;
|
|
case XK_n: return KEY_N;
|
|
case XK_N: return KEY_N;
|
|
case XK_m: return KEY_M;
|
|
case XK_M: return KEY_M;
|
|
case XK_comma: return KEY_COMMA;
|
|
case XK_less: return KEY_COMMA;
|
|
case XK_period: return KEY_DOT;
|
|
case XK_greater: return KEY_DOT;
|
|
case XK_slash: return KEY_SLASH;
|
|
case XK_question: return KEY_SLASH;
|
|
case XK_Shift_R: return KEY_RIGHTSHIFT;
|
|
case XK_KP_Multiply: return KEY_KPASTERISK;
|
|
case XK_Alt_L: return KEY_LEFTALT;
|
|
case XK_space: return KEY_SPACE;
|
|
case XK_Caps_Lock: return KEY_CAPSLOCK;
|
|
case XK_F1: return KEY_F1;
|
|
case XK_F2: return KEY_F2;
|
|
case XK_F3: return KEY_F3;
|
|
case XK_F4: return KEY_F4;
|
|
case XK_F5: return KEY_F5;
|
|
case XK_F6: return KEY_F6;
|
|
case XK_F7: return KEY_F7;
|
|
case XK_F8: return KEY_F8;
|
|
case XK_F9: return KEY_F9;
|
|
case XK_F10: return KEY_F10;
|
|
case XK_Num_Lock: return KEY_NUMLOCK;
|
|
case XK_Scroll_Lock: return KEY_SCROLLLOCK;
|
|
case XK_KP_7: return KEY_KP7;
|
|
case XK_KP_8: return KEY_KP8;
|
|
case XK_KP_9: return KEY_KP9;
|
|
case XK_KP_Subtract: return KEY_KPMINUS;
|
|
case XK_KP_4: return KEY_KP4;
|
|
case XK_KP_5: return KEY_KP5;
|
|
case XK_KP_6: return KEY_KP6;
|
|
case XK_KP_Add: return KEY_KPPLUS;
|
|
case XK_KP_1: return KEY_KP1;
|
|
case XK_KP_2: return KEY_KP2;
|
|
case XK_KP_3: return KEY_KP3;
|
|
case XK_KP_0: return KEY_KP0;
|
|
case XK_KP_Decimal: return KEY_KPDOT;
|
|
case XK_F13: return KEY_F13;
|
|
case XK_F11: return KEY_F11;
|
|
case XK_F12: return KEY_F12;
|
|
case XK_F14: return KEY_F14;
|
|
case XK_F15: return KEY_F15;
|
|
case XK_F16: return KEY_F16;
|
|
case XK_F17: return KEY_F17;
|
|
case XK_F18: return KEY_F18;
|
|
case XK_F19: return KEY_F19;
|
|
case XK_F20: return KEY_F20;
|
|
case XK_KP_Enter: return KEY_KPENTER;
|
|
case XK_Control_R: return KEY_RIGHTCTRL;
|
|
case XK_KP_Divide: return KEY_KPSLASH;
|
|
case XK_Sys_Req: return KEY_SYSRQ;
|
|
case XK_Alt_R: return KEY_RIGHTALT;
|
|
case XK_Linefeed: return KEY_LINEFEED;
|
|
case XK_Home: return KEY_HOME;
|
|
case XK_Up: return KEY_UP;
|
|
case XK_Page_Up: return KEY_PAGEUP;
|
|
case XK_Left: return KEY_LEFT;
|
|
case XK_Right: return KEY_RIGHT;
|
|
case XK_End: return KEY_END;
|
|
case XK_Down: return KEY_DOWN;
|
|
case XK_Page_Down: return KEY_PAGEDOWN;
|
|
case XK_Insert: return KEY_INSERT;
|
|
case XK_Delete: return KEY_DELETE;
|
|
case XK_KP_Equal: return KEY_KPEQUAL;
|
|
case XK_Pause: return KEY_PAUSE;
|
|
case XK_F21: return KEY_F21;
|
|
case XK_F22: return KEY_F22;
|
|
case XK_F23: return KEY_F23;
|
|
case XK_F24: return KEY_F24;
|
|
case XK_KP_Separator: return KEY_KPCOMMA;
|
|
case XK_Meta_L: return KEY_LEFTMETA;
|
|
case XK_Meta_R: return KEY_RIGHTMETA;
|
|
case XK_Multi_key: return KEY_COMPOSE;
|
|
#endif
|
|
default: return -1;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
|
|
From /usr/include/linux/input.h
|
|
|
|
We maintain it here since it is such a painful mess.
|
|
|
|
Here is a little script to make it easier:
|
|
|
|
#!/usr/bin/perl
|
|
while (<>) {
|
|
$_ =~ s/-XK_/XK_/;
|
|
next unless /^XK_/;
|
|
chomp;
|
|
if (/^(\S+)(\s+)(\S+)/) {
|
|
$a = $1;
|
|
$t = $2;
|
|
$b = $3;
|
|
print "\tcase $a:${t}return $b;\n";
|
|
if ($a =~ /XK_[a-z]$/) {
|
|
$a = uc($a);
|
|
print "\tcase $a:${t}return $b;\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
This only handles US kbd, we would need a kbd database in general...
|
|
Ugh: parse dumpkeys(1) or -fookeys /usr/share/keymaps/i386/qwerty/dk.kmap.gz
|
|
|
|
XK_Escape KEY_ESC
|
|
XK_1 KEY_1
|
|
XK_2 KEY_2
|
|
XK_3 KEY_3
|
|
XK_4 KEY_4
|
|
XK_5 KEY_5
|
|
XK_6 KEY_6
|
|
XK_7 KEY_7
|
|
XK_8 KEY_8
|
|
XK_9 KEY_9
|
|
XK_0 KEY_0
|
|
-XK_exclam KEY_1
|
|
-XK_at KEY_2
|
|
-XK_numbersign KEY_3
|
|
-XK_dollar KEY_4
|
|
-XK_percent KEY_5
|
|
-XK_asciicircum KEY_6
|
|
-XK_ampersand KEY_7
|
|
-XK_asterisk KEY_8
|
|
-XK_parenleft KEY_9
|
|
-XK_parenright KEY_0
|
|
XK_minus KEY_MINUS
|
|
-XK_underscore KEY_MINUS
|
|
XK_equal KEY_EQUAL
|
|
-XK_plus KEY_EQUAL
|
|
XK_BackSpace KEY_BACKSPACE
|
|
XK_Tab KEY_TAB
|
|
XK_q KEY_Q
|
|
XK_w KEY_W
|
|
XK_e KEY_E
|
|
XK_r KEY_R
|
|
XK_t KEY_T
|
|
XK_y KEY_Y
|
|
XK_u KEY_U
|
|
XK_i KEY_I
|
|
XK_o KEY_O
|
|
XK_p KEY_P
|
|
XK_braceleft KEY_LEFTBRACE
|
|
XK_braceright KEY_RIGHTBRACE
|
|
-XK_bracketleft KEY_LEFTBRACE
|
|
-XK_bracketright KEY_RIGHTBRACE
|
|
XK_Return KEY_ENTER
|
|
XK_Control_L KEY_LEFTCTRL
|
|
XK_a KEY_A
|
|
XK_s KEY_S
|
|
XK_d KEY_D
|
|
XK_f KEY_F
|
|
XK_g KEY_G
|
|
XK_h KEY_H
|
|
XK_j KEY_J
|
|
XK_k KEY_K
|
|
XK_l KEY_L
|
|
XK_semicolon KEY_SEMICOLON
|
|
-XK_colon KEY_SEMICOLON
|
|
XK_apostrophe KEY_APOSTROPHE
|
|
-XK_quotedbl KEY_APOSTROPHE
|
|
XK_grave KEY_GRAVE
|
|
-XK_asciitilde KEY_GRAVE
|
|
XK_Shift_L KEY_LEFTSHIFT
|
|
XK_backslash KEY_BACKSLASH
|
|
-XK_bar KEY_BACKSLASH
|
|
XK_z KEY_Z
|
|
XK_x KEY_X
|
|
XK_c KEY_C
|
|
XK_v KEY_V
|
|
XK_b KEY_B
|
|
XK_n KEY_N
|
|
XK_m KEY_M
|
|
XK_comma KEY_COMMA
|
|
-XK_less KEY_COMMA
|
|
XK_period KEY_DOT
|
|
-XK_greater KEY_DOT
|
|
XK_slash KEY_SLASH
|
|
-XK_question KEY_SLASH
|
|
XK_Shift_R KEY_RIGHTSHIFT
|
|
XK_KP_Multiply KEY_KPASTERISK
|
|
XK_Alt_L KEY_LEFTALT
|
|
XK_space KEY_SPACE
|
|
XK_Caps_Lock KEY_CAPSLOCK
|
|
XK_F1 KEY_F1
|
|
XK_F2 KEY_F2
|
|
XK_F3 KEY_F3
|
|
XK_F4 KEY_F4
|
|
XK_F5 KEY_F5
|
|
XK_F6 KEY_F6
|
|
XK_F7 KEY_F7
|
|
XK_F8 KEY_F8
|
|
XK_F9 KEY_F9
|
|
XK_F10 KEY_F10
|
|
XK_Num_Lock KEY_NUMLOCK
|
|
XK_Scroll_Lock KEY_SCROLLLOCK
|
|
XK_KP_7 KEY_KP7
|
|
XK_KP_8 KEY_KP8
|
|
XK_KP_9 KEY_KP9
|
|
XK_KP_Subtract KEY_KPMINUS
|
|
XK_KP_4 KEY_KP4
|
|
XK_KP_5 KEY_KP5
|
|
XK_KP_6 KEY_KP6
|
|
XK_KP_Add KEY_KPPLUS
|
|
XK_KP_1 KEY_KP1
|
|
XK_KP_2 KEY_KP2
|
|
XK_KP_3 KEY_KP3
|
|
XK_KP_0 KEY_KP0
|
|
XK_KP_Decimal KEY_KPDOT
|
|
NoSymbol KEY_103RD
|
|
XK_F13 KEY_F13
|
|
NoSymbol KEY_102ND
|
|
XK_F11 KEY_F11
|
|
XK_F12 KEY_F12
|
|
XK_F14 KEY_F14
|
|
XK_F15 KEY_F15
|
|
XK_F16 KEY_F16
|
|
XK_F17 KEY_F17
|
|
XK_F18 KEY_F18
|
|
XK_F19 KEY_F19
|
|
XK_F20 KEY_F20
|
|
XK_KP_Enter KEY_KPENTER
|
|
XK_Control_R KEY_RIGHTCTRL
|
|
XK_KP_Divide KEY_KPSLASH
|
|
XK_Sys_Req KEY_SYSRQ
|
|
XK_Alt_R KEY_RIGHTALT
|
|
XK_Linefeed KEY_LINEFEED
|
|
XK_Home KEY_HOME
|
|
XK_Up KEY_UP
|
|
XK_Page_Up KEY_PAGEUP
|
|
XK_Left KEY_LEFT
|
|
XK_Right KEY_RIGHT
|
|
XK_End KEY_END
|
|
XK_Down KEY_DOWN
|
|
XK_Page_Down KEY_PAGEDOWN
|
|
XK_Insert KEY_INSERT
|
|
XK_Delete KEY_DELETE
|
|
NoSymbol KEY_MACRO
|
|
NoSymbol KEY_MUTE
|
|
NoSymbol KEY_VOLUMEDOWN
|
|
NoSymbol KEY_VOLUMEUP
|
|
NoSymbol KEY_POWER
|
|
XK_KP_Equal KEY_KPEQUAL
|
|
NoSymbol KEY_KPPLUSMINUS
|
|
XK_Pause KEY_PAUSE
|
|
XK_F21 KEY_F21
|
|
XK_F22 KEY_F22
|
|
XK_F23 KEY_F23
|
|
XK_F24 KEY_F24
|
|
XK_KP_Separator KEY_KPCOMMA
|
|
XK_Meta_L KEY_LEFTMETA
|
|
XK_Meta_R KEY_RIGHTMETA
|
|
XK_Multi_key KEY_COMPOSE
|
|
|
|
NoSymbol KEY_STOP
|
|
NoSymbol KEY_AGAIN
|
|
NoSymbol KEY_PROPS
|
|
NoSymbol KEY_UNDO
|
|
NoSymbol KEY_FRONT
|
|
NoSymbol KEY_COPY
|
|
NoSymbol KEY_OPEN
|
|
NoSymbol KEY_PASTE
|
|
NoSymbol KEY_FIND
|
|
NoSymbol KEY_CUT
|
|
NoSymbol KEY_HELP
|
|
NoSymbol KEY_MENU
|
|
NoSymbol KEY_CALC
|
|
NoSymbol KEY_SETUP
|
|
NoSymbol KEY_SLEEP
|
|
NoSymbol KEY_WAKEUP
|
|
NoSymbol KEY_FILE
|
|
NoSymbol KEY_SENDFILE
|
|
NoSymbol KEY_DELETEFILE
|
|
NoSymbol KEY_XFER
|
|
NoSymbol KEY_PROG1
|
|
NoSymbol KEY_PROG2
|
|
NoSymbol KEY_WWW
|
|
NoSymbol KEY_MSDOS
|
|
NoSymbol KEY_COFFEE
|
|
NoSymbol KEY_DIRECTION
|
|
NoSymbol KEY_CYCLEWINDOWS
|
|
NoSymbol KEY_MAIL
|
|
NoSymbol KEY_BOOKMARKS
|
|
NoSymbol KEY_COMPUTER
|
|
NoSymbol KEY_BACK
|
|
NoSymbol KEY_FORWARD
|
|
NoSymbol KEY_CLOSECD
|
|
NoSymbol KEY_EJECTCD
|
|
NoSymbol KEY_EJECTCLOSECD
|
|
NoSymbol KEY_NEXTSONG
|
|
NoSymbol KEY_PLAYPAUSE
|
|
NoSymbol KEY_PREVIOUSSONG
|
|
NoSymbol KEY_STOPCD
|
|
NoSymbol KEY_RECORD
|
|
NoSymbol KEY_REWIND
|
|
NoSymbol KEY_PHONE
|
|
NoSymbol KEY_ISO
|
|
NoSymbol KEY_CONFIG
|
|
NoSymbol KEY_HOMEPAGE
|
|
NoSymbol KEY_REFRESH
|
|
NoSymbol KEY_EXIT
|
|
NoSymbol KEY_MOVE
|
|
NoSymbol KEY_EDIT
|
|
NoSymbol KEY_SCROLLUP
|
|
NoSymbol KEY_SCROLLDOWN
|
|
NoSymbol KEY_KPLEFTPAREN
|
|
NoSymbol KEY_KPRIGHTPAREN
|
|
|
|
NoSymbol KEY_INTL1
|
|
NoSymbol KEY_INTL2
|
|
NoSymbol KEY_INTL3
|
|
NoSymbol KEY_INTL4
|
|
NoSymbol KEY_INTL5
|
|
NoSymbol KEY_INTL6
|
|
NoSymbol KEY_INTL7
|
|
NoSymbol KEY_INTL8
|
|
NoSymbol KEY_INTL9
|
|
NoSymbol KEY_LANG1
|
|
NoSymbol KEY_LANG2
|
|
NoSymbol KEY_LANG3
|
|
NoSymbol KEY_LANG4
|
|
NoSymbol KEY_LANG5
|
|
NoSymbol KEY_LANG6
|
|
NoSymbol KEY_LANG7
|
|
NoSymbol KEY_LANG8
|
|
NoSymbol KEY_LANG9
|
|
|
|
NoSymbol KEY_PLAYCD
|
|
NoSymbol KEY_PAUSECD
|
|
NoSymbol KEY_PROG3
|
|
NoSymbol KEY_PROG4
|
|
NoSymbol KEY_SUSPEND
|
|
NoSymbol KEY_CLOSE
|
|
NoSymbol KEY_PLAY
|
|
NoSymbol KEY_FASTFORWARD
|
|
NoSymbol KEY_BASSBOOST
|
|
NoSymbol KEY_PRINT
|
|
NoSymbol KEY_HP
|
|
NoSymbol KEY_CAMERA
|
|
NoSymbol KEY_SOUND
|
|
NoSymbol KEY_QUESTION
|
|
NoSymbol KEY_EMAIL
|
|
NoSymbol KEY_CHAT
|
|
NoSymbol KEY_SEARCH
|
|
NoSymbol KEY_CONNECT
|
|
NoSymbol KEY_FINANCE
|
|
NoSymbol KEY_SPORT
|
|
NoSymbol KEY_SHOP
|
|
NoSymbol KEY_ALTERASE
|
|
NoSymbol KEY_CANCEL
|
|
NoSymbol KEY_BRIGHTNESSDOWN
|
|
NoSymbol KEY_BRIGHTNESSUP
|
|
NoSymbol KEY_MEDIA
|
|
|
|
NoSymbol KEY_UNKNOWN
|
|
NoSymbol
|
|
NoSymbol BTN_MISC
|
|
NoSymbol BTN_0
|
|
NoSymbol BTN_1
|
|
NoSymbol BTN_2
|
|
NoSymbol BTN_3
|
|
NoSymbol BTN_4
|
|
NoSymbol BTN_5
|
|
NoSymbol BTN_6
|
|
NoSymbol BTN_7
|
|
NoSymbol BTN_8
|
|
NoSymbol BTN_9
|
|
NoSymbol
|
|
NoSymbol BTN_MOUSE
|
|
NoSymbol BTN_LEFT
|
|
NoSymbol BTN_RIGHT
|
|
NoSymbol BTN_MIDDLE
|
|
NoSymbol BTN_SIDE
|
|
NoSymbol BTN_EXTRA
|
|
NoSymbol BTN_FORWARD
|
|
NoSymbol BTN_BACK
|
|
NoSymbol BTN_TASK
|
|
NoSymbol
|
|
NoSymbol BTN_JOYSTICK
|
|
NoSymbol BTN_TRIGGER
|
|
NoSymbol BTN_THUMB
|
|
NoSymbol BTN_THUMB2
|
|
NoSymbol BTN_TOP
|
|
NoSymbol BTN_TOP2
|
|
NoSymbol BTN_PINKIE
|
|
NoSymbol BTN_BASE
|
|
NoSymbol BTN_BASE2
|
|
NoSymbol BTN_BASE3
|
|
NoSymbol BTN_BASE4
|
|
NoSymbol BTN_BASE5
|
|
NoSymbol BTN_BASE6
|
|
NoSymbol BTN_DEAD
|
|
|
|
NoSymbol BTN_GAMEPAD
|
|
NoSymbol BTN_A
|
|
NoSymbol BTN_B
|
|
NoSymbol BTN_C
|
|
NoSymbol BTN_X
|
|
NoSymbol BTN_Y
|
|
NoSymbol BTN_Z
|
|
NoSymbol BTN_TL
|
|
NoSymbol BTN_TR
|
|
NoSymbol BTN_TL2
|
|
NoSymbol BTN_TR2
|
|
NoSymbol BTN_SELECT
|
|
NoSymbol BTN_START
|
|
NoSymbol BTN_MODE
|
|
NoSymbol BTN_THUMBL
|
|
NoSymbol BTN_THUMBR
|
|
|
|
NoSymbol BTN_DIGI
|
|
NoSymbol BTN_TOOL_PEN
|
|
NoSymbol BTN_TOOL_RUBBER
|
|
NoSymbol BTN_TOOL_BRUSH
|
|
NoSymbol BTN_TOOL_PENCIL
|
|
NoSymbol BTN_TOOL_AIRBRUSH
|
|
NoSymbol BTN_TOOL_FINGER
|
|
NoSymbol BTN_TOOL_MOUSE
|
|
NoSymbol BTN_TOOL_LENS
|
|
NoSymbol BTN_TOUCH
|
|
NoSymbol BTN_STYLUS
|
|
NoSymbol BTN_STYLUS2
|
|
NoSymbol BTN_TOOL_DOUBLETAP
|
|
NoSymbol BTN_TOOL_TRIPLETAP
|
|
|
|
NoSymbol BTN_WHEEL
|
|
NoSymbol BTN_GEAR_DOWN
|
|
NoSymbol BTN_GEAR_UP
|
|
|
|
NoSymbol KEY_OK
|
|
NoSymbol KEY_SELECT
|
|
NoSymbol KEY_GOTO
|
|
NoSymbol KEY_CLEAR
|
|
NoSymbol KEY_POWER2
|
|
NoSymbol KEY_OPTION
|
|
NoSymbol KEY_INFO
|
|
NoSymbol KEY_TIME
|
|
NoSymbol KEY_VENDOR
|
|
NoSymbol KEY_ARCHIVE
|
|
NoSymbol KEY_PROGRAM
|
|
NoSymbol KEY_CHANNEL
|
|
NoSymbol KEY_FAVORITES
|
|
NoSymbol KEY_EPG
|
|
NoSymbol KEY_PVR
|
|
NoSymbol KEY_MHP
|
|
NoSymbol KEY_LANGUAGE
|
|
NoSymbol KEY_TITLE
|
|
NoSymbol KEY_SUBTITLE
|
|
NoSymbol KEY_ANGLE
|
|
NoSymbol KEY_ZOOM
|
|
NoSymbol KEY_MODE
|
|
NoSymbol KEY_KEYBOARD
|
|
NoSymbol KEY_SCREEN
|
|
NoSymbol KEY_PC
|
|
NoSymbol KEY_TV
|
|
NoSymbol KEY_TV2
|
|
NoSymbol KEY_VCR
|
|
NoSymbol KEY_VCR2
|
|
NoSymbol KEY_SAT
|
|
NoSymbol KEY_SAT2
|
|
NoSymbol KEY_CD
|
|
NoSymbol KEY_TAPE
|
|
NoSymbol KEY_RADIO
|
|
NoSymbol KEY_TUNER
|
|
NoSymbol KEY_PLAYER
|
|
NoSymbol KEY_TEXT
|
|
NoSymbol KEY_DVD
|
|
NoSymbol KEY_AUX
|
|
NoSymbol KEY_MP3
|
|
NoSymbol KEY_AUDIO
|
|
NoSymbol KEY_VIDEO
|
|
NoSymbol KEY_DIRECTORY
|
|
NoSymbol KEY_LIST
|
|
NoSymbol KEY_MEMO
|
|
NoSymbol KEY_CALENDAR
|
|
NoSymbol KEY_RED
|
|
NoSymbol KEY_GREEN
|
|
NoSymbol KEY_YELLOW
|
|
NoSymbol KEY_BLUE
|
|
NoSymbol KEY_CHANNELUP
|
|
NoSymbol KEY_CHANNELDOWN
|
|
NoSymbol KEY_FIRST
|
|
NoSymbol KEY_LAST
|
|
NoSymbol KEY_AB
|
|
NoSymbol KEY_NEXT
|
|
NoSymbol KEY_RESTART
|
|
NoSymbol KEY_SLOW
|
|
NoSymbol KEY_SHUFFLE
|
|
NoSymbol KEY_BREAK
|
|
NoSymbol KEY_PREVIOUS
|
|
NoSymbol KEY_DIGITS
|
|
NoSymbol KEY_TEEN
|
|
NoSymbol KEY_TWEN
|
|
|
|
NoSymbol KEY_DEL_EOL
|
|
NoSymbol KEY_DEL_EOS
|
|
NoSymbol KEY_INS_LINE
|
|
NoSymbol KEY_DEL_LINE
|
|
NoSymbol KEY_MAX
|
|
|
|
#endif
|
|
|
|
|