Initial commit.
This commit is contained in:
commit
d916bd3eda
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
poormansgamepad
|
5
LICENSE
Normal file
5
LICENSE
Normal file
@ -0,0 +1,5 @@
|
||||
Copyright (C) 2024 by bedohswe bedohswe@firemail.cc
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
11
Makefile
Normal file
11
Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
CFLAGS ?=
|
||||
|
||||
SRCS=src/main.c src/gamepad.c src/panic.c
|
||||
|
||||
all: poormansgamepad
|
||||
|
||||
poormansgamepad: $(SRCS)
|
||||
$(CC) $^ -O2 -Wall -Wpedantic $(CFLAGS) -o poormansgamepad
|
||||
|
||||
clean:
|
||||
$(RM) poormansgamepad
|
8
README.md
Normal file
8
README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Emulate a gamepad with a mouse
|
||||
|
||||
# Usage
|
||||
|
||||
`poormansgamepad devicepath scale_axis scale_wheel`
|
||||
`devicepath` - Path to mouse device (/dev/input/eventX)
|
||||
`scale_axis` - Sensitivity for the virtual thumbstick
|
||||
`scale_wheel` - Sensitivity for the virtual trigger
|
93
src/gamepad.c
Normal file
93
src/gamepad.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/uinput.h>
|
||||
|
||||
#include "panic.h"
|
||||
|
||||
void emit(int uinput, int type, int code, int val){
|
||||
struct input_event ie;
|
||||
|
||||
ie.type = type;
|
||||
ie.code = code;
|
||||
ie.value = val;
|
||||
ie.time.tv_sec = 0;
|
||||
ie.time.tv_usec = 0;
|
||||
|
||||
write(uinput, &ie, sizeof(ie));
|
||||
}
|
||||
|
||||
void destroygamepad(int uinput);
|
||||
|
||||
void sendkey(int uinput, int code, int val) {
|
||||
emit(uinput, EV_KEY, code, val);
|
||||
emit(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
|
||||
void sendaxis(int uinput, int code, int val) {
|
||||
emit(uinput, EV_ABS, code, val);
|
||||
emit(uinput, EV_SYN, SYN_REPORT, 0);
|
||||
}
|
||||
|
||||
int setupaxis(int uinput, int code) {
|
||||
int er;
|
||||
er = ioctl(uinput, UI_SET_ABSBIT, code);
|
||||
if (er < 0)
|
||||
return er;
|
||||
|
||||
struct uinput_abs_setup axis;
|
||||
axis.code = code;
|
||||
axis.absinfo.minimum = 1024;
|
||||
axis.absinfo.maximum = 1024;
|
||||
axis.absinfo.fuzz = 0;
|
||||
axis.absinfo.flat = 0;
|
||||
axis.absinfo.resolution = 1;
|
||||
axis.absinfo.value = 0;
|
||||
|
||||
return ioctl(uinput, UI_ABS_SETUP, &axis);
|
||||
}
|
||||
|
||||
int setupgamepad() {
|
||||
struct uinput_setup usetup;
|
||||
|
||||
int uinput = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
|
||||
if (!uinput)
|
||||
panic("Unable to open /dev/uinput.");
|
||||
|
||||
if (ioctl(uinput, UI_SET_EVBIT, EV_KEY) < 0)
|
||||
panic("Unable to setup EV_KEY.");
|
||||
if (ioctl(uinput, UI_SET_EVBIT, EV_ABS) < 0)
|
||||
panic("Unable to setup EV_ABS.");
|
||||
if (ioctl(uinput, UI_SET_KEYBIT, BTN_SOUTH) < 0)
|
||||
panic("Unable to setup BTN_SOUTH.");
|
||||
if (ioctl(uinput, UI_SET_KEYBIT, BTN_TL2) < 0)
|
||||
panic("Unable to setup BTN_TL2.");
|
||||
if (ioctl(uinput, UI_SET_KEYBIT, BTN_TR2) < 0)
|
||||
panic("Unable to setup BTN_TR2.");
|
||||
|
||||
if (setupaxis(uinput, ABS_X) < 0)
|
||||
panic("Unable to setup ABS_X.");;
|
||||
if (setupaxis(uinput, ABS_Y) < 0)
|
||||
panic("Unable to setup ABS_Y.");;
|
||||
if (setupaxis(uinput, ABS_HAT1X) < 0)
|
||||
panic("Unable to setup ABS_HAT1X.");;
|
||||
|
||||
memset(&usetup, 0, sizeof(usetup));
|
||||
usetup.id.bustype = BUS_USB;
|
||||
usetup.id.vendor = 0;
|
||||
usetup.id.product = 0;
|
||||
strcpy(usetup.name, "Poor man's gamepad");
|
||||
|
||||
ioctl(uinput, UI_DEV_SETUP, &usetup);
|
||||
if (ioctl(uinput, UI_DEV_CREATE) < 0)
|
||||
panic("Unable to create device.");;
|
||||
|
||||
return uinput;
|
||||
}
|
||||
|
||||
void destroygamepad(int uinput) {
|
||||
sleep(1);
|
||||
ioctl(uinput, UI_DEV_DESTROY);
|
||||
close(uinput);
|
||||
}
|
3
src/gamepad.h
Normal file
3
src/gamepad.h
Normal file
@ -0,0 +1,3 @@
|
||||
void sendkey(int uinput, int code, int val);
|
||||
void sendaxis(int uinput, int code, int val);
|
||||
int setupgamepad();
|
92
src/main.c
Normal file
92
src/main.c
Normal file
@ -0,0 +1,92 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/uinput.h>
|
||||
|
||||
#include "gamepad.h"
|
||||
#include "panic.h"
|
||||
|
||||
|
||||
void waitmouse(int mouse, struct input_event* ie) {
|
||||
while (1) {
|
||||
read(mouse, ie, sizeof(struct input_event));
|
||||
if (ie->type != EV_SYN)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int clamp(int num) {
|
||||
// Bruh
|
||||
if (num > 33000)
|
||||
return 33000;
|
||||
if (num < -33000)
|
||||
return -33000;
|
||||
return num;
|
||||
}
|
||||
|
||||
int cut(int num, int amount) {
|
||||
if (num > -amount && num < amount)
|
||||
return 0;
|
||||
return num;
|
||||
}
|
||||
|
||||
int drop(int num, int amount) {
|
||||
if (num > 0)
|
||||
return num - amount;
|
||||
if (num < 0)
|
||||
return num + amount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc == 0) {
|
||||
fprintf(stderr, "????\n");
|
||||
return 255;
|
||||
}
|
||||
if (argc != 5) {
|
||||
printf("Usage: %s devicepath scale_axis scale_wheel deadzone\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
struct input_event ie;
|
||||
int axis_x = 0;
|
||||
int axis_y = 0;
|
||||
int axis_w = 0;
|
||||
int scale_axis = strtol(argv[2], NULL, 10);
|
||||
int scale_wheel = strtol(argv[3], NULL, 10);
|
||||
int deadzone = strtol(argv[3], NULL, 10);
|
||||
int drop_axis = 0;
|
||||
int drop_wheel = 0;
|
||||
|
||||
char* device = argv[1];
|
||||
int mouse = open(device, 0);
|
||||
if (!mouse)
|
||||
panic("Unable to open device.");
|
||||
|
||||
int gamepad = setupgamepad();
|
||||
|
||||
while (1) {
|
||||
waitmouse(mouse, &ie);
|
||||
if (ie.type == EV_REL && ie.code == REL_X)
|
||||
axis_x = drop(axis_x + ie.value * scale_axis, drop_axis);
|
||||
if (ie.type == EV_REL && ie.code == REL_Y)
|
||||
axis_y = drop(axis_y + ie.value * scale_axis, drop_axis);
|
||||
if (ie.type == EV_REL && ie.code == REL_WHEEL)
|
||||
axis_w = drop(axis_w + ie.value * scale_wheel, drop_wheel);
|
||||
axis_x = clamp(axis_x);
|
||||
axis_y = clamp(axis_y);
|
||||
axis_w = clamp(axis_w);
|
||||
sendaxis(gamepad, ABS_X, cut(axis_x, deadzone));
|
||||
sendaxis(gamepad, ABS_Y, cut(axis_y, deadzone));
|
||||
sendaxis(gamepad, ABS_HAT1X, axis_w);
|
||||
if (ie.type == EV_KEY && ie.code == BTN_LEFT)
|
||||
sendkey(gamepad, BTN_TL2, ie.value);
|
||||
if (ie.type == EV_KEY && ie.code == BTN_MIDDLE)
|
||||
sendkey(gamepad, BTN_SOUTH, ie.value);
|
||||
if (ie.type == EV_KEY && ie.code == BTN_RIGHT)
|
||||
sendkey(gamepad, BTN_TR2, ie.value);
|
||||
}
|
||||
return 0;
|
||||
}
|
7
src/panic.c
Normal file
7
src/panic.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void panic(char* msg) {
|
||||
fprintf(stderr, "Fatal error occured.\n%s\n", msg);
|
||||
exit(1);
|
||||
}
|
1
src/panic.h
Normal file
1
src/panic.h
Normal file
@ -0,0 +1 @@
|
||||
void panic(char*);
|
Loading…
Reference in New Issue
Block a user