Init
This commit is contained in:
commit
79e255d19d
11 changed files with 915 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
build/*
|
||||
kvm
|
||||
35
Makefile
Normal file
35
Makefile
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
CC = cc
|
||||
CFLAGS = -O2 -fPIE
|
||||
|
||||
TARGET = kvm
|
||||
LIBS = -ludev -lX11 -lXrandr -lXext -lXfixes -lXft
|
||||
INCLUDES = -I/usr/include/freetype2
|
||||
|
||||
SRC_DIR = src
|
||||
BUILD_DIR = build
|
||||
|
||||
SRC = $(wildcard $(SRC_DIR)/*.c)
|
||||
OBJ = $(SRC:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
|
||||
|
||||
PREFIX = /usr/local
|
||||
BINDIR = $(PREFIX)/bin
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
$(CC) $(OBJ) -o $@ $(LIBS)
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
@mkdir -p $(BUILD_DIR)
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
|
||||
|
||||
install: $(TARGET)
|
||||
install -Dm755 $(TARGET) $(BINDIR)/$(TARGET)
|
||||
|
||||
uninstall:
|
||||
rm -f $(BINDIR)/$(TARGET)
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR) $(TARGET)
|
||||
|
||||
.PHONY: all install uninstall clean
|
||||
19
README.md
Normal file
19
README.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# KVM
|
||||
Kernel virtual mouse
|
||||
KVM is a tool that allows you to use mouse input without reaching over to the mouse, using the kernel's input routines to be portable across X and wayland.
|
||||
This is still early stage, if you wanna send patches message me on xmpp at cody@youra.monster
|
||||
|
||||
## Keybinds:
|
||||
Exit: q / esc
|
||||
Move mouse: vim keys
|
||||
Click: W, E, R (left, middle, and right respectively)
|
||||
Scroll: M,','
|
||||
Horizontal Scroll: '.','/'
|
||||
Tree selector: X
|
||||
Exit tree selector: P
|
||||
Tree selector navigate: YUIDFGCVB (buttons are on screen you can figure it out)
|
||||
|
||||
## Current problems:
|
||||
Tree selector mode is X only
|
||||
Code could probably be cleaned up
|
||||
No config
|
||||
64
bldit.lua
Normal file
64
bldit.lua
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
bldit_version = "1.1.3"
|
||||
package_version = "1.1.3"
|
||||
|
||||
dependencies = {}
|
||||
|
||||
exec_name = "kvm"
|
||||
libs = "-Wall -Wextra -ludev -lX11 -lXrandr -lXext -lXfixes -lXft"
|
||||
includes = "-Iudev -ggdb -I/usr/include/freetype2"
|
||||
cc = "gcc"
|
||||
|
||||
execute = function(str)
|
||||
print(str)
|
||||
return os.execute(str)
|
||||
end
|
||||
|
||||
targets = {
|
||||
default = {
|
||||
build = function()
|
||||
e,h,c = execute("rm -fr build")
|
||||
if c ~= 0 and c ~= nil then
|
||||
print("Build Error")
|
||||
print("GIVEN UP")
|
||||
return c
|
||||
end
|
||||
e,h,c = execute("mkdir build")
|
||||
if c ~= 0 and c ~= nil then
|
||||
print("Build Error")
|
||||
print("GIVEN UP")
|
||||
return c
|
||||
end
|
||||
cmd = [[find src -type f -name "*.c" -print]]
|
||||
p = io.popen(cmd)
|
||||
assert(p, "File detection error, GIVEN UP")
|
||||
|
||||
for f in p:lines() do
|
||||
base = f:match("([^/]+)%.c$")
|
||||
obj = "build/"..base..".o"
|
||||
ccom = cc.." -c -O3 '"..f.."' -o '"..obj.."' "..includes
|
||||
e,h,c = execute(ccom)
|
||||
if c ~= 0 and c ~= nil then
|
||||
print("Compilation Error")
|
||||
print("GIVEN UP")
|
||||
return c
|
||||
end
|
||||
end
|
||||
p:close()
|
||||
e,h,c = execute(cc.." build/*.o "..libs.." -o "..exec_name)
|
||||
if c ~= 0 and c ~= nil then
|
||||
print("Compilation Error")
|
||||
print("GIVEN UP")
|
||||
return c
|
||||
end
|
||||
return 0
|
||||
end,
|
||||
install = function()
|
||||
e,h,c = execute("cp "..exec_name.." /bin")
|
||||
return c or 0
|
||||
end,
|
||||
uninstall = function()
|
||||
e,h,c = execute("rm /bin"..exec_name)
|
||||
return c or 0
|
||||
end,
|
||||
}
|
||||
}
|
||||
147
src/device_select.c
Normal file
147
src/device_select.c
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#include <stdbool.h>
|
||||
#include <libudev.h>
|
||||
#include <linux/input.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int menuSelectDevice(struct udev *udev,
|
||||
struct udev_list_entry *devices, char *fpath) {
|
||||
struct udev_list_entry *entry;
|
||||
int pipe_in[2];
|
||||
int pipe_out[2];
|
||||
pipe(pipe_in);
|
||||
pipe(pipe_out);
|
||||
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid == 0) {
|
||||
dup2(pipe_in[0], STDIN_FILENO);
|
||||
dup2(pipe_out[1], STDOUT_FILENO);
|
||||
close(pipe_in[1]);
|
||||
close(pipe_out[0]);
|
||||
// TODO: read config for menu program
|
||||
execlp("dmenu", "dmenu", "-p", "Keyboard:", NULL);
|
||||
perror("execlp");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(pipe_in[0]);
|
||||
close(pipe_out[1]);
|
||||
|
||||
udev_list_entry_foreach(entry, devices) {
|
||||
const char *path =
|
||||
udev_list_entry_get_name(entry);
|
||||
struct udev_device *dev =
|
||||
udev_device_new_from_syspath(
|
||||
udev,
|
||||
path
|
||||
);
|
||||
const char *devnode =
|
||||
udev_device_get_devnode(dev);
|
||||
|
||||
if (devnode) {
|
||||
const char *keyboard = udev_device_get_property_value(
|
||||
dev,"ID_INPUT_KEYBOARD");
|
||||
const char *mouse = udev_device_get_property_value(
|
||||
dev, "ID_INPUT_MOUSE");
|
||||
if (mouse) continue;
|
||||
if (!keyboard) continue;
|
||||
|
||||
const char *vendor = udev_device_get_property_value
|
||||
(dev, "ID_VENDOR");
|
||||
const char *model = udev_device_get_property_value
|
||||
(dev, "ID_MODEL");
|
||||
dprintf(pipe_in[1], "%s %s %s\n", devnode, vendor, model);
|
||||
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
close(pipe_in[1]);
|
||||
FILE *f = fdopen(pipe_out[0], "r");
|
||||
char menures[256];
|
||||
fscanf(f, "%255s", menures);
|
||||
close(pipe_out[0]);
|
||||
printf("Selected %s\n", menures);
|
||||
FILE *kbd_f = fopen(fpath, "w");
|
||||
fputs(menures, kbd_f);
|
||||
fclose(kbd_f);
|
||||
|
||||
waitpid(pid, NULL, 0);
|
||||
udev_list_entry_foreach(entry, devices) {
|
||||
const char *path =
|
||||
udev_list_entry_get_name(entry);
|
||||
struct udev_device *dev =
|
||||
udev_device_new_from_syspath(
|
||||
udev,
|
||||
path
|
||||
);
|
||||
const char *devnode =
|
||||
udev_device_get_devnode(dev);
|
||||
if (devnode && !strcmp(devnode, menures)) {
|
||||
int fd = open(devnode, O_RDONLY);
|
||||
udev_device_unref(dev);
|
||||
return fd;
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int selectDevice(struct udev *udev,
|
||||
struct udev_list_entry *devices, char *fpath) {
|
||||
struct udev_list_entry *entry;
|
||||
FILE *f = fopen(fpath, "r");
|
||||
char goalnode[4096];
|
||||
fgets(goalnode, 4096, f);
|
||||
|
||||
uint devidx = 0;
|
||||
udev_list_entry_foreach(entry, devices) {
|
||||
const char *path =
|
||||
udev_list_entry_get_name(entry);
|
||||
struct udev_device *dev =
|
||||
udev_device_new_from_syspath(
|
||||
udev,
|
||||
path
|
||||
);
|
||||
const char *devnode =
|
||||
udev_device_get_devnode(dev);
|
||||
|
||||
if (devnode) {
|
||||
const char *keyboard = udev_device_get_property_value(
|
||||
dev,"ID_INPUT_KEYBOARD");
|
||||
const char *mouse = udev_device_get_property_value(
|
||||
dev, "ID_INPUT_MOUSE");
|
||||
if (mouse) continue;
|
||||
if (!keyboard) continue;
|
||||
int fd = open(devnode, O_RDONLY);
|
||||
|
||||
const char *path = udev_device_get_sysattr_value(dev, "ID_PATH");
|
||||
const char *name = udev_device_get_sysattr_value(dev, "name");
|
||||
const char *vendor = udev_device_get_property_value
|
||||
(dev, "ID_VENDOR");
|
||||
const char *model = udev_device_get_property_value
|
||||
(dev, "ID_MODEL");
|
||||
printf("[%d] Device: %s\n", ++devidx, devnode);
|
||||
printf(" Name: %s\n",
|
||||
name ? name : "unknown");
|
||||
printf(" Vendor: %s\n",
|
||||
vendor ? vendor : "unknown");
|
||||
printf(" Model: %s\n",
|
||||
model ? model : "unknown");
|
||||
printf(" Node: %s\n",
|
||||
devnode ? devnode : "unknown");
|
||||
if (!strcmp(devnode, goalnode)) {
|
||||
udev_device_unref(dev);
|
||||
return fd;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
return menuSelectDevice(udev, devices, fpath);
|
||||
}
|
||||
4
src/device_select.h
Normal file
4
src/device_select.h
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
int menuSelectDevice(struct udev *udev,
|
||||
struct udev_list_entry *devices, char *fpath);
|
||||
int selectDevice(struct udev *udev,
|
||||
struct udev_list_entry *devices, char *fpath);
|
||||
559
src/main.c
Normal file
559
src/main.c
Normal file
|
|
@ -0,0 +1,559 @@
|
|||
#include <stdio.h>
|
||||
#include <libudev.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/uinput.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include "util.h"
|
||||
#include "device_select.h"
|
||||
#include "mouse.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <string.h>
|
||||
#include <X11/Xft/Xft.h>
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
XRRMonitorInfo *findMonitor(Display *dpy, Window root, int fx, int fy) {
|
||||
int nmonitors;
|
||||
XRRMonitorInfo *monitors =
|
||||
XRRGetMonitors(dpy, root, True, &nmonitors);
|
||||
|
||||
if (!monitors || nmonitors <= 0) {
|
||||
fprintf(stderr, "Could not find monitors\n");
|
||||
XCloseDisplay(dpy);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
XRRMonitorInfo *monitor = NULL;
|
||||
|
||||
for (int i = 0; i < nmonitors; i++) {
|
||||
int x1 = monitors[i].x;
|
||||
int y1 = monitors[i].y;
|
||||
int x2 = x1 + monitors[i].width;
|
||||
int y2 = y1 + monitors[i].height;
|
||||
|
||||
if (fx >= x1 && fx < x2 && fy >= y1 && fy < y2) {
|
||||
monitor = &monitors[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!monitor)
|
||||
monitor = &monitors[0];
|
||||
return monitor;
|
||||
}
|
||||
|
||||
void renderGrid(int treeX, int treeY, int treeW, int treeH,
|
||||
Display *dpy, int screen,
|
||||
Pixmap treeMask, GC maskGC,
|
||||
Window treeWin, GC gc,
|
||||
XftDraw *xftDraw, XftColor textColor, XftFont *font,
|
||||
XRRMonitorInfo *mon,
|
||||
char *treekeynames) {
|
||||
int fsize = treeH/4;
|
||||
if (font) {
|
||||
XftFontClose(dpy, font);
|
||||
font = NULL;
|
||||
}
|
||||
char fontname[256];
|
||||
snprintf(fontname, sizeof(fontname), "Mono:size=%d", fsize);
|
||||
printf("Loading %s\n", fontname);
|
||||
font = XftFontOpenName(
|
||||
dpy,
|
||||
screen,
|
||||
fontname
|
||||
);
|
||||
if (!font) {
|
||||
fprintf(stderr, "Failed to load font: %s\n", fontname);
|
||||
exit(1);
|
||||
}
|
||||
int wx = treeW/3;
|
||||
int wy = treeH/3;
|
||||
XSetForeground(dpy, maskGC, 0);
|
||||
XFillRectangle(
|
||||
dpy,
|
||||
treeMask,
|
||||
maskGC,
|
||||
0, 0,
|
||||
mon->width, mon->height
|
||||
);
|
||||
XSetForeground(dpy, maskGC, 1);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
XDrawLine(
|
||||
dpy, treeMask, maskGC,
|
||||
treeX+i*wx, treeY+0,
|
||||
treeX+i*wx, treeY+treeH
|
||||
);
|
||||
XDrawLine(
|
||||
dpy, treeMask, maskGC,
|
||||
treeX+0, treeY+i*wy,
|
||||
treeX+treeW, treeY+i*wy
|
||||
);
|
||||
}
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
//const char *text = &treekeynames[i+j*3];
|
||||
XFillRectangle(dpy, treeMask, maskGC,
|
||||
treeX+i*wx+wx/2, treeY+j*wy+(wy*3/4)-fsize,
|
||||
fsize, fsize); // TODO: find character width
|
||||
}
|
||||
}
|
||||
XShapeCombineMask(
|
||||
dpy,
|
||||
treeWin,
|
||||
ShapeBounding,
|
||||
0, 0,
|
||||
treeMask,
|
||||
ShapeSet
|
||||
);
|
||||
XSetForeground(dpy, gc, WhitePixel(dpy, screen));
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
XDrawLine(
|
||||
dpy, treeWin, gc,
|
||||
treeX+i*wx, treeY+0,
|
||||
treeX+i*wx, treeY+treeH
|
||||
);
|
||||
XDrawLine(
|
||||
dpy, treeWin, gc,
|
||||
treeX+0, treeY+i*wy,
|
||||
treeX+treeW, treeY+i*wy
|
||||
);
|
||||
}
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const char *text = &treekeynames[i+j*3];
|
||||
XftDrawStringUtf8(
|
||||
xftDraw,
|
||||
&textColor,
|
||||
font,
|
||||
treeX+i*wx+wx/2, treeY+j*wy+(wy*3/4),
|
||||
(const FcChar8 *)text,
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
XFlush(dpy);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
char config_dir[4096];
|
||||
const char *xdg = getenv("XDG_CONFIG_DIR");
|
||||
if (!xdg) {
|
||||
const char *home = getenv("HOME");
|
||||
if (!home) {
|
||||
printf("You don't have home or config..."
|
||||
"what is wrong with your system\n");
|
||||
}
|
||||
snprintf(config_dir, 4096, "%s/.config/", home);
|
||||
} else {
|
||||
snprintf(config_dir, 4096, "%s", xdg);
|
||||
}
|
||||
|
||||
char keyboard_path[4096];
|
||||
snprintf(keyboard_path, 4096, "%s/kvm/keyboard", config_dir);
|
||||
if (access(keyboard_path, F_OK) != 0) {
|
||||
makeFileAndParents(keyboard_path);
|
||||
}
|
||||
|
||||
struct udev *udev = udev_new();
|
||||
|
||||
if (!udev) {
|
||||
printf("Failed to create udev\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct udev_enumerate *enumerate =
|
||||
udev_enumerate_new(udev);
|
||||
udev_enumerate_add_match_subsystem(
|
||||
enumerate,
|
||||
"input"
|
||||
);
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
|
||||
struct udev_list_entry *devices =
|
||||
udev_enumerate_get_list_entry(enumerate);
|
||||
int kbd_fd = selectDevice(udev, devices, keyboard_path);
|
||||
int mouse_fd = create_virtual_mouse();
|
||||
usleep(100000);
|
||||
|
||||
if (ioctl(kbd_fd, EVIOCGRAB, 1) < 0) {
|
||||
perror("EVIOCGRAB grab");
|
||||
return 1;
|
||||
}
|
||||
printf("Keyboard grabbed\n");
|
||||
|
||||
struct input_event ev;
|
||||
int dxn = 0;
|
||||
int dxp = 0;
|
||||
int dyn = 0;
|
||||
int dyp = 0;
|
||||
float speedmul = 1.0f;
|
||||
|
||||
Display *dpy = XOpenDisplay(NULL);
|
||||
int screen = DefaultScreen(dpy);
|
||||
Window root = RootWindow(dpy, screen);
|
||||
|
||||
Window focused;
|
||||
int revert;
|
||||
|
||||
XGetInputFocus(dpy, &focused, &revert);
|
||||
int fx, fy;
|
||||
Window child;
|
||||
|
||||
if (!XTranslateCoordinates(dpy,focused,
|
||||
root, 0, 0, &fx, &fy, &child)) {
|
||||
fprintf(stderr, "Could not find focused window position\n");
|
||||
XCloseDisplay(dpy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool treemode = false;
|
||||
|
||||
XSetWindowAttributes attrs = {0};
|
||||
attrs.override_redirect = True;
|
||||
|
||||
XRRMonitorInfo *mon = findMonitor(dpy, root, fx, fy);
|
||||
|
||||
//int treeX = mon->x;
|
||||
//int treeY = mon->y;
|
||||
int treeX = 0;
|
||||
int treeY = 0;
|
||||
int treeW = mon->width;
|
||||
int treeH = mon->height;
|
||||
|
||||
Window treeWin = XCreateWindow(
|
||||
dpy,
|
||||
root,
|
||||
mon->x, mon->y,
|
||||
mon->width, mon->height,
|
||||
0,
|
||||
CopyFromParent,
|
||||
InputOutput,
|
||||
CopyFromParent,
|
||||
CWOverrideRedirect,
|
||||
&attrs
|
||||
);
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* Visible shape
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
Pixmap treeMask = XCreatePixmap(
|
||||
dpy,
|
||||
treeWin,
|
||||
treeW,
|
||||
treeH,
|
||||
1
|
||||
);
|
||||
|
||||
GC maskGC = XCreateGC(
|
||||
dpy,
|
||||
treeMask,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
|
||||
/* Start with everything invisible */
|
||||
XSetForeground(dpy, maskGC, 0);
|
||||
|
||||
XFillRectangle(
|
||||
dpy,
|
||||
treeMask,
|
||||
maskGC,
|
||||
0, 0,
|
||||
treeW,
|
||||
treeH
|
||||
);
|
||||
|
||||
GC gc = XCreateGC(
|
||||
dpy,
|
||||
treeWin,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
XMapRaised(dpy, treeWin);
|
||||
XShapeCombineMask(
|
||||
dpy,
|
||||
treeWin,
|
||||
ShapeBounding,
|
||||
0, 0,
|
||||
treeMask,
|
||||
ShapeSet
|
||||
);
|
||||
|
||||
XftDraw *xftDraw = XftDrawCreate(
|
||||
dpy,
|
||||
treeWin,
|
||||
DefaultVisual(dpy, screen),
|
||||
DefaultColormap(dpy, screen)
|
||||
);
|
||||
|
||||
XftFont *font = XftFontOpenName(
|
||||
dpy,
|
||||
screen,
|
||||
"Mono:size=80"
|
||||
);
|
||||
|
||||
if (!font) {
|
||||
fprintf(stderr, "Couldn't load font\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
XftColor textColor;
|
||||
|
||||
if (!XftColorAllocName(
|
||||
dpy,
|
||||
DefaultVisual(dpy, screen),
|
||||
DefaultColormap(dpy, screen),
|
||||
"white",
|
||||
&textColor))
|
||||
{
|
||||
fprintf(stderr, "Couldn't allocate text color\n");
|
||||
return 1;
|
||||
}
|
||||
XFlush(dpy);
|
||||
|
||||
while (1) {
|
||||
ssize_t n = read(kbd_fd, &ev, sizeof(ev));
|
||||
XEvent event;
|
||||
while (XPending(dpy)) {
|
||||
printf("Event\n");
|
||||
XNextEvent(dpy, &event);
|
||||
}
|
||||
if (n != sizeof(ev)) {
|
||||
perror("read");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char treekeynames[9] = {'Y', 'U', 'I', 'D', 'F', 'G', 'C', 'V', 'B'};
|
||||
// These are characters but they don't match up right
|
||||
// I.e KEY_I == 'm'
|
||||
char treekeys[9] = {KEY_Y, KEY_U, KEY_I, KEY_D, KEY_F, KEY_G, KEY_C, KEY_V, KEY_B};
|
||||
|
||||
bool shouldsleep = true;
|
||||
//movemouse(mouse_fd, ev);
|
||||
if (ev.type == EV_KEY) {
|
||||
if (ev.code == KEY_ESC || ev.code == KEY_Q) {
|
||||
break;
|
||||
}
|
||||
if (ev.value == 1 && !treemode) {
|
||||
if (ev.code == KEY_LEFTSHIFT) {
|
||||
speedmul = 2.0f;
|
||||
printf("start shift speed\n");
|
||||
}
|
||||
if (ev.code == KEY_LEFTCTRL) {
|
||||
speedmul = 0.5f;
|
||||
printf("start control slow\n");
|
||||
}
|
||||
if (ev.code == KEY_J) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_Y, speedmul*25);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_K) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_Y, speedmul*-25);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_L) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_X, speedmul*25);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_H) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_X, speedmul*-25);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_W) {
|
||||
send_mouse_event(mouse_fd, EV_KEY, BTN_LEFT, 1);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_E) {
|
||||
send_mouse_event(mouse_fd, EV_KEY, BTN_MIDDLE, 1);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_R) {
|
||||
send_mouse_event(mouse_fd, EV_KEY, BTN_RIGHT, 1);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_M) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_WHEEL, -speedmul);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_COMMA) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_WHEEL, speedmul);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_DOT) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_HWHEEL, -speedmul);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_SLASH) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_HWHEEL, speedmul);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_X) {
|
||||
treemode = true;
|
||||
renderGrid(treeX, treeY, treeW, treeH, dpy, screen,
|
||||
treeMask, maskGC, treeWin, gc, xftDraw, textColor,
|
||||
font, mon, treekeynames);
|
||||
}
|
||||
}
|
||||
if (ev.value == 1 && treemode) {
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
if (ev.code == treekeys[i]) {
|
||||
int ix = i%3;
|
||||
int iy = i/3;
|
||||
int des_x = treeX + (treeW/3)*ix;
|
||||
int des_y = treeY + (treeH/3)*iy;
|
||||
|
||||
// This is X only
|
||||
// If someone who understands wayland can send patches please do
|
||||
XWarpPointer(dpy, root, root, 0, 0, 0, 0,
|
||||
mon->x+des_x, mon->y+des_y);
|
||||
treeX = des_x;
|
||||
treeY = des_y;
|
||||
treeW /= 3;
|
||||
treeH /= 3;
|
||||
XSetForeground(dpy, maskGC, 0);
|
||||
XFillRectangle(
|
||||
dpy,
|
||||
treeMask,
|
||||
maskGC,
|
||||
0, 0,
|
||||
mon->width, mon->height
|
||||
);
|
||||
XShapeCombineMask(
|
||||
dpy,
|
||||
treeWin,
|
||||
ShapeBounding,
|
||||
0, 0,
|
||||
treeMask,
|
||||
ShapeSet
|
||||
);
|
||||
|
||||
renderGrid(treeX, treeY, treeW, treeH, dpy, screen,
|
||||
treeMask, maskGC, treeWin, gc, xftDraw, textColor,
|
||||
font, mon, treekeynames);
|
||||
}
|
||||
}
|
||||
if (ev.code == KEY_P) {
|
||||
XSetForeground(dpy, maskGC, 0);
|
||||
XFillRectangle(
|
||||
dpy,
|
||||
treeMask,
|
||||
maskGC,
|
||||
0, 0,
|
||||
mon->width, mon->height
|
||||
);
|
||||
XShapeCombineMask(
|
||||
dpy,
|
||||
treeWin,
|
||||
ShapeBounding,
|
||||
0, 0,
|
||||
treeMask,
|
||||
ShapeSet
|
||||
);
|
||||
treeX = 0;
|
||||
treeY = 0;
|
||||
treeW = mon->width;
|
||||
treeH = mon->height;
|
||||
treemode = false;
|
||||
}
|
||||
}
|
||||
if (ev.value == 2 && !treemode) {
|
||||
int speed = 6;
|
||||
if (ev.code == KEY_J) {
|
||||
dyp = speed;
|
||||
}
|
||||
if (ev.code == KEY_K) {
|
||||
dyn = speed;
|
||||
}
|
||||
if (ev.code == KEY_L) {
|
||||
dxp = speed;
|
||||
}
|
||||
if (ev.code == KEY_H) {
|
||||
dxn = speed;
|
||||
}
|
||||
if (ev.code == KEY_M) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_WHEEL, -speedmul);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_COMMA) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_WHEEL, speedmul);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_DOT) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_HWHEEL, -speedmul);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_SLASH) {
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_HWHEEL, speedmul);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
shouldsleep = false;
|
||||
}
|
||||
if (ev.value == 0 && !treemode) {
|
||||
if (ev.code == KEY_W) {
|
||||
send_mouse_event(mouse_fd, EV_KEY, BTN_LEFT, 0);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_E) {
|
||||
send_mouse_event(mouse_fd, EV_KEY, BTN_MIDDLE, 0);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_R) {
|
||||
send_mouse_event(mouse_fd, EV_KEY, BTN_RIGHT, 0);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
if (ev.code == KEY_J) {
|
||||
dyp = 0;
|
||||
}
|
||||
if (ev.code == KEY_K) {
|
||||
dyn = 0;
|
||||
}
|
||||
if (ev.code == KEY_L) {
|
||||
dxp = 0;
|
||||
}
|
||||
if (ev.code == KEY_H) {
|
||||
dxn = 0;
|
||||
}
|
||||
if (ev.code == KEY_LEFTSHIFT) {
|
||||
speedmul = 1.0f;
|
||||
}
|
||||
if (ev.code == KEY_LEFTCTRL) {
|
||||
speedmul = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int total_dx = dxp - dxn;
|
||||
int total_dy = dyp - dyn;
|
||||
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_X, speedmul*total_dx);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
send_mouse_event(mouse_fd, EV_REL, REL_Y, speedmul*total_dy);
|
||||
send_mouse_event(mouse_fd, EV_SYN, SYN_REPORT, 0);
|
||||
|
||||
if (shouldsleep) usleep(1000000/60);
|
||||
}
|
||||
|
||||
// Give control back
|
||||
if (ioctl(kbd_fd, EVIOCGRAB, 0) < 0) {
|
||||
perror("EVIOCGRAB release");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Keyboard released\n");
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
udev_unref(udev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
56
src/mouse.c
Normal file
56
src/mouse.c
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <linux/uinput.h>
|
||||
|
||||
|
||||
void send_mouse_event(int fd, int type, int code, int value) {
|
||||
struct input_event ev;
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
|
||||
ev.type = type;
|
||||
ev.code = code;
|
||||
ev.value = value;
|
||||
|
||||
write(fd, &ev, sizeof(ev));
|
||||
}
|
||||
|
||||
int create_virtual_mouse() {
|
||||
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
perror("uinput");
|
||||
exit(1);
|
||||
}
|
||||
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_RELBIT, REL_WHEEL);
|
||||
ioctl(fd, UI_SET_RELBIT, REL_HWHEEL);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_MIDDLE);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_REL);
|
||||
|
||||
struct uinput_setup setup;
|
||||
|
||||
memset(&setup, 0, sizeof(setup));
|
||||
|
||||
setup.id.bustype = BUS_USB;
|
||||
setup.id.vendor = 0x1234;
|
||||
setup.id.product = 0x5678;
|
||||
|
||||
strcpy(setup.name, "Virtual Keyboard Mouse");
|
||||
|
||||
ioctl(fd, UI_DEV_SETUP, &setup);
|
||||
ioctl(fd, UI_DEV_CREATE);
|
||||
|
||||
|
||||
printf("Virtual mouse created\n");
|
||||
|
||||
return fd;
|
||||
}
|
||||
2
src/mouse.h
Normal file
2
src/mouse.h
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
void send_mouse_event(int fd, int type, int code, int value);
|
||||
int create_virtual_mouse();
|
||||
26
src/util.c
Normal file
26
src/util.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
int makeFileAndParents(const char *path) {
|
||||
char buf[4096];
|
||||
|
||||
strcpy(buf, path);
|
||||
|
||||
for (char *p = buf + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
*p = '\0';
|
||||
|
||||
if (mkdir(buf, 0755) == -1 && errno != EEXIST)
|
||||
return -1;
|
||||
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
return open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
}
|
||||
|
||||
1
src/util.h
Normal file
1
src/util.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
int makeFileAndParents(const char *path);
|
||||
Loading…
Add table
Add a link
Reference in a new issue