From d40392215749bd38edb2f2123a181c68e2fcd9a4 Mon Sep 17 00:00:00 2001 From: Nuri Melih Sensoy Date: Fri, 15 Feb 2019 03:40:03 +0300 Subject: [PATCH] added real device sharing feature & first release --- README.md | 30 +- clients/C_Cpp/mouse/Makefile | 22 ++ clients/C_Cpp/mouse/mouse_client.c | 148 ++++++++ input_events.txt | 352 ------------------ server/src/server.c | 11 +- test/ideas/new_server.c | 576 ----------------------------- test/ideas/udp_client.c | 41 ++ test/ideas/udp_server.c | 49 +++ test/integration/device_client.c | 147 -------- test/units/debug_device.c | 95 ----- test/units/dev_debug.c | 98 +++++ test/units/event_hid.c | 47 +++ test/units/list_hid.c | 41 ++ 13 files changed, 478 insertions(+), 1179 deletions(-) create mode 100644 clients/C_Cpp/mouse/Makefile create mode 100644 clients/C_Cpp/mouse/mouse_client.c delete mode 100644 input_events.txt delete mode 100644 test/ideas/new_server.c create mode 100644 test/ideas/udp_client.c create mode 100644 test/ideas/udp_server.c delete mode 100644 test/integration/device_client.c delete mode 100644 test/units/debug_device.c create mode 100644 test/units/dev_debug.c create mode 100644 test/units/event_hid.c create mode 100644 test/units/list_hid.c diff --git a/README.md b/README.md index af254b1..8d4429b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Virtual HID over TCP -A HID device emulation which can be controlled remotely over tcp socket connection.You can create joystick, keyboard or mouse device and send events like **joystick axis and buttons, keyboard key presses, mouse pointer movements** over network. +A HID device emulation which can be controlled remotely over network.You can create joystick, keyboard or mouse device and send events like **joystick axis and buttons, keyboard key presses, mouse pointer movements** over network.With new client real device events can be sent.So its perfectly fit for keyboard, mouse sharing. Server side is written in C and currently works only in Linux.But client side is platform independent so can be written in any platform&language with using tcp socket connection. @@ -26,26 +26,36 @@ cd bin/ ### C/C++ Client +If your server located in diffrent pc then set server ip adress with -ip 11.11.11.11 option. + ```sh cd clients/C_Cpp/ make ./client --help ``` +**For Real Mouse Sharing** + +```sh +cd clients/C_Cpp/mouse +make +sudo ./mouse_client 127.0.0.1 +``` + #### Key Press 115 -> Volume Up // 114 -> Volume Down -```c +```sh ./client -k 115 ``` #### Mouse Pointer --m X Y +-pX -pY -```c -./client -m 50 50 +```sh +./client -pX 20 ``` ### Python Client @@ -54,6 +64,14 @@ make 115 -> Volume Up // 114 -> Volume Down -```python +```sh python client.py -k 114 +``` + +#### Mouse Pointer + +-pX -pY + +```sh +python client.py -pX 20 ``` \ No newline at end of file diff --git a/clients/C_Cpp/mouse/Makefile b/clients/C_Cpp/mouse/Makefile new file mode 100644 index 0000000..20d410b --- /dev/null +++ b/clients/C_Cpp/mouse/Makefile @@ -0,0 +1,22 @@ +CC = gcc +CFLAGS = -Wall +LIBS = -lm + +SRC_DIR = +OBJ_DIR = +BIN_DIR = + +APP_NAME = mouse_client + +$(BIN_DIR)$(APP_NAME): $(OBJ_DIR)$(APP_NAME).o + $(CC) $(CFLAGS) $(LIBS) -o $(BIN_DIR)$(APP_NAME) $(OBJ_DIR)$(APP_NAME).o + +$(OBJ_DIR)$(APP_NAME).o: $(SRC_DIR)$(APP_NAME).c + $(CC) $(CFLAGS) -c $(SRC_DIR)$(APP_NAME).c -o $(OBJ_DIR)$(APP_NAME).o + +clean: + rm -f $(OBJ_DIR)*.o + +install: + cp $(BIN_DIR)$(APP_NAME) /usr/bin + diff --git a/clients/C_Cpp/mouse/mouse_client.c b/clients/C_Cpp/mouse/mouse_client.c new file mode 100644 index 0000000..749ff64 --- /dev/null +++ b/clients/C_Cpp/mouse/mouse_client.c @@ -0,0 +1,148 @@ +/* + * Author: Nuri Melih Sensoy + * github.com/nmelihsensoy + * File: "device_client.c" + * + * This client sends real device events +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PORT 8080 + +int device_count = 0; +char **device; +int sock = 0; + +void error_handling(char *msg){ + perror(msg); + exit(EXIT_FAILURE); +} + +void scan_devices(){ + struct dirent *de; + int i=0; + + DIR *dr = opendir("/dev/input"); + + if (dr == NULL){ + error_handling("Could not open directory"); + } + + device = malloc(50 * sizeof(char*)); + + while((de = readdir(dr)) != NULL){ + if(strncmp("event", de->d_name, 5) == 0){ + char filename[64]; + int fd = -1; + char name[256] = "???"; + + sprintf(filename, "%s%s", "/dev/input/", de->d_name); + + fd = open(filename, O_RDONLY); + if(fd < 0) + continue; + + ioctl(fd, EVIOCGNAME(sizeof(name)), name); + printf("%i - (%s) %s\n", i, de->d_name, name); + device[i] = malloc(100); + strncpy(device[i], filename, sizeof(filename)); + i++; + } + } + device_count = i; + device = realloc(device, (i)* sizeof(char*)); + closedir(dr); +} + +void socket_connect(char* server_address){ + struct sockaddr_in serv_addr; + + if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){ + error_handling("Socket creation error"); + } + + memset(&serv_addr, '0', sizeof(serv_addr)); + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + // Convert IPv4 and IPv6 addresses from text to binary form + if(inet_pton(AF_INET, server_address, &serv_addr.sin_addr)<=0){ + error_handling("Invalid Address"); + } + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){ + error_handling("Connection Failed"); + } +} + +int main(int argc, char* argv[]){ + + char payload[6]; + socket_connect(argv[1]); + + int choice; + char* selected_dev; + + scan_devices(); + printf("Select Device: "); + scanf("%d", &choice); + selected_dev = *(device+choice); + + int fd = -1; + int rd; + struct input_event ev[64]; + int size = sizeof(struct input_event); + fd_set set; + + if((fd = open(selected_dev, O_RDONLY)) == 0){ + error_handling("cannot open device"); + } + + //Exclusive access + ioctl(fd, EVIOCGRAB, 1); + + FD_ZERO(&set); + FD_SET(fd, &set); + + while(1){ + select(fd+1, &set, NULL, NULL, NULL); + rd = read(fd, ev, sizeof(ev)); + + if(rd < size){ + error_handling("read error"); + } + + for(int i = 0; i < rd / size; i++){ + printf("%s: Type[%d] Code[%d] Value[%d]\n", selected_dev, ev[i].type, ev[i].code, ev[i].value); + + if(ev[i].type != 0){ + if(ev[i].type == 2) + sprintf(payload, "%d%d%03d", ev[i].type, ev[i].code, ev[i].value); + else if(ev[i].type == 1) + sprintf(payload, "%d%d%d", ev[i].type, ev[i].value, ev[i].code); + + send(sock , payload, 6, 0); + printf("%s", payload); + } + sleep(0); + } + usleep(10); + } + + ioctl(fd, EVIOCGRAB, 0); + close(sock); + close(fd); + return 0; +} \ No newline at end of file diff --git a/input_events.txt b/input_events.txt deleted file mode 100644 index 03b3fae..0000000 --- a/input_events.txt +++ /dev/null @@ -1,352 +0,0 @@ -The input protocol uses a map of types and codes to express input device values -to userspace. This document describes the types and codes and how and when they -may be used. - -A single hardware event generates multiple input events. Each input event -contains the new value of a single data item. A special event type, EV_SYN, is -used to separate input events into packets of input data changes occurring at -the same moment in time. In the following, the term "event" refers to a single -input event encompassing a type, code, and value. - -The input protocol is a stateful protocol. Events are emitted only when values -of event codes have changed. However, the state is maintained within the Linux -input subsystem; drivers do not need to maintain the state and may attempt to -emit unchanged values without harm. Userspace may obtain the current state of -event code values using the EVIOCG* ioctls defined in linux/input.h. The event -reports supported by a device are also provided by sysfs in -class/input/event*/device/capabilities/, and the properties of a device are -provided in class/input/event*/device/properties. - -Event types: -=========== -Event types are groupings of codes under a logical input construct. Each -type has a set of applicable codes to be used in generating events. See the -Codes section for details on valid codes for each type. - -* EV_SYN: - - Used as markers to separate events. Events may be separated in time or in - space, such as with the multitouch protocol. - -* EV_KEY: - - Used to describe state changes of keyboards, buttons, or other key-like - devices. - -* EV_REL: - - Used to describe relative axis value changes, e.g. moving the mouse 5 units - to the left. - -* EV_ABS: - - Used to describe absolute axis value changes, e.g. describing the - coordinates of a touch on a touchscreen. - -* EV_MSC: - - Used to describe miscellaneous input data that do not fit into other types. - -* EV_SW: - - Used to describe binary state input switches. - -* EV_LED: - - Used to turn LEDs on devices on and off. - -* EV_SND: - - Used to output sound to devices. - -* EV_REP: - - Used for autorepeating devices. - -* EV_FF: - - Used to send force feedback commands to an input device. - -* EV_PWR: - - A special type for power button and switch input. - -* EV_FF_STATUS: - - Used to receive force feedback device status. - -Event codes: -=========== -Event codes define the precise type of event. - -EV_SYN: ----------- -EV_SYN event values are undefined. Their usage is defined only by when they are -sent in the evdev event stream. - -* SYN_REPORT: - - Used to synchronize and separate events into packets of input data changes - occurring at the same moment in time. For example, motion of a mouse may set - the REL_X and REL_Y values for one motion, then emit a SYN_REPORT. The next - motion will emit more REL_X and REL_Y values and send another SYN_REPORT. - -* SYN_CONFIG: - - TBD - -* SYN_MT_REPORT: - - Used to synchronize and separate touch events. See the - multi-touch-protocol.txt document for more information. - -* SYN_DROPPED: - - Used to indicate buffer overrun in the evdev client's event queue. - Client should ignore all events up to and including next SYN_REPORT - event and query the device (using EVIOCG* ioctls) to obtain its - current state. - -EV_KEY: ----------- -EV_KEY events take the form KEY_ or BTN_. For example, KEY_A is used -to represent the 'A' key on a keyboard. When a key is depressed, an event with -the key's code is emitted with value 1. When the key is released, an event is -emitted with value 0. Some hardware send events when a key is repeated. These -events have a value of 2. In general, KEY_ is used for keyboard keys, and -BTN_ is used for other types of momentary switch events. - -A few EV_KEY codes have special meanings: - -* BTN_TOOL_: - - These codes are used in conjunction with input trackpads, tablets, and - touchscreens. These devices may be used with fingers, pens, or other tools. - When an event occurs and a tool is used, the corresponding BTN_TOOL_ - code should be set to a value of 1. When the tool is no longer interacting - with the input device, the BTN_TOOL_ code should be reset to 0. All - trackpads, tablets, and touchscreens should use at least one BTN_TOOL_ - code when events are generated. - -* BTN_TOUCH: - BTN_TOUCH is used for touch contact. While an input tool is determined to be - within meaningful physical contact, the value of this property must be set - to 1. Meaningful physical contact may mean any contact, or it may mean - contact conditioned by an implementation defined property. For example, a - touchpad may set the value to 1 only when the touch pressure rises above a - certain value. BTN_TOUCH may be combined with BTN_TOOL_ codes. For - example, a pen tablet may set BTN_TOOL_PEN to 1 and BTN_TOUCH to 0 while the - pen is hovering over but not touching the tablet surface. - -Note: For appropriate function of the legacy mousedev emulation driver, -BTN_TOUCH must be the first evdev code emitted in a synchronization frame. - -Note: Historically a touch device with BTN_TOOL_FINGER and BTN_TOUCH was -interpreted as a touchpad by userspace, while a similar device without -BTN_TOOL_FINGER was interpreted as a touchscreen. For backwards compatibility -with current userspace it is recommended to follow this distinction. In the -future, this distinction will be deprecated and the device properties ioctl -EVIOCGPROP, defined in linux/input.h, will be used to convey the device type. - -* BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP: - - These codes denote one, two, three, and four finger interaction on a - trackpad or touchscreen. For example, if the user uses two fingers and moves - them on the touchpad in an effort to scroll content on screen, - BTN_TOOL_DOUBLETAP should be set to value 1 for the duration of the motion. - Note that all BTN_TOOL_ codes and the BTN_TOUCH code are orthogonal in - purpose. A trackpad event generated by finger touches should generate events - for one code from each group. At most only one of these BTN_TOOL_ - codes should have a value of 1 during any synchronization frame. - -Note: Historically some drivers emitted multiple of the finger count codes with -a value of 1 in the same synchronization frame. This usage is deprecated. - -Note: In multitouch drivers, the input_mt_report_finger_count() function should -be used to emit these codes. Please see multi-touch-protocol.txt for details. - -EV_REL: ----------- -EV_REL events describe relative changes in a property. For example, a mouse may -move to the left by a certain number of units, but its absolute position in -space is unknown. If the absolute position is known, EV_ABS codes should be used -instead of EV_REL codes. - -A few EV_REL codes have special meanings: - -* REL_WHEEL, REL_HWHEEL: - - These codes are used for vertical and horizontal scroll wheels, - respectively. - -EV_ABS: ----------- -EV_ABS events describe absolute changes in a property. For example, a touchpad -may emit coordinates for a touch location. - -A few EV_ABS codes have special meanings: - -* ABS_DISTANCE: - - Used to describe the distance of a tool from an interaction surface. This - event should only be emitted while the tool is hovering, meaning in close - proximity of the device and while the value of the BTN_TOUCH code is 0. If - the input device may be used freely in three dimensions, consider ABS_Z - instead. - - BTN_TOOL_ should be set to 1 when the tool comes into detectable - proximity and set to 0 when the tool leaves detectable proximity. - BTN_TOOL_ signals the type of tool that is currently detected by the - hardware and is otherwise independent of ABS_DISTANCE and/or BTN_TOUCH. - -* ABS_MT_: - - Used to describe multitouch input events. Please see - multi-touch-protocol.txt for details. - -EV_SW: ----------- -EV_SW events describe stateful binary switches. For example, the SW_LID code is -used to denote when a laptop lid is closed. - -Upon binding to a device or resuming from suspend, a driver must report -the current switch state. This ensures that the device, kernel, and userspace -state is in sync. - -Upon resume, if the switch state is the same as before suspend, then the input -subsystem will filter out the duplicate switch state reports. The driver does -not need to keep the state of the switch at any time. - -EV_MSC: ----------- -EV_MSC events are used for input and output events that do not fall under other -categories. - -A few EV_MSC codes have special meaning: - -* MSC_TIMESTAMP: - - Used to report the number of microseconds since the last reset. This event - should be coded as an uint32 value, which is allowed to wrap around with - no special consequence. It is assumed that the time difference between two - consecutive events is reliable on a reasonable time scale (hours). - A reset to zero can happen, in which case the time since the last event is - unknown. If the device does not provide this information, the driver must - not provide it to user space. - -EV_LED: ----------- -EV_LED events are used for input and output to set and query the state of -various LEDs on devices. - -EV_REP: ----------- -EV_REP events are used for specifying autorepeating events. - -EV_SND: ----------- -EV_SND events are used for sending sound commands to simple sound output -devices. - -EV_FF: ----------- -EV_FF events are used to initialize a force feedback capable device and to cause -such device to feedback. - -EV_PWR: ----------- -EV_PWR events are a special type of event used specifically for power -management. Its usage is not well defined. To be addressed later. - -Device properties: -================= -Normally, userspace sets up an input device based on the data it emits, -i.e., the event types. In the case of two devices emitting the same event -types, additional information can be provided in the form of device -properties. - -INPUT_PROP_DIRECT + INPUT_PROP_POINTER: --------------------------------------- -The INPUT_PROP_DIRECT property indicates that device coordinates should be -directly mapped to screen coordinates (not taking into account trivial -transformations, such as scaling, flipping and rotating). Non-direct input -devices require non-trivial transformation, such as absolute to relative -transformation for touchpads. Typical direct input devices: touchscreens, -drawing tablets; non-direct devices: touchpads, mice. - -The INPUT_PROP_POINTER property indicates that the device is not transposed -on the screen and thus requires use of an on-screen pointer to trace user's -movements. Typical pointer devices: touchpads, tablets, mice; non-pointer -device: touchscreen. - -If neither INPUT_PROP_DIRECT or INPUT_PROP_POINTER are set, the property is -considered undefined and the device type should be deduced in the -traditional way, using emitted event types. - -INPUT_PROP_BUTTONPAD: --------------------- -For touchpads where the button is placed beneath the surface, such that -pressing down on the pad causes a button click, this property should be -set. Common in clickpad notebooks and macbooks from 2009 and onwards. - -Originally, the buttonpad property was coded into the bcm5974 driver -version field under the name integrated button. For backwards -compatibility, both methods need to be checked in userspace. - -INPUT_PROP_SEMI_MT: ------------------- -Some touchpads, most common between 2008 and 2011, can detect the presence -of multiple contacts without resolving the individual positions; only the -number of contacts and a rectangular shape is known. For such -touchpads, the semi-mt property should be set. - -Depending on the device, the rectangle may enclose all touches, like a -bounding box, or just some of them, for instance the two most recent -touches. The diversity makes the rectangle of limited use, but some -gestures can normally be extracted from it. - -If INPUT_PROP_SEMI_MT is not set, the device is assumed to be a true MT -device. - -INPUT_PROP_TOPBUTTONPAD: ------------------------ -Some laptops, most notably the Lenovo *40 series provide a trackstick -device but do not have physical buttons associated with the trackstick -device. Instead, the top area of the touchpad is marked to show -visual/haptic areas for left, middle, right buttons intended to be used -with the trackstick. - -If INPUT_PROP_TOPBUTTONPAD is set, userspace should emulate buttons -accordingly. This property does not affect kernel behavior. -The kernel does not provide button emulation for such devices but treats -them as any other INPUT_PROP_BUTTONPAD device. - -INPUT_PROP_ACCELEROMETER -------------------------- -Directional axes on this device (absolute and/or relative x, y, z) represent -accelerometer data. All other axes retain their meaning. A device must not mix -regular directional axes and accelerometer axes on the same event node. - -Guidelines: -========== -The guidelines below ensure proper single-touch and multi-finger functionality. -For multi-touch functionality, see the multi-touch-protocol.txt document for -more information. - -Mice: ----------- -REL_{X,Y} must be reported when the mouse moves. BTN_LEFT must be used to report -the primary button press. BTN_{MIDDLE,RIGHT,4,5,etc.} should be used to report -further buttons of the device. REL_WHEEL and REL_HWHEEL should be used to report -scroll wheel events where available. - -Touchscreens: ----------- -ABS_{X,Y} must be reported with the location of the touch. BTN_TOUCH must be -used to report when a touch is active on the screen. -BTN_{MOUSE,LEFT,MIDDLE,RIGHT} must not be reported as the result of touch -contact. BTN_TOOL_ events should be reported where possible. - -For new hardware, INPUT_PROP_DIRECT should be set. - -Trackpads: ----------- -Legacy trackpads that only provide relative position information must report -events like mice described above. - -Trackpads that provide absolute touch position must report ABS_{X,Y} for the -location of the touch. BTN_TOUCH should be used to report when a touch is active -on the trackpad. Where multi-finger support is available, BTN_TOOL_ should -be used to report the number of touches active on the trackpad. - -For new hardware, INPUT_PROP_POINTER should be set. - -Tablets: ----------- -BTN_TOOL_ events must be reported when a stylus or other tool is active on -the tablet. ABS_{X,Y} must be reported with the location of the tool. BTN_TOUCH -should be used to report when the tool is in contact with the tablet. -BTN_{STYLUS,STYLUS2} should be used to report buttons on the tool itself. Any -button may be used for buttons on the tablet except BTN_{MOUSE,LEFT}. -BTN_{0,1,2,etc} are good generic codes for unlabeled buttons. Do not use -meaningful buttons, like BTN_FORWARD, unless the button is labeled for that -purpose on the device. - -For new hardware, both INPUT_PROP_DIRECT and INPUT_PROP_POINTER should be set. \ No newline at end of file diff --git a/server/src/server.c b/server/src/server.c index c459f74..24c952d 100644 --- a/server/src/server.c +++ b/server/src/server.c @@ -29,7 +29,7 @@ struct uinput_setup usetup; //Key events must be defined in keys[] before using -int keys[] = {BTN_LEFT, BTN_RIGHT, KEY_VOLUMEUP, KEY_VOLUMEDOWN}; +int keys[] = {BTN_LEFT, BTN_RIGHT}; //Socket int server_fd; @@ -77,12 +77,17 @@ int socket_accept(){ int main(){ int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); - //Key events init + //Custom key events init ioctl(fd, UI_SET_EVBIT, EV_KEY); for(int i=0; i -#include -#include -#include -#include -#include -#include -#include //usleep, sleep, close, read, write -#include //printf, perror -#include //htons, sockaddr_in -#include //memset, strcpy, strlen -#include //open -#include //exit -#include -#include - -#define PORT 8080 //Socket port - -struct uinput_setup usetup; - -//Key events must be defined in keys[] before using -int keys[] = {BTN_LEFT, KEY_VOLUMEUP, KEY_VOLUMEDOWN}; - -int server_fd; -int new_socket, valread; -struct sockaddr_in address; -int opt = 1; -int addrlen = sizeof(address); - - -/* - * Sends input events -*/ -void emit(int fd, int type, int code, int val){ - struct input_event ie; - - ie.type = type; - ie.code = code; - ie.value = val; - /* timestamp values below are ignored */ - ie.time.tv_sec = 0; - ie.time.tv_usec = 0; - - write(fd, &ie, sizeof(ie)); -} - -static unsigned char rdesc[] = { - 0x05, 0x01, // Usage Page (Generic Desktop) 0 - 0x09, 0x02, // Usage (Mouse) 2 - 0xa1, 0x01, // Collection (Application) 4 - 0x85, 0x01, // Report ID (1) 6 - 0x09, 0x01, // Usage (Pointer) 8 - 0xa1, 0x00, // Collection (Physical) 10 - 0x05, 0x09, // Usage Page (Button) 12 - 0x19, 0x01, // Usage Minimum (1) 14 - 0x29, 0x08, // Usage Maximum (8) 16 - 0x15, 0x00, // Logical Minimum (0) 18 - 0x25, 0x01, // Logical Maximum (1) 20 - 0x95, 0x08, // Report Count (8) 22 - 0x75, 0x01, // Report Size (1) 24 - 0x81, 0x02, // Input (Data,Var,Abs) 26 - 0x05, 0x01, // Usage Page (Generic Desktop) 28 - 0x16, 0x01, 0xf8, // Logical Minimum (-2047) 30 - 0x26, 0xff, 0x07, // Logical Maximum (2047) 33 - 0x75, 0x0c, // Report Size (12) 36 - 0x95, 0x02, // Report Count (2) 38 - 0x09, 0x30, // Usage (X) 40 - 0x09, 0x31, // Usage (Y) 42 - 0x81, 0x06, // Input (Data,Var,Rel) 44 - 0x15, 0x81, // Logical Minimum (-127) 46 - 0x25, 0x7f, // Logical Maximum (127) 48 - 0x75, 0x08, // Report Size (8) 50 - 0x95, 0x01, // Report Count (1) 52 - 0x09, 0x38, // Usage (Wheel) 54 - 0x81, 0x06, // Input (Data,Var,Rel) 56 - 0xc0, // End Collection 58 - 0xc0, // End Collection 59 - 0x05, 0x01, // Usage Page (Generic Desktop) 60 - 0x09, 0x06, // Usage (Keyboard) 62 - 0xa1, 0x01, // Collection (Application) 64 - 0x85, 0x08, // Report ID (8) 66 - 0x05, 0x07, // Usage Page (Keyboard) 68 - 0x19, 0xe0, // Usage Minimum (224) 70 - 0x29, 0xe7, // Usage Maximum (231) 72 - 0x15, 0x00, // Logical Minimum (0) 74 - 0x25, 0x01, // Logical Maximum (1) 76 - 0x75, 0x01, // Report Size (1) 78 - 0x95, 0x08, // Report Count (8) 80 - 0x81, 0x02, // Input (Data,Var,Abs) 82 - 0x05, 0x07, // Usage Page (Keyboard) 84 - 0x19, 0x00, // Usage Minimum (0) 86 - 0x29, 0x97, // Usage Maximum (151) 88 - 0x15, 0x00, // Logical Minimum (0) 90 - 0x25, 0x01, // Logical Maximum (1) 92 - 0x75, 0x01, // Report Size (1) 94 - 0x96, 0x98, 0x00, // Report Count (152) 96 - 0x81, 0x02, // Input (Data,Var,Abs) 99 - 0xc0, // End Collection 101 - 0x06, 0x03, 0xff, // Usage Page (Vendor Usage Page 0xff03) 102 - 0x0a, 0x02, 0x24, // Usage (Vendor Usage 0x2402) 105 - 0xa1, 0x01, // Collection (Application) 108 - 0x85, 0x03, // Report ID (3) 110 - 0x19, 0x01, // Usage Minimum (1) 112 - 0x29, 0x29, // Usage Maximum (41) 114 - 0x15, 0x00, // Logical Minimum (0) 116 - 0x25, 0xff, // Logical Maximum (255) 118 - 0x75, 0x08, // Report Size (8) 120 - 0x95, 0x29, // Report Count (41) 122 - 0x81, 0x00, // Input (Data,Arr,Abs) 124 - 0x19, 0x01, // Usage Minimum (1) 126 - 0x29, 0x1f, // Usage Maximum (31) 128 - 0x15, 0x00, // Logical Minimum (0) 130 - 0x25, 0xff, // Logical Maximum (255) 132 - 0x75, 0x08, // Report Size (8) 134 - 0x95, 0x29, // Report Count (41) 136 - 0xb1, 0x02, // Feature (Data,Var,Abs) 138 - 0xc0, // End Collection 140 - 0x05, 0x0c, // Usage Page (Consumer Devices) 141 - 0x09, 0x01, // Usage (Consumer Control) 143 - 0xa1, 0x01, // Collection (Application) 145 - 0x85, 0x04, // Report ID (4) 147 - 0x19, 0x00, // Usage Minimum (0) 149 - 0x2a, 0x9c, 0x02, // Usage Maximum (668) 151 - 0x15, 0x00, // Logical Minimum (0) 154 - 0x26, 0x9c, 0x02, // Logical Maximum (668) 156 - 0x75, 0x10, // Report Size (16) 159 - 0x95, 0x01, // Report Count (1) 161 - 0x81, 0x00, // Input (Data,Arr,Abs) 163 - 0xc0, // End Collection 165 - 0x05, 0x01, // Usage Page (Generic Desktop) 166 - 0x09, 0x80, // Usage (System Control) 168 - 0xa1, 0x01, // Collection (Application) 170 - 0x85, 0x05, // Report ID (5) 172 - 0x1a, 0x81, 0x00, // Usage Minimum (129) 174 - 0x2a, 0x83, 0x00, // Usage Maximum (131) 177 - 0x15, 0x00, // Logical Minimum (0) 180 - 0x25, 0x01, // Logical Maximum (1) 182 - 0x75, 0x01, // Report Size (1) 184 - 0x95, 0x03, // Report Count (3) 186 - 0x81, 0x02, // Input (Data,Var,Abs) 188 - 0x95, 0x05, // Report Count (5) 190 - 0x81, 0x01, // Input (Cnst,Arr,Abs) 192 - 0xc0, // End Collection 194 -}; - - -static int uhid_write(int fd, const struct uhid_event *ev) -{ - ssize_t ret; - - ret = write(fd, ev, sizeof(*ev)); - if (ret < 0) { - fprintf(stderr, "Cannot write to uhid: %m\n"); - return -errno; - } else if (ret != sizeof(*ev)) { - fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n", - ret, sizeof(ev)); - return -EFAULT; - } else { - return 0; - } -} - -static int create(int fd) -{ - struct uhid_event ev; - - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_CREATE; - strcpy((char*)ev.u.create.name, "test-uhid-device"); - ev.u.create.rd_data = rdesc; - ev.u.create.rd_size = sizeof(rdesc); - ev.u.create.bus = BUS_USB; - ev.u.create.vendor = 0x15d9; - ev.u.create.product = 0x0a37; - ev.u.create.version = 0; - ev.u.create.country = 0; - - return uhid_write(fd, &ev); -} - -static void destroy(int fd) -{ - struct uhid_event ev; - - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_DESTROY; - - uhid_write(fd, &ev); -} - -/* This parses raw output reports sent by the kernel to the device. A normal - * uhid program shouldn't do this but instead just forward the raw report. - * However, for ducomentational purposes, we try to detect LED events here and - * print debug messages for it. */ -static void handle_output(struct uhid_event *ev) -{ - /* LED messages are adverised via OUTPUT reports; ignore the rest */ - if (ev->u.output.rtype != UHID_OUTPUT_REPORT) - return; - /* LED reports have length 2 bytes */ - if (ev->u.output.size != 2) - return; - /* first byte is report-id which is 0x02 for LEDs in our rdesc */ - if (ev->u.output.data[0] != 0x2) - return; - - /* print flags payload */ - fprintf(stderr, "LED output report received with flags %x\n", - ev->u.output.data[1]); -} - -static int event(int fd) -{ - struct uhid_event ev; - ssize_t ret; - - memset(&ev, 0, sizeof(ev)); - ret = read(fd, &ev, sizeof(ev)); - if (ret == 0) { - fprintf(stderr, "Read HUP on uhid-cdev\n"); - return -EFAULT; - } else if (ret < 0) { - fprintf(stderr, "Cannot read uhid-cdev: %m\n"); - return -errno; - } else if (ret != sizeof(ev)) { - fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n", - ret, sizeof(ev)); - return -EFAULT; - } - - switch (ev.type) { - case UHID_START: - fprintf(stderr, "UHID_START from uhid-dev\n"); - break; - case UHID_STOP: - fprintf(stderr, "UHID_STOP from uhid-dev\n"); - break; - case UHID_OPEN: - fprintf(stderr, "UHID_OPEN from uhid-dev\n"); - break; - case UHID_CLOSE: - fprintf(stderr, "UHID_CLOSE from uhid-dev\n"); - break; - case UHID_OUTPUT: - fprintf(stderr, "UHID_OUTPUT from uhid-dev\n"); - handle_output(&ev); - break; - case UHID_OUTPUT_EV: - fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n"); - break; - default: - fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type); - } - - return 0; -} - -static bool btn1_down; -static bool btn2_down; -static bool btn3_down; -static signed char abs_hor; -static signed char abs_ver; -static signed char wheel; - -static int send_event(int fd) -{ - struct uhid_event ev; - - memset(&ev, 0, sizeof(ev)); - ev.type = UHID_INPUT; - ev.u.input.size = 3; - - ev.u.input.data[0] = 0x0; - if (btn1_down) - ev.u.input.data[0] = 0x1; - - //ev.u.input.data[0] = 0x1; left button - //ev.u.input.data[0] = 0x3, 0x4; right button - //ev.u.input.data[0] = 0x4; middle button - if (btn2_down) - ev.u.input.data[0] = 0x4; - - ev.u.input.data[1] = abs_hor; - ev.u.input.data[2] = abs_ver; - ev.u.input.data[4] = wheel; - - return uhid_write(fd, &ev); -} - -static int keyboard(int fd) -{ - char buf[128]; - ssize_t ret, i; - - ret = read(STDIN_FILENO, buf, sizeof(buf)); - if (ret == 0) { - fprintf(stderr, "Read HUP on stdin\n"); - return -EFAULT; - } else if (ret < 0) { - fprintf(stderr, "Cannot read stdin: %m\n"); - return -errno; - } - - for (i = 0; i < ret; ++i) { - switch (buf[i]) { - case '1': - btn1_down = !btn1_down; - ret = send_event(fd); - if (ret) - return ret; - break; - case '2': - btn2_down = !btn2_down; - ret = send_event(fd); - if (ret) - return ret; - break; - case '3': - btn3_down = !btn3_down; - ret = send_event(fd); - if (ret) - return ret; - break; - case 'a': - abs_hor = -20; - ret = send_event(fd); - abs_hor = 0; - if (ret) - return ret; - break; - case 'd': - abs_hor = 20; - ret = send_event(fd); - abs_hor = 0; - if (ret) - return ret; - break; - case 'w': - abs_ver = -20; - ret = send_event(fd); - abs_ver = 0; - if (ret) - return ret; - break; - case 's': - abs_ver = 20; - ret = send_event(fd); - abs_ver = 0; - if (ret) - return ret; - break; - case 'r': - wheel = 1; - ret = send_event(fd); - wheel = 0; - if (ret) - return ret; - break; - case 'f': - wheel = -1; - ret = send_event(fd); - wheel = 0; - if (ret) - return ret; - break; - case 'q': - return -ECANCELED; - default: - fprintf(stderr, "Invalid input: %c\n", buf[i]); - } - } - - return 0; -} - -int main(int argc, char **argv){ - int fd; - const char *path = "/dev/uhid"; - struct pollfd pfds[2]; - int ret; - struct termios state; - - ret = tcgetattr(STDIN_FILENO, &state); - if (ret) { - fprintf(stderr, "Cannot get tty state\n"); - } else { - state.c_lflag &= ~ICANON; - state.c_cc[VMIN] = 1; - ret = tcsetattr(STDIN_FILENO, TCSANOW, &state); - if (ret) - fprintf(stderr, "Cannot set tty state\n"); - } - - if (argc >= 2) { - if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { - fprintf(stderr, "Usage: %s [%s]\n", argv[0], path); - return EXIT_SUCCESS; - } else { - path = argv[1]; - } - } - - fprintf(stderr, "Open uhid-cdev %s\n", path); - fd = open(path, O_RDWR | 0); - if (fd < 0) { - fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path); - return EXIT_FAILURE; - } - - fprintf(stderr, "Create uhid device\n"); - ret = create(fd); - if (ret) { - close(fd); - return EXIT_FAILURE; - } - - pfds[0].fd = STDIN_FILENO; - pfds[0].events = POLLIN; - pfds[1].fd = fd; - pfds[1].events = POLLIN; - - //EVENT - int fds = open("/dev/uinput", O_WRONLY | O_NONBLOCK); - - //Key events init - ioctl(fds, UI_SET_EVBIT, EV_KEY); - for(int i=0; i +#include +#include +#include +#include +#include +#include +#include + +#define PORT 8080 + +void error_handling(char* msg){ + perror(msg); + exit(EXIT_FAILURE); +} + +// Driver code +int main() { + int sockfd; + struct sockaddr_in servaddr; + + // Creating socket file descriptor + if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ){ + error_handling("socket creation failed"); + } + + memset(&servaddr, 0, sizeof(servaddr)); + + // Filling server information + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(PORT); + servaddr.sin_addr.s_addr = INADDR_ANY; + + int n, len; + + char *hello = "Hello from client"; + sendto(sockfd, (const char *)hello, strlen(hello), MSG_CONFIRM, (const struct sockaddr *) &servaddr, sizeof(servaddr)); + + close(sockfd); + return 0; +} diff --git a/test/ideas/udp_server.c b/test/ideas/udp_server.c new file mode 100644 index 0000000..20d6640 --- /dev/null +++ b/test/ideas/udp_server.c @@ -0,0 +1,49 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT 8080 + +void error_handling(char* msg){ + perror(msg); + exit(EXIT_FAILURE); +} + +int main() { + int sockfd; + char buffer[1024]; + struct sockaddr_in servaddr, cliaddr; + + // Creating socket file descriptor + if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ){ + error_handling("socket creation failed"); + } + + memset(&servaddr, 0, sizeof(servaddr)); + memset(&cliaddr, 0, sizeof(cliaddr)); + + servaddr.sin_family = AF_INET; // IPv4 + servaddr.sin_addr.s_addr = INADDR_ANY; + servaddr.sin_port = htons(PORT); + + // Bind the socket with the server address + if(bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0 ) { + error_handling("bind failed"); + } + + while(1){ + int len, n; + n = recvfrom(sockfd, (char *)buffer, 1024, MSG_WAITALL | SO_REUSEADDR, ( struct sockaddr *) &cliaddr, &len); + buffer[n] = '\0'; + + printf("Client : %s\n", buffer); + usleep(100); + } + + return 0; +} diff --git a/test/integration/device_client.c b/test/integration/device_client.c deleted file mode 100644 index 565d5ae..0000000 --- a/test/integration/device_client.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Author: Nuri Melih Sensoy - * github.com/nmelihsensoy - * File: "device_client.c" - * - * This client sends real device events -*/ -#include -#include -#include -#include -#include -#include -#include -#include - -#define PORT 8080 //Socket Port - -struct event_device{ - char *device; - int fd; -}; - -int main(int argc, char* argv[]){ - - //Socket - int sock = 0; - struct sockaddr_in serv_addr; - char payload[5]; - - //HID - struct input_event ev[64]; - int numevents; - int result = 0; - int size = sizeof(struct input_event); - int rd; - char name[256]; - char* device[12]; - struct event_device evdevs[12], *evdev; - int numevdevs = 0; - fd_set fds; - int maxfd; - - //device[0] = "/dev/input/event21"; - device[0] = argv[2]; - //device[1] = "/dev/input/event18"; - - for(int i = 0; i < 1; ++i){ - evdev = &evdevs[numevdevs]; - - evdev->device = device[i]; - evdev->fd = open(evdev->device, O_RDONLY); - if (evdev->fd == -1) { - printf("Failed to open event device: %s.\n", evdev->device); - continue; - } - ++numevdevs; - - memset(name, 0, sizeof(name)); - result = ioctl(evdev->fd, EVIOCGNAME(sizeof(name)), name); - printf ("Reading From : %s (%s)\n", evdev->device, name); - - printf("Getting exclusive access: "); - result = ioctl(evdev->fd, EVIOCGRAB, 1); - printf("%s\n", (result == 0) ? "SUCCESS" : "FAILURE"); - } - - if(numevdevs == 0){ - exit(1); - } - - //Socket - if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){ - printf("Socket creation error \n"); - exit(EXIT_FAILURE); - } - - memset(&serv_addr, '0', sizeof(serv_addr)); - - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(PORT); - - // Convert IPv4 and IPv6 addresses from text to binary form - if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0){ - printf("\nInvalid address/ Address not supported \n"); - exit(EXIT_FAILURE); - } - - if(connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){ - printf("Connection Failed \n"); - exit(EXIT_FAILURE); - } - - while(1){ - - FD_ZERO(&fds); - maxfd = -1; - for(int i = 0; i < numevdevs; ++i){ - evdev = &evdevs[i]; - FD_SET(evdev->fd, &fds); - if (maxfd < evdev->fd) maxfd = evdev->fd; - } - - result = select(maxfd+1, &fds, NULL, NULL, NULL); - if(result == -1){ - break; - } - - for(int i = 0; i < numevdevs; ++i){ - evdev = &evdevs[i]; - - if(!FD_ISSET(evdev->fd, &fds)){ - continue; - } - - if((rd = read(evdev->fd, ev, size * 64)) < size){ - continue; - } - - numevents = rd / size; - - for(int j = 0; j < numevents; ++j){ - printf ("%s: Type[%d] Code[%d] Value[%d]\n", evdev->device, ev[j].type, ev[j].code, ev[j].value); - if(ev[j].type != 0){ - if(ev[j].type == 2) - sprintf(payload, "%d%d%03d", ev[j].type, ev[j].code, ev[j].value); - else if(ev[j].type == 1) - sprintf(payload, "%d%d%d", ev[j].type, ev[j].value, ev[j].code); - - send(sock , payload, 6, 0); - } - } - sleep(0); - } - usleep(10); - } - - for(int i = 0; i < numevdevs; ++i){ - evdev = &evdevs[i]; - result = ioctl(evdev->fd, EVIOCGRAB, 0); - close(evdev->fd); - } - - close(sock); - - return 0; -} \ No newline at end of file diff --git a/test/units/debug_device.c b/test/units/debug_device.c deleted file mode 100644 index d9bb443..0000000 --- a/test/units/debug_device.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include -#include -#include -#include - -struct event_device{ - char *device; - int fd; -}; - -int main(int argc, char* argv[]){ - struct input_event ev[64]; - int numevents; - int result = 0; - int size = sizeof(struct input_event); - int rd; - char name[256]; - char* device[12]; - struct event_device evdevs[12], *evdev; - int numevdevs = 0; - fd_set fds; - int maxfd; - - device[0] = "/dev/input/event11"; - device[1] = "/dev/input/event18"; - - for (int i = 0; i < 1; ++i){ - evdev = &evdevs[numevdevs]; - - evdev->device = device[i]; - evdev->fd = open(evdev->device, O_RDONLY); - if (evdev->fd == -1) { - printf("Failed to open event device: %s.\n", evdev->device); - continue; - } - ++numevdevs; - - memset(name, 0, sizeof(name)); - result = ioctl(evdev->fd, EVIOCGNAME(sizeof(name)), name); - printf ("Reading From : %s (%s)\n", evdev->device, name); - - printf("Getting exclusive access: "); - result = ioctl(evdev->fd, EVIOCGRAB, 1); - printf("%s\n", (result == 0) ? "SUCCESS" : "FAILURE"); - } - - if (numevdevs == 0){ - exit(1); - } - - while (1){ - FD_ZERO(&fds); - maxfd = -1; - - for(int i = 0; i < numevdevs; ++i){ - evdev = &evdevs[i]; - FD_SET(evdev->fd, &fds); - if (maxfd < evdev->fd) maxfd = evdev->fd; - } - - result = select(maxfd+1, &fds, NULL, NULL, NULL); - if(result == -1){ - break; - } - - for(int i = 0; i < numevdevs; ++i){ - evdev = &evdevs[i]; - - if(!FD_ISSET(evdev->fd, &fds)){ - continue; - } - - if ((rd = read(evdev->fd, ev, size * 64)) < size) { - continue; - } - - numevents = rd / size; - for (int j = 0; j < numevents; ++j) { - printf ("%s: Type[%d] Code[%d] Value[%d]\n", evdev->device, ev[j].type, ev[j].code, ev[j].value); - } - } - } - - printf("Exiting.\n"); - - for(int i = 0; i < numevdevs; ++i){ - evdev = &evdevs[i]; - result = ioctl(evdev->fd, EVIOCGRAB, 0); - close(evdev->fd); - } - - return 0; -} \ No newline at end of file diff --git a/test/units/dev_debug.c b/test/units/dev_debug.c new file mode 100644 index 0000000..9add250 --- /dev/null +++ b/test/units/dev_debug.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +int device_count = 0; +char **device; + +void error_handling(char *msg){ + perror(msg); + exit(EXIT_FAILURE); +} + +void scan_devices(){ + struct dirent *de; + int i=0; + + DIR *dr = opendir("/dev/input"); + + if (dr == NULL){ + error_handling("Could not open directory"); + } + + device = malloc(50 * sizeof(char*)); + + while((de = readdir(dr)) != NULL){ + if(strncmp("event", de->d_name, 5) == 0){ + char filename[64]; + int fd = -1; + char name[256] = "???"; + + sprintf(filename, "%s%s", "/dev/input/", de->d_name); + + fd = open(filename, O_RDONLY); + if(fd < 0) + continue; + + ioctl(fd, EVIOCGNAME(sizeof(name)), name); + printf("%i - (%s) %s\n", i, de->d_name, name); + device[i] = malloc(100); + strncpy(device[i], filename, sizeof(filename)); + i++; + } + } + device_count = i; + device = realloc(device, (i)* sizeof(char*)); + closedir(dr); +} + +void print_events(char* device){ + int fd = -1; + int rd; + struct input_event ev[64]; + int size = sizeof(struct input_event); + fd_set set; + + if((fd = open(device, O_RDONLY)) == 0){ + error_handling("cannot open device"); + } + + FD_ZERO(&set); + FD_SET(fd, &set); + + while(1){ + select(fd+1, &set, NULL, NULL, NULL); + rd = read(fd, ev, sizeof(ev)); + + if(rd < (int)sizeof(struct input_event)){ + error_handling("read error"); + } + + for (int i = 0; i < rd / sizeof(struct input_event); i++){ + printf("%s: Type[%d] Code[%d] Value[%d]\n", device, ev[i].type, ev[i].code, ev[i].value); + } + + } + + close(fd); +} + +int main(){ + + int choice; + scan_devices(); + printf("Select Event: "); + scanf("%d", &choice); + print_events(*(device+choice)); + + //printf("%s", *(device+choice)); + + return 0; +} \ No newline at end of file diff --git a/test/units/event_hid.c b/test/units/event_hid.c new file mode 100644 index 0000000..1ba41ab --- /dev/null +++ b/test/units/event_hid.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + + +int main(int argc, char* argv[]){ + + int fd = -1; + int rd; + char event[256]; + struct input_event ev[64]; + int size = sizeof(struct input_event); + fd_set set; + + fd = open(argv[1], O_RDONLY); + //ioctl(fd, EVIOCGRAB, 1); + + FD_ZERO(&set); + FD_SET(fd, &set); + + while (1) { + select(fd + 1, &set, NULL, NULL, NULL); + + rd = read(fd, ev, sizeof(ev)); + + if (rd < (int) sizeof(struct input_event)){ + printf("expected %d bytes, got %d\n", (int) sizeof(struct input_event), rd); + perror("\nevtest: error reading"); + return 1; + } + + for (int i = 0; i < rd / sizeof(struct input_event); i++){ + printf ("%s: Type[%d] Code[%d] Value[%d]\n", argv[i+1], ev[i].type, ev[i].code, ev[i].value); + } + + } + + //ioctl(fd, EVIOCGRAB, 0); + close(fd); + return 0; +} \ No newline at end of file diff --git a/test/units/list_hid.c b/test/units/list_hid.c new file mode 100644 index 0000000..7cc607b --- /dev/null +++ b/test/units/list_hid.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +int main(){ + struct dirent *de; + + DIR *dr = opendir("/dev/input"); + + if (dr == NULL){ + printf("Could not open directory"); + return 0; + } + + while ((de = readdir(dr)) != NULL){ + if(strncmp("event", de->d_name, 5) == 0){ + char filename[64]; + int fd = -1; + char name[256] = "???"; + + sprintf(filename, "%s%s", "/dev/input/", de->d_name); + + fd = open(filename, O_RDONLY); + if(fd < 0) + continue; + + ioctl(fd, EVIOCGNAME(sizeof(name)), name); + printf("%s %s\n", name, de->d_name); + + } + } + + closedir(dr); + return 0; +} \ No newline at end of file