I've been using the following C code to try to simulate keystrokes on a CentOS 6.0 machine:
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#inlcude <linux/input.h>
#include <linux/uinput.h>
#include <sys/time.h>
static int fd = -1;
struct uinput_user_dev uidev;
struct input_event event;
int main()
{
int i;
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
memset(&uidev, 0, sizeof(uidev));
snrpintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-kbd");
uidev.id.version = 1;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.bustype = BUS_USB;
ioctl(fd, UI_SET_EVBIT, EV_KEY);
for(i = 0; i < 256; i++)
{
ioctl(fd, UI_SET_KEYBIT, i);
}
ioctl(fd, UI_SET_EVBIT, EV_SYN);
write(fd, &uidev, sizeof(uidev));
ioctl(fd, UI_DEV_CREATE));
memset(&event, 0, sizeof(event));
gettimeofday(&event.time, NULL);
event.type = EV_KEY;
event.code = KEY_1;
event.value = 1;
write(fd, &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write(fd, &event, sizeof(event));
memset(&event, 0, sizeof(event));
gettimeofday(&event.time, NULL);
event.type = EV_KEY;
event.code = KEY_1;
event.value = 0;
write(fd, &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write(fd, &event, sizeof(event));
ioctl(fd, UI_DEV_DESTROY);
close(fd);
return 0;
}
If I'm correct, this code should create a virtual input device on the machine and then press the "1" key on that device. And when I execute the code, it seems to run without any issues (I haven't include the code that checks to make sure the device is being created and the keystrokes are being written, etc, in my example code, because it would have gotten way too long), but I can't see any sign of the actual keystroke.
My impression was that if I run this from a terminal window while logged directly into the machine, I should see a "1" character appear on the terminal window that I'm running it from. And if I log into the machine via ssh and run it that way, the keystroke should register on the machine rather than the ssh session. But I'm not getting anything in either situation.
Am I misunderstanding the purpose of this code? Have I done it wrong? Or is the more that I need to add to properly simulate a keystroke?
Wow, I was having the same issue as you just a few minutes ago, but now I don't have the issue anymore, and according to evtest it seems to work. I don't know what I did that resolved the problem unfortunately.
Here's the steps I used to troubleshoot, hopefully that at least gets you somewhere:
Verify that dmesg reports input device when connected.
Example:
[Fri Jul 22 22:38:55 2022] input: Custom Tourbox TBG_H Driver as /devices/virtual/input/input25
Verify that program can write to /dev/uinput file. Can be done via checking return value of write() call (the example code you listed doesn't).
If you have any issues with the above, double-check permissions. ( I did the hack of running my program as root and then changing the permission on the /dev/uinput file to be world-writable, via:
$ chmod +0666 /dev/uinput
This probably isn't recommended though, it would probably be better to create a group and then add your user to that group )
Verify that evtest recognizes your new driver.
Run:
$ sudo evtest
And you should see your device (probably at the bottom):
/dev/input/event24: Custom Tourbox TBG_H Driver
Verify that evtest recognizes that your device has registered an event handler for the keys you wish to use. In my case, I need to simulate key presses for 'a', so I made sure to verify that key was listed as one of the possible event types:
This is what the example output looked like:
Input driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x483 product 0xbeef version 0x0
Input device name: "Custom Tourbox TBG_H Driver"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 30 (KEY_A)
From there, all I did was press the key and it worked.
Here now I found why this can't work, I spend two days finding the problem. Luckily and finally, I found it in linux kernel 5.60 source example which is in chapter 7.4. Here is the picture .Solution
the document said that we'd better wait for some time so that there is a space for userspace to detect event, because creating a device node in kernel state will spend lots of time compared to sending a event to fd, hopes that the answer is not too late.
Here is the link 7.Uinput-module
Related
I am trying to implement ZeroMQ to get an application on a Raspberry Pi 3 (Raspbian Stretch) to communicate with an application on a separate machine (in this case Windows 7 64bit OS) linked by a wired or WLAN connection.
I have compiled ZeroMQ with the C library interface on both machines (using Cygwin on Windows) and the Hello World example (which I modified slightly to print the pointer values to assure me that the functions were 'working'). Both machines are connected (in this case via a wired Ethernet link and a router) and the connection is good (I link to RPi from PC via Xrdp or SSH OK).
The problem I have is that the client/server ZeroMQ programs don't appear to be 'seeing' each other even though they do appear to work and my question is: What are the first steps I should take to investigate why this is happening? Are there any commandline or GUI tools that can help me find out what's causing the blockage? (like port activity monitors or something?).
I know very little about networking so consider me a novice in all things sockety/servicey in your reply. The source code on the RPi (server) is:
// ZeroMQ Test Server
// Compile with
// gcc -o zserver zserver.c -lzmq
#include <zmq.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
int main (void)
{
void *context=NULL,*responder=NULL;
int rc=1;
// Socket to talk to clients
context = zmq_ctx_new ();
printf("Context pointer = %p\n",context);
responder = zmq_socket (context, ZMQ_REP);
printf("Responder pointer = %p\n",responder);
rc = zmq_bind (responder, "tcp://*:5555");
printf("rc = %d\n",rc);
assert (rc == 0);
while (1) {
char buffer [10];
zmq_recv (responder, buffer, 10, 0);
printf ("Received Hello\n");
sleep (1); // Do some 'work'
zmq_send (responder, "World", 5, 0);
}
return 0;
}
The source code on the PC (Cygwin) client is:
// ZeroMQ Test Client
// Compile with:
// gcc -o zclient zclient.c -L/usr/local/lib -lzmq
#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int main (void)
{
void *context=NULL,*requester=NULL;
printf ("Connecting to hello world server\n");
context = zmq_ctx_new ();
printf("Context pointer = %p\n",context);
requester = zmq_socket (context, ZMQ_REQ);
printf("Requester pointer = %p\n",requester);
zmq_connect (requester, "tcp://localhost:5555");
int request_nbr;
for (request_nbr = 0; request_nbr != 10; request_nbr++) {
char buffer [10];
printf ("Sending Hello %d\n", request_nbr);
zmq_send (requester, "Hello", 5, 0);
zmq_recv (requester, buffer, 10, 0);
printf ("Received World %d\n", request_nbr);
}
zmq_close (requester);
zmq_ctx_destroy (context);
return 0;
}
On the RPi LXTerminal I run the server and get this:
Context pointer = 0xefe308
Responder pointer = 0xf00e08
rc = 0
and on the Cygwin Bash shell I run the client and get this:
Connecting to hello world server
Context pointer = 0x60005ab90
Requester pointer = 0x60005f890
Sending Hello 0
... and there they both hang - one listening, the other sending but neither responding to each other.
Any clue how to start investigating this would be appreciated.
+1 for a care using explicit zmq_close() and zmq_ctx_term() release of resources ...
In case this is the first time to work with ZeroMQ,
one may here enjoy to first look at "ZeroMQ Principles in less than Five Seconds" before diving into further details
Q : What are the first steps I should take to investigate why this is happening?
A Line-of-Sight test as a step zero makes no sense here.
All localhost-placed interfaces are hard to not "see" one another.
Next, test as a first step call { .bind() | .connect() }-methods using an explicit address like tcp://127.0.0.1:56789 ( so as to avoid the expansion of both the *-wildcard and the localhost-symbolic name translations )
Always be ready to read/evaluate the API-provided errno that ZeroMQ keeps reporting about the last ZeroMQ API-operation resultin error-state.
Best read the ZeroMQ native API documentation, which is well maintained from version to version, so as to fully understand the comfort of API designed signaling/messaging meta-plane.
Mea Culpa: the LoS is sure not to have been established by the O/P code:
RPi .bind()-s on it's local I/F ( and cannot otherwise )
PC .connect()-s not to that of RPi, but the PC's local I/F
PC .connect( "tcp://<address_of_RPi>:5555" ) will make it ( use the same IP-address as you use in Xrdp or SSH to connect to RPi or may read one explicitly from RPi CLI-terminal after ~$ ip address and use that one for PC-side client code )
Two disjoint ZeroMQ AccessPoint-s have zero way how to communicate,once no transport-"wire" from A to B
// Zero MQ Test Server
// Compile with
// gcc -o zserver zserver.c -lzmq
#include <zmq.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
int main (void)
{
void *context=NULL,*responder=NULL;
int rc=1;
// Socket to talk to clients
context = zmq_ctx_new (); printf("Context pointer = %p\n",context);
responder = zmq_socket (context, ZMQ_REP); printf("Responder pointer = %p\n",responder);
rc = zmq_bind (responder, "tcp://*:5555"); printf("rc = %d\n",rc);
/* ----------------------------------^^^^^^------------RPi interface-----------*/
assert (rc == 0);
while (1) {
char buffer [10];
zmq_recv (responder, buffer, 10, 0); printf("Received Hello\n");
sleep (1); // Do some 'work'
zmq_send (responder, "World", 5, 0);
}
return 0;
}
The source code on the PC (Cygwin) client is:
// ZeroMQ Test Client
// Compile with:
// gcc -o zclient zclient.c -L/usr/local/lib -lzmq
#include <zmq.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int main (void)
{
void *context=NULL,*requester=NULL;
printf("Connecting to hello world server\n");
context = zmq_ctx_new (); printf("Context pointer = %p\n",context);
requester = zmq_socket (context, ZMQ_REQ); printf("Requester pointer = %p\n",requester);
zmq_connect (requester, "tcp://localhost:5555");
/*---------------------------------^^^^^^^^^^^^^^---------PC-local-interface------*/
int request_nbr;
for (request_nbr = 0; request_nbr != 10; request_nbr++) {
char buffer [10]; printf("Sending Hello %d\n", request_nbr);
zmq_send (requester, "Hello", 5, 0);
zmq_recv (requester, buffer, 10, 0); printf("Received World %d\n", request_nbr);
}
zmq_close (requester);
zmq_ctx_destroy (context);
return 0;
}
May like to also read more on ZeroMQ-related subjects here
Epilogue :
The trouble reported in the O/P is actually masked and remains hidden from being detectable by the API. ZeroMQ permits one AccessPoint to have 0+ transport-class-connections simultaneously, given a proper syntax and other conditions are met.
A call tozmq_connect( reguester, "tcp://<address-not-intended-but-correct>:<legal-port>" ) will result in legally-fair state and none of the defined and documented cases of possible error-states would get reported, because none of all such cases did actually happen:
EINVAL
The endpoint supplied is invalid.
EPROTONOSUPPORT
The requested transport protocol is not supported.
ENOCOMPATPROTO
The requested transport protocol is not compatible with the socket type.
ETERM
The ØMQ context associated with the specified socket was terminated.
ENOTSOCK
The provided socket was invalid.
EMTHREAD
No I/O thread is available to accomplish the task.
There are some chances to at least somehow-"detect" the trouble would be to enforce another sort of exception/error, but deferred into the call of { zmq_recv() | zmq_recv() } in their non-blocking form, where these may turn into reporting EAGAIN or might be EFSM for not having completed the end-to-end re-confirmed ZMTP-protocol handshaking ( no counterparty was and would never be met on the PC-localhost-port with remote RPi-server-side ). This requires also prior settings of zmq_setsockopt( responder, ZMQ_IMMEDIATE, 1 ) and other configuration details.
Next one, in ZeroMQ v4.+, there is a chance to inspect a subset of AccessPoint's internally reported events, using an "inspection-socket" via a rather complex strategy of instantiatingint zmq_socket_monitor (void *socket, char *endpoint, int events); attached to the AccessPoint's internals via inproc:// transport-class ~ here "inproc://myPCsocketAccessPOINT_monitor" like this:
rc = zmq_socket_monitor( responder, // AccessPoint to monitor
"inproc://myPCsocketAccessPOINT_monitor", // symbolinc name
ZMQ_ALL_EVENTS // scope of Events
);
Such created internal monitoring "inspection-socket" may next get zmq_connect()-ed to like:
void *my_end_of_monitor_socket = zmq_socket ( context, ZMQ_PAIR );
rc = zmq_connect( my_end_of_monitor_socket, // local-end PAIR-socket AccessPoint
"inproc://myPCsocketAccessPOINT_monitor" // symbolic name
);
and finally, we can use this to read a sequence of events (and act accordingly ):
int event = get_monitor_event( my_end_of_monitor_socket, NULL, NULL );
if (event == ZMQ_EVENT_CONNECT_DELAYED) { ...; }
if (event == ... ) { ...; }
using as a tool a trivialised get_monitor_event() like this, that handles some of the internal rules of reading and interpreting the multi-part messages that come as ordered from the instantiated "internal"-monitor attached to the AccessPoint:
// Read one event off the monitor socket; return value and address
// by reference, if not null, and event number by value. Returns -1
// in case of error.
static int
get_monitor_event ( void *monitor, int *value, char **address )
{
// First frame in message contains event number and value
zmq_msg_t msg;
zmq_msg_init (&msg);
if (zmq_msg_recv (&msg, monitor, 0) == -1) return -1; // Interrupted, presumably
assert (zmq_msg_more (&msg));
uint8_t *data = (uint8_t *) zmq_msg_data (&msg);
uint16_t event = *(uint16_t *) (data);
if (value) *value = *(uint32_t *) (data + 2);
// Second frame in message contains event address
zmq_msg_init (&msg);
if (zmq_msg_recv (&msg, monitor, 0) == -1) return -1; // Interrupted, presumably
assert (!zmq_msg_more (&msg));
if (address) {
uint8_t *data = (uint8_t *) zmq_msg_data (&msg);
size_t size = zmq_msg_size (&msg);
*address = (char *) malloc (size + 1);
memcpy (*address, data, size);
(*address)[size] = 0;
}
return event;
}
What internal-API-events can be monitored ?
As of the state of v4.2 API, there is this set of "internal"-monitor(able) internal-API-events:
ZMQ_EVENT_CONNECTED
The socket has successfully connected to a remote peer. The event value is the file descriptor (FD) of the underlying network socket. Warning: there is no guarantee that the FD is still valid by the time your code receives this event.
ZMQ_EVENT_CONNECT_DELAYED
A connect request on the socket is pending. The event value is unspecified.
ZMQ_EVENT_CONNECT_RETRIED
A connect request failed, and is now being retried. The event value is the reconnect interval in milliseconds. Note that the reconnect interval is recalculated at each retry.
ZMQ_EVENT_LISTENING
The socket was successfully bound to a network interface. The event value is the FD of the underlying network socket. Warning: there is no guarantee that the FD is still valid by the time your code receives this event.
ZMQ_EVENT_BIND_FAILED
The socket could not bind to a given interface. The event value is the errno generated by the system bind call.
ZMQ_EVENT_ACCEPTED
The socket has accepted a connection from a remote peer. The event value is the FD of the underlying network socket. Warning: there is no guarantee that the FD is still valid by the time your code receives this event.
ZMQ_EVENT_ACCEPT_FAILED
The socket has rejected a connection from a remote peer. The event value is the errno generated by the accept call.
ZMQ_EVENT_CLOSED
The socket was closed. The event value is the FD of the (now closed) network socket.
ZMQ_EVENT_CLOSE_FAILED
The socket close failed. The event value is the errno returned by the system call. Note that this event occurs only on IPC transports.
ZMQ_EVENT_DISCONNECTED
The socket was disconnected unexpectedly. The event value is the FD of the underlying network socket. Warning: this socket will be closed.
ZMQ_EVENT_MONITOR_STOPPED
Monitoring on this socket ended.
ZMQ_EVENT_HANDSHAKE_FAILED
The ZMTP security mechanism handshake failed. The event value is unspecified.
NOTE: in DRAFT state, not yet available in stable releases.
ZMQ_EVENT_HANDSHAKE_SUCCEED
NOTE: as new events are added, the catch-all value will start returning them. An application that relies on a strict and fixed sequence of events must not use ZMQ_EVENT_ALL in order to guarantee compatibility with future versions.
Each event is sent as two frames. The first frame contains an event number (16 bits), and an event value (32 bits) that provides additional data according to the event number. The second frame contains a string that specifies the affected TCP or IPC endpoint.
In zmq_connect, you must indicate the IP address of the raspberry (which have executed zmq_bind:
It should have been:
// on PC, remote ip is the raspberry one, the one you use for ssh for instance
rc = zmq_connect(requester, "tcp://<remote ip>:5555");
What I want to do
I'm writing a daemon which listen to the input devices for keys presses and send signals via D-Bus. The main goal is to manage audio volume and screen backlight level by requesting changes or informing about changes.
I use libevdev to handle the input device events.
I wrote a function for opening an input device located at a specified path:
Device device_open(const char *path);
That function works well, but while I'm writing unit tests for it, I wanted to create file fixtures with different properties (existence of the file, read access, etc.) to check the error handling of my function and memory management (as I store data in a structure).
What I have already done
But testing it with a real input device (located at /dev/input/event*) needs root access rights. Setting read access for everyone on /dev/input/event* files works but seems risky to me. Executing my tests as root is worse !
Creating a device using mknod works but needs to be done as root.
I also tried to use character special files (because input devices are one of those) allowing read for everyone (like /dev/random, /dev/zero, /dev/null and even the terminal device i'm currently using: /dev/tty2).
But those devices does not handles ioctl requests needed by libevdev: EVIOCGBIT is the first request returning an error "Inappropriate ioctl for device".
What I'm looking for
I want to be able to create device files as a regular user (the user executing the unit tests). Then, by setting access rights I should be able to test my function behavior for different kinds of file (read only, no read allowed, bad device type, etc.).
If it appears to be impossible, I will certainly refactor my function using private helpers. But how to do it. Any examples ?
Thanks.
Edit: I tried to express better my needs.
Create a group for users who are allowed to access the device, and an udev rule to set the ownership of that input event device to that group.
I use teensy (system) group:
sudo groupadd -r teensy
and add each user into it using e.g.
sudo usermod -a -g teensy my-user-name
or whatever graphical user interface I have available.
By managing which users and service daemons belong to the teensy group, you can easily manage the access to the devices.
For my Teensy microcontrollers (that have native USB, and I use for HID testing), I have the following /lib/udev/rules.d/49-teensy.rules:
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", ENV{ID_MM_DEVICE_IGNORE}="1"
ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789A]?", ENV{MTP_NO_PROBE}="1"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789ABCD]?", GROUP:="teensy", MODE:="0660"
KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", GROUP:="teensy", MODE:="0660"
You only need the third line (SUBSYSTEMS=="usb", one) for HID devices, though. Make sure the idVendor and idProduct match your USB HID device. You can use lsusb to list the currently connected USB devices vendor and product numbers. The matching uses glob patterns, just like file names.
After adding the above, don't forget running sudo udevadm control --reload-rules && sudo udevadm trigger to reload the rules. Next time you plug in your USB HID device, all members of your group (teensy in the above) can access it directly.
Note that by default in most distributions, udev also creates persistent symlinks in /dev/input/by-id/ using the USB device type and serial. In my case, one of my Teensy LC's (serial 4298820) with a combined keyboard-mouse-joystic device provides /dev/input/by-id/usb-Teensyduino_Keyboard_Mouse_Joystick_4298820-event-kbd for the keyboard event device, /dev/input/by-id/usb-Teensyduino_Keyboard_Mouse_Joystick_4298820-if01-event-mouse for the mouse event device, and /dev/input/by-id/usb-Teensyduino_Keyboard_Mouse_Joystick_4298820-if03-event-joystick and /dev/input/by-id/usb-Teensyduino_Keyboard_Mouse_Joystick_4298820-if04-event-joystick for the two joystick interfaces.
(By "persistent", I do not mean these symlinks always exist; I mean that whenever that particular device is plugged in, the symlink of exactly that name exists, and points to the actual Linux input event character device.)
The Linux uinput device can be used to implement a virtual input event device using a simple privileged daemon.
The process to create a new virtual USB input event device goes as follows.
Open /dev/uinput for writing (or reading and writing):
fd = open("/dev/uinput", O_RDWR);
if (fd == -1) {
fprintf(stderr, "Cannot open /dev/uinput: %s.\n", strerror(errno));
exit(EXIT_FAILURE);
}
The above requires superuser privileges. However, immediately after opening the device, you can drop all privileges, and have your daemon/service run as a dedicated user instead.
Use the UI_SET_EVBIT ioctl for each event type allowed.
You will want to allow at least EV_SYN; and EV_KEY for keyboards and mouse buttons, and EV_REL for mouse movement, and so on.
if (ioctl(fd, UI_SET_EVBIT, EV_SYN) == -1 ||
ioctl(fd, UI_SET_EVBIT, EV_KEY) == -1 ||
ioctl(fd, UI_SET_EVBIT, EV_REL) == -1) {
fprintf(stderr, "Uinput event types not allowed: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
I personally use a static constant array with the codes, for easier management.
Use the UI_SET_KEYBIT ioctl for each key code the device may emit, and UI_SET_RELBIT ioctl for each relative movement code (mouse code). For example, to allow space, left mouse button, horizontal and vertical mouse movement, and mouse wheel:
if (ioctl(fd, UI_SET_KEYBIT, KEY_SPACE) == -1 ||
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) == -1 ||
ioctl(fd, UI_SET_RELBIT, REL_X) == -1 ||
ioctl(fd, UI_SET_RELBIT, REL_Y) == -1 ||
ioctl(fd, UI_SET_RELBIT, REL_WHEEL) == -1) {
fprintf(stderr, "Uinput event types not allowed: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
Again, static const arrays (one for UI_SET_KEYBIT and one for UI_SET_RELBIT codes) is much easier to maintain.
Define a struct uinput_user_dev, and write it to the device.
If you have name containing the device name string, vendor and product with the USB vendor and product ID numbers, version with a version number (0 is fine), use
struct uinput_user_dev dev;
memset(&dev, 0, sizeof dev);
strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
dev.id.bustype = BUS_USB;
dev.id.vendor = vendor;
dev.id.product = product;
dev.id.version = version;
if (write(fd, &dev, sizeof dev) != sizeof dev) {
fprintf(stderr, "Cannot write an uinput device description: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
Later kernels have an ioctl to do the same thing (apparently being involved in systemd development causes this kind of drain bamage);
struct uinput_setup dev;
memset(&dev, 0, sizeof dev);
strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
dev.id.bustype = BUS_USB;
dev.id.vendor = vendor;
dev.id.product = product;
dev.id.version = version;
if (ioctl(fd, UI_DEV_SETUP, &dev) == -1) {
fprintf(stderr, "Cannot write an uinput device description: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
The idea seems to be that instead of using the former, you can try the latter first, and if it fails, do the former instead. You know, because a single interface might some day not be enough. (That's what the documentation and commit say, anyway.)
I might sound a bit cranky, here, but that's just because I do subscribe to both the Unix philosophy and the KISS principle (or minimalist approach), and see such warts completely unnecessary. And too often coming from the same loosely related group of developers. Ahem. No personal insult intended; I just think they are doing poor job.
Create the virtual device, by issuing an UI_DEV_CREATE ioctl:
if (ioctl(fd, UI_DEV_CREATE) == -1) {
fprintf(stderr, "Cannot create the virtual uinput device: %s.\n", strerror(errno));
close(fd);
exit(EXIT_FAILURE);
}
At this point, the kernel will construct the device, provide the corresponding event to the udev daemon, and the udev daemon will construct the device node and symlink(s) according to its configuration. All this will take a bit of time -- a fraction of a second in the real world, but enough that trying to emit events immediately might cause some of them to be lost.
Emit the input events (struct input_event) by writing to the uinput device.
You can write one or more struct input_events at a time, and should never see short writes (unless you try to write a partial event structure). Partial event structures are completely ignored. (See drivers/input/misc/uinput.c:uinput_write() uinput_inject_events() for how the kernel handles such writes.)
Many actions consists of more than one struct input_event. For example, you might move the mouse diagonally (emitting both { .type == EV_REL, .code == REL_X, .value = xdelta } and { .type == EV_REL, .code == REL_Y, .value = ydelta } for that single movement). The synchronization events ({ .type == EV_SYN, .code == 0, .value == 0 }) are used as a sentinel or separator, denoting the end of related events.
Because of this, you'll need to append an { .type == EV_SYN, .code == 0, .value == 0 } input event after each individual action (mouse movement, key press, key release, and so on). Think of it as the equivalent of a newline, for line-buffered input.
For example, the following code moves the mouse diagonally down right by a single pixel.
struct input_event event[3];
memset(event, 0, sizeof event);
event[0].type = EV_REL;
event[0].code = REL_X;
event[0].value = +1; /* Right */
event[1].type = EV_REL;
event[1].code = REL_Y;
event[1].value = +1; /* Down */
event[2].type = EV_SYN;
event[2].code = 0;
event[2].value = 0;
if (write(fd, event, sizeof event) != sizeof event)
fprintf(stderr, "Failed to inject mouse movement event.\n");
The failure case is not fatal; it only means the events were not injected (although I don't see how that could happen in current kernels; better be defensive, just in case). You can simply retry the same again, or ignore the failure (but letting the user know, so they can investigate, if it ever happens). So log it or output a warning, but no need for it to cause the daemon/service to exit.
Destroy the device:
ioctl(fd, UI_DEV_DESTROY);
close(fd);
The device does get automatically destroyed when the last duplicate of the original opened descriptor gets closed, but I recommend doing it explicitly as above.
Putting steps 1-5 in a function, you get something like
#define _POSIX_C_SOURCE 200809L
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/uinput.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
static const unsigned int allow_event_type[] = {
EV_KEY,
EV_SYN,
EV_REL,
};
#define ALLOWED_EVENT_TYPES (sizeof allow_event_type / sizeof allow_event_type[0])
static const unsigned int allow_key_code[] = {
KEY_SPACE,
BTN_LEFT,
BTN_MIDDLE,
BTN_RIGHT,
};
#define ALLOWED_KEY_CODES (sizeof allow_key_code / sizeof allow_key_code[0])
static const unsigned int allow_rel_code[] = {
REL_X,
REL_Y,
REL_WHEEL,
};
#define ALLOWED_REL_CODES (sizeof allow_rel_code / sizeof allow_rel_code[0])
static int uinput_open(const char *name, const unsigned int vendor, const unsigned int product, const unsigned int version)
{
struct uinput_user_dev dev;
int fd;
size_t i;
if (!name || strlen(name) < 1 || strlen(name) >= UINPUT_MAX_NAME_SIZE) {
errno = EINVAL;
return -1;
}
fd = open("/dev/uinput", O_RDWR);
if (fd == -1)
return -1;
memset(&dev, 0, sizeof dev);
strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE);
dev.id.bustype = BUS_USB;
dev.id.vendor = vendor;
dev.id.product = product;
dev.id.version = version;
do {
for (i = 0; i < ALLOWED_EVENT_TYPES; i++)
if (ioctl(fd, UI_SET_EVBIT, allow_event_type[i]) == -1)
break;
if (i < ALLOWED_EVENT_TYPES)
break;
for (i = 0; i < ALLOWED_KEY_CODES; i++)
if (ioctl(fd, UI_SET_KEYBIT, allow_key_code[i]) == -1)
break;
if (i < ALLOWED_KEY_CODES)
break;
for (i = 0; i < ALLOWED_REL_CODES; i++)
if (ioctl(fd, UI_SET_RELBIT, allow_rel_code[i]) == -1)
break;
if (i < ALLOWED_REL_CODES)
break;
if (write(fd, &dev, sizeof dev) != sizeof dev)
break;
if (ioctl(fd, UI_DEV_CREATE) == -1)
break;
/* Success. */
return fd;
} while (0);
/* FAILED: */
{
const int saved_errno = errno;
close(fd);
errno = saved_errno;
return -1;
}
}
static void uinput_close(const int fd)
{
ioctl(fd, UI_DEV_DESTROY);
close(fd);
}
which seem to work fine, and requires no libraries (other than the standard C library).
It is important to realize that the Linux input subsystem, including uinput and struct input_event, are binary interfaces to the Linux kernel, and therefore will be kept backwards compatible (except for pressing technical reasons, like security issues or serious conflicts with other parts of the kernel). (The desire to wrap everything under the freedesktop.org or systemd umbrella is not one.)
So how do you do this properly?
I know how to do it by creating socket, then setting IFF_PROMISC flag using ioctl (as explained in "howto check a network devices status in C?" and elsewhere), but this looks flawed at least in theory.
you read flags via ioctl
you update flags
someone else modified flags
you set updated flags via ioctl
Is there a better way or do I simply worry too much?
Later I found that one should add interface to PACKET_MR_PROMISC via setsockopt (which also does not have a race) like this:
void set_promisc(const char *ifname, bool enable)
{
struct packet_mreq mreq = {0};
int sfd;
int action;
if ((sfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
perror("unable to open socket");
return;
}
mreq.mr_ifindex = if_nametoindex(ifname);
mreq.mr_type = PACKET_MR_PROMISC;
if (mreq.mr_ifindex == 0) {
perror("unable to get interface index");
return;
}
if (enable)
action = PACKET_ADD_MEMBERSHIP;
else
action = PACKET_DROP_MEMBERSHIP;
if (setsockopt(sfd, SOL_PACKET, action, &mreq, sizeof(mreq)) != 0) {
perror("unable to enter promiscouous mode");
return;
}
close(sfd);
}
Unfortunately this has no effect whatsoever on interface, although it should, if I unserstand the doc correctly. Possibly broken since 2001 (tm)?
Comments in pcap source also complain about this.
PACKET_MR_PROMISC turns on promiscuous mode for the device. That will not be reflected in the status shown by ifconfig as it does not modify the state of the global IFF_PROMISC flag on the device. That does not mean it hasn't been done though. This is how the pcap library works now and the fact that wireshark (and a dozen other utilities) can open a device and see packets not addressed to the local system shows that it works.
There is an internal counter on each device that is incremented each time a process uses PACKET_MR_PROMISC, and decremented when that process goes away. That solves the race you originally described.
From the last link you provided:
> IFF_PROMISC is not set,
It's not supposed to be set.
The correct way to put into promiscuous mode the device to which a
PF_PACKET socket is to do a SOL_PACKET/PACKET_ADD_MEMBERSHIP
"setsockopt()" call with PACKET_MR_PROMISC as the argument (see the
"packet(7)" man page), and that's what libpcap is doing.
The old way of directly setting IFF_PROMISC had problems - to quote the
comment at the front of "pcap-linux.c":
[snipped]
i'm trying to make an app for the remote control of mouse on linux server by android application. As a beginner, i've got lot of probs..before writing the linux Server with C, I tried to check if i can control and move the mouse on Linux according to the code :
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <linux/input.h>
int main(){
struct input_event event, event_end;
int i=0;
int fd = -1;
fd = open("/dev/input/event4", O_RDWR | O_NONBLOCK);
if(fd<0){
perror("error");
}
memset(&event, 0, sizeof(event));
memset(&event, 0, sizeof(event_end));
gettimeofday(&event.time, NULL);
event.type = EV_REL;
event.code = REL_X;
event.value = 100;
gettimeofday(&event_end.time, NULL);
event_end.type = EV_SYN;
event_end.code = SYN_REPORT;
event_end.value = 0;
for( i=0; i<5; i++){
write(fd, &event, sizeof(event));// Move the mouse
write(fd, &event_end, sizeof(event_end));// Show move
sleep(1);
}
close(fd);
return 0;
}
after build compile execute.. nothing happens
cursor never moves..will it be somekind of VirtualBox setting issue?
sudo cat /dev/input/event4 shows weird string of symbols when i physically move the mouse.
That means to be able to get contol of mouse cursor movement by event4 isn't it?
i wonder why the cursor won't move... anyone can help?
And further, I would be glad if anyone suggests Library and Functions to control mouse
thx a lot
You can't just write to the device file and expect the drivers to behave as if actual hardware was sending these events. Things are way more complicated than that.
If you are only concerned with X Windows environment you are in luck. You can use this function to send events to the window:
http://tronche.com/gui/x/xlib/event-handling/XSendEvent.html
If you don't know which window should be receiving your events just send them to the root window, they will be routed appropriately.
Also there is a library for that.
http://www.x.org/releases/X11R7.6/doc/libXtst/recordlib.html
Just keep in mind that in X windows events have a flag that indicates whether the event came from the actual hardware or was synthesized by one of the above methods. In most cases programs just ignore this flag and behave the same regardless. But sometimes you can have weird surprises.
I'm working on a new project where I want to make a connection with an FTDI which is connected to my debian machine. I am intending to write the code with C, not C++. Here lies my problem. All the examples I find are incomplete or are made for a c++ compiler in stead of the GCC compiler.
The goal is to talk to my microcontroller which is connected to the FTDI. For debugging i want to start building a linux application which is able to:
initialize a serial connection on startup with ttyUSB1
send a character string
display character strings when they are received by the pc
save the communication to a .txt file
Is there any example code or tutorial to make this?
If I succeed I will defenetly place the code here so that new viewers can use it to!
Edit:
Like I said I would post the code if I had it, and this is what worked for me:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#define MODEM "/dev/ttyUSB0"
#define BAUDRATE B115200
int main(int argc,char** argv)
{
struct termios tio;
struct termios stdio;
struct termios old_stdio;
int tty_fd, flags;
unsigned char c='D';
tcgetattr(STDOUT_FILENO,&old_stdio);
printf("Please start with %s /dev/ttyS1 (for example)\n",argv[0]);
memset(&stdio,0,sizeof(stdio));
stdio.c_iflag=0;
stdio.c_oflag=0;
stdio.c_cflag=0;
stdio.c_lflag=0;
stdio.c_cc[VMIN]=1;
stdio.c_cc[VTIME]=0;
tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); // make the reads non-blocking
memset(&tio,0,sizeof(tio));
tio.c_iflag=0;
tio.c_oflag=0;
tio.c_cflag=CS8|CREAD|CLOCAL; // 8n1, see termios.h for more information
tio.c_lflag=0;
tio.c_cc[VMIN]=1;
tio.c_cc[VTIME]=5;
if((tty_fd = open(MODEM , O_RDWR | O_NONBLOCK)) == -1){
printf("Error while opening\n"); // Just if you want user interface error control
return -1;
}
cfsetospeed(&tio,BAUDRATE);
cfsetispeed(&tio,BAUDRATE); // baudrate is declarated above
tcsetattr(tty_fd,TCSANOW,&tio);
while (c!='q'){
if (read(tty_fd,&c,1)>0){
write(STDOUT_FILENO,&c,1); // if new data is available on the serial port, print it out
printf("\n");
}
if (read(STDIN_FILENO,&c,1)>0){
write(tty_fd,&c,1);//if new data is available on the console, send it to serial port
printf("\n");
}
}
close(tty_fd);
tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio);
return EXIT_SUCCESS;
}
Most of the code came from http://en.wikibooks.org/wiki/Serial_Programming/Serial_Linux but i also used a bit from the code posted below.
Handling with serial ports ( for linux OS ) :
- To open communication, you will need a descriptor which will be the handle for your serial port.
- Set the flags to control how the comunication will be.
- Write the command to this Handle ( make sure you're formatting the input correctly ).
- Get the answer. (make sure you're to read the amount of information you want )
- Close the handle.
It will seem like this:
int fd; // file descriptor
int flags; // communication flags
int rsl_len; // result size
char message[128]; // message to send, you can even dinamically alocate.
char result[128]; // result to read, same from above, thanks to #Lu
flags = O_RDWR | O_NOCTTY; // Read and write, and make the job control for portability
if ((fd = open("/dev/ttyUSB1", flags)) == -1 ) {
printf("Error while opening\n"); // Just if you want user interface error control
return -1;
}
// In this point your communication is already estabilished, lets send out something
strcpy(message, "Hello");
if (rsl_len = write(fd, message, strlen(message)) < 0 ) {
printf("Error while sending message\n"); // Again just in case
return -2;
}
if (rsl_len = read(fd, &result, sizeof(result)) < 0 ) {
printf("Error while reading return\n");
return -3;
}
close(fd);
Note that you have to care about what to write and what to read.
Some more flags can be used in case of parity control, stop bits, baud rate and more.
Since gcc is a C/C++ compiler, you don't need to limit yourself to pure C.
Sticking to pure C is OK if you enjoy writing lots of boilerplate code, and if you really know what you're doing. Many people use Unix APIs incorrectly, and a lot of example code out there is much too simplistic. Writing correct Unix C code is somewhat annoying, to say the least.
Personally, I'd suggest using not only C++, but also a higher-level application development framework like Qt. Qt 5 comes bundled with a QtSerialPort module that makes it easy to enumerate the serial ports, configure them, and get data into and out of them. Qt does not force you to use the gui modules, it can be a command line application, or a non-interactive server/daemon.
QtSerialPort is also usable from Qt 4, but it doesn't come bundled with Qt 4, you have to add it to your project. I suggest starting out with Qt 5, it's nicer to use with its C++11 support.
The code using Qt can be pretty simple, not much longer than your plain-English description. The below is a Qt console application using Qt 5 and C++11. It uses the core and serialport modules. It also handles the SIGINT signal so that the output file gets flushed before the process would terminate due to a ^C. I'm using QLocalSocket in place of raw Unix API to communicate from the Unix signal handler, the functionality is the same.
Only the code within main is strictly required, the rest is just to make it properly wrap things up when you hit ^C.
#include <QCoreApplication>
#include <QSerialPort>
#include <QFile>
#include <QTextStream>
#include <QLocalServer>
#include <QLocalSocket>
#include <cstdio>
#include <csignal>
QLocalSocket * xmit;
static void signalHandler(int)
{
xmit->write(" ");
xmit->flush();
}
static bool setupSignalHandler()
{
QLocalServer srv;
srv.listen("foobarbaz");
xmit = new QLocalSocket(qApp);
xmit->connectToServer(srv.serverName(), QIODevice::WriteOnly);
srv.waitForNewConnection();
QLocalSocket * receive = srv.nextPendingConnection();
receive->setParent(qApp);
qApp->connect(receive, &QLocalSocket::readyRead, &QCoreApplication::quit);
struct sigaction sig;
sig.sa_handler = signalHandler;
sigemptyset(&sig.sa_mask);
sig.sa_flags = SA_RESTART;
return ! sigaction(SIGINT, &sig, NULL);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
setupSignalHandler();
QSerialPort port("ttyUSB1");
QFile file("file.txt");
QTextStream err(stderr, QIODevice::WriteOnly);
QTextStream out(stdout, QIODevice::WriteOnly);
if (!file.open(QIODevice::WriteOnly)) {
err << "Couldn't open the output file" << endl;
return 1;
}
if (!port.open(QIODevice::ReadWrite)) {
err << "Couldn't open the port" << endl;
return 2;
}
port.setBaudRate(9600);
QObject::connect(&port, &QSerialPort::readyRead, [&](){
QByteArray data = port.readAll();
out << data;
file.write(data);
});
out << "Use ^C to quit" << endl;
return a.exec();
}