Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Standard c and unix libraries
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <unistd.h>
- #include <string.h>
- #include <time.h>
- #include <fcntl.h>
- // Threading
- #include <pthread.h>
- //Input management
- #include <linux/input.h>
- #include <linux/uinput.h>
- // Joystick reading
- #include <linux/joystick.h>
- // ALL OF MY FUNCTIONS EXIT ON ERROR
- // Gets a single input event and returns it.
- struct js_event getAnInput(FILE *file);
- // Creates/opens the uinput device (returns filedescriptor)
- int createUinput();
- // Configures the event types based on an array argv
- void configEvtype(int argc, int* argv,int fd);
- // Configure the keys usable based on an array argv
- void configKeys(int argc, int* argv, int fd);
- // Configures the relitive axis usable based on array argv
- void configRel(int argc, int* argv, int fd);
- // Configure the virtual device and submits it to the filedescriptor
- void configureDevice(int fd, char* name, int vendor, int product, int version);
- // Send a single event
- void sendEvent(int fd, int type, int code, int value);
- // Macro to send and then sync an event
- #define SendAndSync(fd,type,code,value) sendEvent(fd,type,code,value);sendEvent(fd,EV_SYN,0,0);
- // A pthread function which performs mouse axis movements constantly
- void *axisThreadLoop(void *ptr);
- // A record of which axis are pressed, and how much (the last one is for speed of motion on axis)
- int axisLog[7] = {0,0,0,0,0,0,1};
- int main(int argc, char* argv[]) {
- // Want root for the uinput device
- if (getuid()!=0) {
- printf("You must be root to use the uinput device, self escalating with sudo\n");
- printf("Hopefully you didnt change the program name\n");
- system("sudo ./ouycraft");
- exit(0);
- }
- printf("The program is running as root\n");
- // Open the joystick device
- FILE *file;
- // Either opens to the given joystick, or if none is given, js0
- file=fopen(argc==2?argv[1]:"/dev/input/js0","rb");
- if (!file) {
- printf("File not opened/found\n");
- exit(1);
- }
- // Creates the uinput device (returns filedescriptor)
- int fd = createUinput();
- // Configures the evtype to sync, relitive axis, and syncing
- int bits[3] = {EV_KEY,EV_REL,EV_SYN};
- configEvtype(3, bits,fd);
- // Configure the keys usable W,S,A,D,ESC,SPACE,E,leftclick,rightclick,middleclick,leftshift
- int keys[11] = {KEY_W,KEY_S,KEY_D,KEY_ESC,KEY_SPACE,KEY_A,KEY_E,BTN_LEFT,BTN_RIGHT,BTN_MIDDLE,KEY_LEFTSHIFT};
- configKeys(11, keys,fd);
- // Configure the x and y mouse axis, and the wheel motion
- int rel[3] = {REL_X,REL_Y,REL_WHEEL};
- configRel(3,rel,fd);
- // Configure the virtual device for uinput
- configureDevice(fd, "ouyInputDevice", 0x1234, 0x5678, 1);
- // Tell uinput to now create our device
- int ret = ioctl(fd,UI_DEV_CREATE);
- if (ret < 0) {
- printf("Error creating dev\n");
- exit(1);
- }
- printf("Congratulations, everything is configure, please wait a second");
- sleep(1);
- printf("Ready to run joystick actions!\n");
- // Thread to control the axis, needs the filedescriptor too
- pthread_t axisThread;
- int retval = pthread_create( &axisThread, NULL, axisThreadLoop, (void*)&fd);
- if (retval) {printf("Thread not created, exiting\n");exit(1);}
- // A main loop for the program
- while (1) {
- // jevent is not java event, but joystick event, its read in every while loop
- struct js_event jevent = getAnInput(file);
- // If jevent.type = 2 then its a axis movement with extra possible values
- if (jevent.type == 2) {
- // axis
- switch(jevent.number) {
- // Move left or right (left joystick x)
- case 0:
- if (axisLog[0] == 1 && jevent.value>=10) break;
- if (axisLog[0] == 0 && jevent.value<=10 && jevent.value>=-10) break;
- if (axisLog[0] == -1 && jevent.value<=-10) break;
- if (axisLog[0] == 1 && jevent.value<10) {SendAndSync(fd,EV_KEY,KEY_D,0); axisLog[0]=0;}
- if (axisLog[0] == -1 && jevent.value>-10) {SendAndSync(fd,EV_KEY,KEY_A,0);axisLog[0]=0;}
- if (axisLog[0] == 0 && jevent.value<=-10) {SendAndSync(fd,EV_KEY,KEY_A,1);axisLog[0]=-1;}
- if (axisLog[0] == 0 && jevent.value>=10) {SendAndSync(fd,EV_KEY,KEY_D,1);axisLog[0]=1;}
- break;
- // Move forward or backwards (left joystick y)
- case 1:
- if (axisLog[1] == 1 && jevent.value>=10) break;
- if (axisLog[1] == 0 && jevent.value<=10 && jevent.value>=-10) break;
- if (axisLog[1] == -1 && jevent.value<=-10) break;
- if (axisLog[1] == 1 && jevent.value<10) {SendAndSync(fd,EV_KEY,KEY_S,0); axisLog[1]=0;}
- if (axisLog[1] == -1 && jevent.value>-10) {SendAndSync(fd,EV_KEY,KEY_W,0);axisLog[1]=0;}
- if (axisLog[1] == 0 && jevent.value<=-10) {SendAndSync(fd,EV_KEY,KEY_W,1);axisLog[1]=-1;}
- if (axisLog[1] == 0 && jevent.value>=10) {SendAndSync(fd,EV_KEY,KEY_S,1);axisLog[1]=1;}
- break;
- // Select an item to the left (left trigger)
- case 2:
- if (axisLog[2] == jevent.value>=-32760 || axisLog[2]) break;
- axisLog[2] = jevent.value>=-32760;
- SendAndSync(fd,EV_REL,REL_WHEEL,-1);
- break;
- // just copy the mousemove for x, (right joystick x)
- case 3:
- axisLog[3] = jevent.value;
- break;
- // Just copy the mousemove for y, (right joystick y)
- case 4:
- axisLog[4] = jevent.value;
- break;
- // Select an item to the right (right trigger)
- case 5:
- if (axisLog[5] == jevent.value>=-32760 || axisLog[5]) break;
- axisLog[5] = jevent.value>=-32760;
- SendAndSync(fd,EV_REL,REL_WHEEL,1);
- break;
- }
- // If jevent.type = 1 its a simple button press
- } else if (jevent.type == 1) {
- // button
- switch (jevent.number) {
- // PS x Equivlent(jump)
- case 0: SendAndSync(fd,EV_KEY,KEY_SPACE,jevent.value);break;
- // PS circle equivlent (open inventory and slow mouse)
- case 3: SendAndSync(fd,EV_KEY,KEY_E,jevent.value);if (jevent.value) {axisLog[6]= !axisLog[6];}break;
- // Left bumper (place block)
- case 4: SendAndSync(fd,EV_KEY,BTN_RIGHT,jevent.value);break;//if(jevent.value){SendAndSync(fd,EV_REL,REL_WHEEL,1);}break;
- // Right bumper (remove block)
- case 5: SendAndSync(fd,EV_KEY,BTN_LEFT,jevent.value);break;//if (jevent.value){SendAndSync(fd,EV_REL,REL_WHEEL,-1);}break;
- // Left stick click (shiftwalk)
- case 6: SendAndSync(fd,EV_KEY,KEY_LEFTSHIFT,jevent.value);break;
- // Right stick click (copy block)
- case 7: SendAndSync(fd,EV_KEY,BTN_MIDDLE,jevent.value);break;
- // Dpad down (slow mouse)
- case 9: if (jevent.value) {axisLog[6]= !axisLog[6];}break;
- //case 12: SendAndSync(fd,EV_KEY,BTN_RIGHT,jevent.value);break;
- //case 13: SendAndSync(fd,EV_KEY,BTN_LEFT,jevent.value);break;
- // Home button (open menu)
- case 14: SendAndSync(fd,EV_KEY,KEY_ESC,jevent.value);break;
- }
- // Ignore all other messages, (joystick initialization actions)
- } else continue;
- }
- }
- // Get a single input event, and return it
- struct js_event getAnInput(FILE *file) {
- struct js_event jevent;
- int returnvalue = fread(&jevent,sizeof(jevent),1, file);
- if (returnvalue<0) {printf("file failed read\n");exit(1);}
- return jevent;
- }
- // Deal with the axis on a time based loop, prevents blocking from fread on the js0 file
- void *axisThreadLoop(void *ptr) {
- // Restore the filedescriptor
- int fd = * (int*) ptr;
- // get the current time for usage later
- clock_t start = clock();
- clock_t cur;
- // Loop for the events,(never exits)
- while (1) {
- // get the current time of the loop start
- cur = clock();
- // clock() calls can rap arround after about 75 minutes, should only hickup this way
- if (cur-start < 0) start=clock();
- // Wait a consistent time
- if (cur-start <= 10000) continue;
- // Reset the start time
- start = clock();
- // The axisLog[6] is to change the mouse speed, helpful for menus
- // The x axis is sent first but not synced
- sendEvent(fd,EV_REL,REL_X,(int)axisLog[3]/(axisLog[6]?1900:4000));
- // The y axis is sent, and we can sync it now, so now x and y are synced
- SendAndSync(fd,EV_REL,REL_Y,(int)axisLog[4]/(axisLog[6]?1900:4000));
- }
- }
- // Send our event into the uevent descriptor
- void sendEvent(int fd, int type, int code, int value) {
- // The event to be sent
- struct input_event ev;
- // 0 out all the values(i was told to)
- memset(&ev,0,sizeof(ev));
- // Copy in the type, code, and value
- ev.type = type;
- ev.code = code;
- ev.value = value;
- //POTENTIAL BUG? i dont know what the write shoudl return, il leave asis
- if (write(fd,&ev,sizeof(ev))<=0) {
- printf("Error write\n");
- exit(1);
- }
- }
- // Configure the ev types based on the loop
- void configEvtype(int argc, int* argv,int fd) {
- int ret;
- for (int i = 0; i < argc; i++) {
- // Ioctl configures the ui_set_evbit for me
- ret = ioctl(fd,UI_SET_EVBIT,argv[i]);
- if (ret < 0) {
- printf("Error setevntype %i\n",i);
- exit(1);
- }
- }
- }
- // same as configevtype but with keys
- void configKeys(int argc, int* argv, int fd) {
- int ret;
- for (int i = 0; i < argc; i++) {
- ret = ioctl(fd,UI_SET_KEYBIT,argv[i]);
- if (ret < 0) {
- printf("Error setkey %i\n",i);
- exit(1);
- }
- }
- }
- // same as configevtype but with relitive events
- void configRel(int argc, int* argv, int fd) {
- int ret;
- for (int i = 0; i < argc; i++) {
- ret = ioctl(fd,UI_SET_RELBIT,argv[i]);
- if (ret < 0) {
- printf("Error setrel %i\n",i);
- exit(1);
- }
- }
- }
- // Create a fake device for our uevent
- void configureDevice(int fd, char* name, int vendor, int product, int version) {
- struct uinput_user_dev uidev;
- memset(&uidev,0,sizeof(uidev));
- snprintf(uidev.name,UINPUT_MAX_NAME_SIZE,name);
- uidev.id.bustype=BUS_USB;
- uidev.id.vendor=vendor;
- uidev.id.product=product;
- uidev.id.version=version;
- int ret = write(fd,&uidev,sizeof(uidev));
- if (ret < 0) {
- printf("Error on writing thing\n");
- exit(1);
- }
- }
- // Create an input device based on /dev/uinput or /dev/input/uinput
- int createUinput() {
- int fd;
- // On my system its /dev/uinput, on some it may be /dev/input/uinput. lets try both
- fd = open("/dev/uinput",O_WRONLY | O_NONBLOCK);
- if (fd < 0) {
- printf("Failed to open file, Trying other input device\n");
- fd = open("/dev/input/uinput",O_WRONLY | O_NONBLOCK);
- if (fd < 0) {
- printf("No luck on input files, exiting\n");
- exit(1);
- }
- }
- return fd;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement