Fake a Microsoft Xbox360 controller
This commit is contained in:
parent
d5ccced593
commit
f7593f7e78
3 changed files with 200 additions and 4 deletions
4
main.c
4
main.c
|
|
@ -84,7 +84,7 @@ int main(int argc, char ** argv) {
|
|||
queue_init(&gamepad_ev, 32);
|
||||
queue_init(&imu_ev, 32);
|
||||
|
||||
out_imu_dev.fd = create_output_dev("/dev/uinput", "Virtual IMU - ROGueENEMY", output_dev_imu);
|
||||
out_imu_dev.fd = create_output_dev("/dev/uinput", "Microsoft X-Box 360 pad - ROGueENEMY", output_dev_imu);
|
||||
if (out_imu_dev.fd < 0) {
|
||||
// TODO: free(imu_dev.events_list);
|
||||
// TODO: free(gamepadd_dev.events_list);
|
||||
|
|
@ -92,7 +92,7 @@ int main(int argc, char ** argv) {
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
out_gamepadd_dev.fd = create_output_dev("/dev/uinput", "Virtual Controller - ROGueENEMY", output_dev_gamepad);
|
||||
out_gamepadd_dev.fd = create_output_dev("/dev/uinput", "Microsoft X-Box 360 pad - ROGueENEMY", output_dev_gamepad);
|
||||
if (out_gamepadd_dev.fd < 0) {
|
||||
close(out_imu_dev.fd);
|
||||
// TODO: free(imu_dev.events_list);
|
||||
|
|
|
|||
196
output_dev.c
196
output_dev.c
|
|
@ -1,6 +1,8 @@
|
|||
#include "output_dev.h"
|
||||
#include "queue.h"
|
||||
#include "message.h"
|
||||
#include <linux/input-event-codes.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int create_output_dev(const char* uinput_path, const char* name, output_dev_type_t type) {
|
||||
int fd = open(uinput_path, O_WRONLY | O_NONBLOCK);
|
||||
|
|
@ -133,6 +135,183 @@ int create_output_dev(const char* uinput_path, const char* name, output_dev_type
|
|||
}
|
||||
|
||||
case output_dev_gamepad: {
|
||||
ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_BUTTONPAD);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_ABS);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_MSC);
|
||||
//ioctl(fd, UI_SET_EVBIT, EV_SYN);
|
||||
ioctl(fd, UI_SET_MSCBIT, MSC_TIMESTAMP);
|
||||
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_X);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_Y);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_Z);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_RX);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_RY);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_RZ);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_HAT0X);
|
||||
ioctl(fd, UI_SET_ABSBIT, ABS_HAT0Y);
|
||||
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_SOUTH);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_EAST);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_NORTH);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_WEST);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_TL);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_TR);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_SELECT);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_START);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_MODE);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_TRIGGER);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_THUMBL);
|
||||
ioctl(fd, UI_SET_KEYBIT, BTN_THUMBR);
|
||||
|
||||
const struct uinput_abs_setup devAbsX = {
|
||||
.code = ABS_X,
|
||||
.absinfo = {
|
||||
.value = 0,
|
||||
.minimum = -32768,
|
||||
.maximum = +32768,
|
||||
.resolution = 1,
|
||||
.fuzz = 16,
|
||||
.flat = 128,
|
||||
}
|
||||
};
|
||||
if(ioctl(fd, UI_ABS_SETUP, &devAbsX) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
struct uinput_abs_setup devAbsY = {
|
||||
.code = ABS_Y,
|
||||
.absinfo = {
|
||||
.value = 0,
|
||||
.minimum = -32768,
|
||||
.maximum = +32768,
|
||||
.resolution = 1,
|
||||
.fuzz = 16,
|
||||
.flat = 128,
|
||||
}
|
||||
};
|
||||
|
||||
if(ioctl(fd, UI_ABS_SETUP, &devAbsY) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
struct uinput_abs_setup devAbsZ = {
|
||||
.code = ABS_Z,
|
||||
.absinfo = {
|
||||
.value = 0,
|
||||
.minimum = 0,
|
||||
.maximum = 255,
|
||||
.resolution = 255,
|
||||
//.fuzz = 16,
|
||||
//.flat = 128,
|
||||
}
|
||||
};
|
||||
if(ioctl(fd, UI_ABS_SETUP, &devAbsZ) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
struct uinput_abs_setup devAbsRX = {
|
||||
.code = ABS_RX,
|
||||
.absinfo = {
|
||||
.value = 0,
|
||||
.minimum = -32768,
|
||||
.maximum = +32768,
|
||||
.resolution = 1,
|
||||
.fuzz = 16,
|
||||
.flat = 128,
|
||||
}
|
||||
};
|
||||
if(ioctl(fd, UI_ABS_SETUP, &devAbsRX) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
struct uinput_abs_setup devAbsRY = {
|
||||
.code = ABS_RY,
|
||||
.absinfo = {
|
||||
.value = -1,
|
||||
.minimum = -32768,
|
||||
.maximum = +32768,
|
||||
.resolution = 1,
|
||||
.fuzz = 16,
|
||||
.flat = 128,
|
||||
}
|
||||
};
|
||||
if(ioctl(fd, UI_ABS_SETUP, &devAbsRY) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
struct uinput_abs_setup devAbsRZ = {
|
||||
.code = ABS_RZ,
|
||||
.absinfo = {
|
||||
.value = 0,
|
||||
.minimum = 0,
|
||||
.maximum = 255,
|
||||
.resolution = 255,
|
||||
//.fuzz = 16,
|
||||
//.flat = 128,
|
||||
}
|
||||
};
|
||||
if(ioctl(fd, UI_ABS_SETUP, &devAbsRZ) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
struct uinput_abs_setup devAbsHat0X = {
|
||||
.code = ABS_HAT0X,
|
||||
.absinfo = {
|
||||
.value = 0,
|
||||
.minimum = -1,
|
||||
.maximum = 1,
|
||||
.resolution = 1,
|
||||
//.fuzz = 16,
|
||||
//.flat = 128,
|
||||
}
|
||||
};
|
||||
if(ioctl(fd, UI_ABS_SETUP, &devAbsHat0X) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
struct uinput_abs_setup devAbsHat0Y = {
|
||||
.code = ABS_HAT0Y,
|
||||
.absinfo = {
|
||||
.value = 0,
|
||||
.minimum = -1,
|
||||
.maximum = 1,
|
||||
.resolution = 1,
|
||||
//.fuzz = 16,
|
||||
//.flat = 128,
|
||||
}
|
||||
};
|
||||
if(ioctl(fd, UI_ABS_SETUP, &devAbsHat0Y) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
if(ioctl(fd, UI_DEV_SETUP, &dev) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
if(ioctl(fd, UI_DEV_CREATE) < 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
goto create_output_dev_err;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -151,6 +330,8 @@ create_output_dev_err:
|
|||
void *output_dev_thread_func(void *ptr) {
|
||||
output_dev_t *out_dev = (output_dev_t*)ptr;
|
||||
|
||||
const int fd = out_dev->fd;
|
||||
|
||||
for (;;) {
|
||||
void *raw_ev;
|
||||
const int pop_res = queue_pop_timeout(out_dev->queue, &raw_ev, 1000);
|
||||
|
|
@ -164,6 +345,18 @@ void *output_dev_thread_func(void *ptr) {
|
|||
msg->ev.value
|
||||
);
|
||||
|
||||
struct timeval now = {0};
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
const struct input_event ev = {
|
||||
.code = msg->ev.code,
|
||||
.type = msg->ev.type,
|
||||
.value = msg->ev.value,
|
||||
.time = now,
|
||||
};
|
||||
|
||||
write(fd, (void*)&ev, sizeof(ev));
|
||||
|
||||
// from now on it's forbidden to use this memory
|
||||
msg->flags |= MESSAGE_FLAGS_HANDLE_DONE;
|
||||
} else if (pop_res == -1) {
|
||||
|
|
@ -180,5 +373,8 @@ void *output_dev_thread_func(void *ptr) {
|
|||
}
|
||||
}
|
||||
|
||||
ioctl(fd, UI_DEV_DESTROY);
|
||||
close(fd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include "queue.h"
|
||||
|
||||
#define OUTPUT_DEV_VENDOR_ID 0x4532
|
||||
#define OUTPUT_DEV_PRODUCT_ID 0x0924
|
||||
#define OUTPUT_DEV_VENDOR_ID 0x045e
|
||||
#define OUTPUT_DEV_PRODUCT_ID 0x028e
|
||||
|
||||
#define OUTPUT_DEV_CTRL_FLAG_EXIT 0x00000001U
|
||||
#define OUTPUT_DEV_CTRL_FLAG_DATA 0x00000002U
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue