#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/uinput.h>
#include <stdlib.h>
#define msleep(ms) usleep((ms)*1000)
static void setup_abs(int fd, unsigned chan, int min, int max);
// demo showing how to provide a joystick/gamepad instance from
// userspace.
int main(void)
{
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fd < 0)
{
perror("open /dev/uinput");
return 1;
}
ioctl(fd, UI_SET_EVBIT, EV_KEY); // enable button/key handling
int translatetable[] = {
KEY_LEFTSHIFT, BTN_0,
KEY_Z, BTN_1,
KEY_X, BTN_2,
KEY_C, BTN_3,
KEY_V, BTN_4,
KEY_B, BTN_5,
KEY_N, BTN_6,
KEY_M, BTN_7,
KEY_COMMA, BTN_8,
KEY_DOT, BTN_9,
KEY_SLASH, BTN_TRIGGER_HAPPY1,
KEY_RIGHTSHIFT, BTN_TRIGGER_HAPPY2,
KEY_UP, BTN_DPAD_UP,
KEY_LEFT, BTN_DPAD_LEFT,
KEY_DOWN, BTN_DPAD_DOWN,
KEY_RIGHT, BTN_DPAD_RIGHT };
int translatetablelen = sizeof(translatetable) / sizeof (int);
int rcode;
// tell uinput which BTN events we will generate
for (int i=0;i<translatetablelen;i+=2) ioctl(fd, UI_SET_KEYBIT, translatetable[i+1]);
char keyboard_to_open[256] = "/dev/input/by-id/usb-0461_USB_Wired_Keyboard-event-kbd";
char keyboard_name[256] = "Unknown";
int keyboard_fd = open(keyboard_to_open, O_RDONLY | O_NONBLOCK);
if ( keyboard_fd == -1 ) {
printf("Failed to open keyboard.\n");
exit(1);
}
rcode = ioctl(keyboard_fd, EVIOCGNAME(sizeof(keyboard_name)), keyboard_name);
printf("Reading From : %s \n", keyboard_name);
printf("Getting exclusive access: ");
rcode = ioctl(keyboard_fd, EVIOCGRAB, 1);
printf("%s\n", (rcode == 0) ? "SUCCESS" : "FAILURE");
struct input_event keyboard_event;
ioctl(fd, UI_SET_EVBIT, EV_ABS); // enable analog absolute position handling
setup_abs(fd, ABS_X, -512, 512);
setup_abs(fd, ABS_Y, -512, 512);
setup_abs(fd, ABS_Z, -32767, 32767);
struct uinput_setup setup =
{
.name = "Userspace Joystick",
.id =
{
.bustype = BUS_USB,
.vendor = 0x3,
.product = 0x3,
.version = 2,
}
};
if (ioctl(fd, UI_DEV_SETUP, &setup))
{
perror("UI_DEV_SETUP");
return 1;
}
if (ioctl(fd, UI_DEV_CREATE))
{
perror("UI_DEV_CREATE");
return 1;
}
struct input_event button_event;
while (1) {
int readval;
if ( readval = read(keyboard_fd, &keyboard_event, sizeof(keyboard_event)), readval != -1 ) {
if (keyboard_event.type == EV_KEY)
for (int i=0;i<translatetablelen;i+=2) if (keyboard_event.code == translatetable[i])
{
button_event.type = EV_KEY;
button_event.code = translatetable[i+1];
button_event.value = keyboard_event.value;
printf("ev type = %d keycode=%d code = %d value = %d\n",
button_event.type,
keyboard_event.code,
button_event.code,
button_event.value);
if(write(fd, &button_event, sizeof button_event) < 0)
{
perror("write");
return 1;
}
// send a SYNC event
button_event.type = EV_SYN;
button_event.code = 0;
button_event.value = 0;
if(write(fd, &button_event, sizeof button_event) < 0)
{
perror("write");
return 1;
}
if(write(fd, &button_event, sizeof button_event) < 0)
{
perror("write");
return 1;
}
break;
}
if (readval == -1) msleep(50);
}
}
if(ioctl(fd, UI_DEV_DESTROY))
{
printf("UI_DEV_DESTROY");
return 1;
}
close(fd);
return 0;
}
// enable and configure an absolute "position" analog channel
static void setup_abs(int fd, unsigned chan, int min, int max)
{
if (ioctl(fd, UI_SET_ABSBIT, chan))
perror("UI_SET_ABSBIT");
struct uinput_abs_setup s =
{
.code = chan,
.absinfo = { .minimum = min, .maximum = max },
};
if (ioctl(fd, UI_ABS_SETUP, &s))
perror("UI_ABS_SETUP");
}