Initial commit.

This commit is contained in:
bʰedoh₂ swé 2024-07-08 10:50:35 +05:00
commit d916bd3eda
9 changed files with 221 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
poormansgamepad

5
LICENSE Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1 @@
void panic(char*);