Я потом нашёл два варианта, один через Xlib, другой через ядро с помощью ioctl.
Сейчас посмотрел, в обоих случаях "/" есть, с Xlib это XK_slash,
через ioctl это KEY_SLASH.
Вот вариант с Xlib, он периодически посылает Enter и сделан демоном.
В Ubuntu <sys/param.h> подключает <signal.h> и его можно закомментировать.
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/extensions/XTest.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
//#include <sys/types.h>
#include <signal.h>
int main(int argc,char **argv){
int fd,n=256;
pid_t id;
struct rlimit flim;
if(argc>1)n=atoi(argv[1]);
if (getppid() != 1){ signal(SIGTTOU,SIG_IGN);signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN); id=fork(); if(id != 0){ fprintf(stdout,
"daemon is running, %d %d\n",(int)id,n);fflush(stdout);exit(0);} setsid();}
getrlimit(RLIMIT_NOFILE,&flim); for(fd=0;fd<flim.rlim_max;fd++)close(fd);
fd=chdir("/");
if(fd != 0){ fprintf(stdout,"We a not in \"/\"!,%d\n",fd);fflush(stdout);}
Display *display;
unsigned int keycode;
display = XOpenDisplay(NULL);
keycode = XKeysymToKeycode(display, XK_Return);
while(1){
XTestFakeKeyEvent(display, keycode, True, 0);
XTestFakeKeyEvent(display, keycode, False, 0);
sleep(n);
XFlush(display);
}
XCloseDisplay(display);
return 0;
}
Вот вариант с ioctl, он делает то же самое.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <pos_gnu.h>
#include <signal.h>
void print_errno(int,FILE *);
//KEY_SPACE instead of KEY_ENTER !!!
int main(int argc,char **argv){
int n=256,nr,fd;
pid_t id;
struct uinput_user_dev uidev;
struct input_event ev;
struct rlimit flim;
FILE *fout;
if(argc>1)n=atoi(argv[1]);
if (getppid() != 1){ signal(SIGTTOU,SIG_IGN);signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN); id=fork(); if(id != 0){ fprintf(stdout,
"daemon is running, %d %d\n",(int)id,n);fflush(stdout);exit(0);} setsid();}
getrlimit(RLIMIT_NOFILE,&flim); for(fd=0;fd<flim.rlim_max;fd++)close(fd);
nr=chdir("/"); fout=fopen("/home/operator0/uinput_daemon_cr_out","w");
if(nr != 0){ fprintf(fout,"We a not in \"/\"!,%d\n",nr);fflush(fout);}
fd=open("/dev/uinput", O_WRONLY | O_NONBLOCK);if(fd<0)print_errno(errno,fout);
fprintf(fout,"period=%d fd=%d\n",n,fd);fflush(fout);
nr=ioctl(fd, UI_SET_EVBIT, EV_KEY);if(nr<0)print_errno(errno,fout);
nr=ioctl(fd, UI_SET_EVBIT, EV_SYN);if(nr<0)print_errno(errno,fout);
// nr=ioctl(fd, UI_SET_KEYBIT, KEY_D);if(nr<0)print_errno(errno,fout);
nr=ioctl(fd, UI_SET_KEYBIT, KEY_ENTER);if(nr<0)print_errno(errno,fout);
memset(&uidev, 0, sizeof(uidev));
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput_cr");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1; uidev.id.product = 0x1; uidev.id.version = 1;
nr=write(fd, &uidev, sizeof(uidev));if(nr<0)print_errno(errno,fout);
nr=ioctl(fd, UI_DEV_CREATE);if(nr<0)print_errno(errno,fout);
while(1) {
/*
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_KEY; ev.code = KEY_D; ev.value = 1;
nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_KEY; ev.code = KEY_D; ev.value = 0;
nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);
*/
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_KEY; ev.code = KEY_ENTER; ev.value = 1;
nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_KEY; ev.code = KEY_ENTER; ev.value = 0;
nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_SYN; ev.code = 0; ev.value = 0;
nr=write(fd, &ev, sizeof(struct input_event));if(nr<0)print_errno(errno,fout);
sleep(n);
}
sleep(2);
nr=ioctl(fd, UI_DEV_DESTROY);if(nr<0)print_errno(errno,fout);
close(fd);fclose(fout);
return 0;
}
void print_errno(int ne,FILE *f){
int n;
char buf[160];
#if ispos
n=strerror_r(ne,buf+80,80);strcpy(buf,buf+80);
#else
strcpy(buf,strerror_r(ne,buf+80,80));
#endif
fprintf(f,"%d %s\n",ne,buf);fflush(f);
}
pos_gnu.h - это мой файл, он у меня в /usr/local/include:
#ifndef POS_GNU_H
#define POS_GNU_H 1
#ifndef _POSIX_C_SOURCE
#define isnp 0
#else
# if ( _POSIX_C_SOURCE >= 200112L )
#define isnp 1
#endif
#endif
#ifndef _XOPEN_SOURCE
#define isnx 0
#else
# if ( _XOPEN_SOURCE >= 600 )
#define isnx 1
#endif
#endif
#ifdef _GNU_SOURCE
#define isng 1
#else
#define isng 0
#endif
#if ( ( isnp || isnx ) && ! isng )
#define ispos 1
#else
#define ispos 0
#endif
#endif
Пример с ioctl взят отсюда:
http://thiemonge.org/getting-started-with-uinput
мне эту ссылку приводили здесь выше.