I'm trying to do a virtual keyboard with uinput on Debian Stretch, that i could feed with strings, like "Toto !", and the keyboard would write this string. However, I'm stuck with the conversion from C char to keycodes handled by the keyboard. I'm not using the Macros defined in event-codes.h because I want my solution to work on the locale of the computer, and the macros are defined around an US Keyboard.
Here's the device created using uinput :
int setup_uinput_device(){
/* Temporary variable */
int i=0;
/* Open the input device */
uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY);
if (fcntl(uinp_fd, F_GETFD) == -1)
{
printf("Unable to open /dev/uinput\n");
return -1;
}
memset(&uinp,0,sizeof(uinp)); /* Intialize the uInput device to NULL */
strncpy(uinp.name, "Custom Keyboard", UINPUT_MAX_NAME_SIZE);
uinp.id.bustype = BUS_USB;
// Setup the uinput device
ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY);
ioctl(uinp_fd, UI_SET_EVBIT, EV_REL);
ioctl(uinp_fd, UI_SET_EVBIT, EV_REP);
for (i=0; i < 256; i++) {
ioctl(uinp_fd, UI_SET_KEYBIT, i);
}
/* Create input device into input sub-system */
write(uinp_fd, &uinp, sizeof(uinp));
if (ioctl(uinp_fd, UI_DEV_CREATE))
{
printf("Unable to create UINPUT device.\n");
return -1;
}
return 0;
}
I've already tried solutions using the X11 library, as depicted in this link : Convert ASCII character to x11 keycode Unfortunately, the keyboard i've managed to create using uinput takes differents keycodes than the ones X11 uses. (I think my keyboard takes the same keycodes that I can get with using the dumpkeys command). It's surely possible to convert X11 keycodes into (kernel ?) keycodes that my keyboard correctly inteprets, but I'd like to keep the numbers of dependencies low.
I'm now trying to use EVIOCGKEYCODE as depicted in linux.h, but I have difficulties to understand how it works, and I think it does the inverse of what I really want.
Here's an example :
int main(int argc, char *argv[]) {
setup_uinput_device();
struct input_keymap_entry mapping;
int i =0;
/* Set the max value at 130 just for the purpose of testing */
for (i=0; i<130; i++) {
mapping.scancode[0] = i;
if(ioctl(fd, EVIOCGKEYCODE_V2, mapping)) {
perror("evdev ioctl");
}
printf("Scancode= %d, Keycode = %d\n",
mapping.scancode[0], mapping.keycode);
}
/* Simple function to destroy the device */
destroy_uinput_device();
return 0;
}
I get the following error : "evdev ioctl: Invalid argument". I've read somewhere that it's an old method used with PS2 keyboard, so it's probably one of the many reasons it's not working.
The last solution I consider is to parse the result of dumpkeys in a table or a map that I could use later, but I think I will get performance issues, and I don't want to recreate something that perhaps already exists.
Any Idea ?
So after a lot of tryout, I finally managed to understand that the Keycode used by the kernel are the same that the one used by X11 minus 8.
I'd first had to manage encoding. I've used the following code to manage multi bytes encoded characters (like €) :
char *str = "Test €";
size_t mbslen; /* Number of multibyte characters in source */
wchar_t *wcs; /* Pointer to converted wide character string */
wchar_t *wp;
setlocale(LC_ALL, "");
mbslen = mbstowcs(NULL, str, 0);
if (mbslen == (size_t) -1) {
perror("mbstowcs");
exit(ERROR_FAILURE);
}
wcs = calloc(mbslen + 1, sizeof(wchar_t));
if (wcs == NULL) {
perror("calloc");
exit(ERROR_FAILURE);
}
/* Convert the multibyte character string in str to a wide character string */
if (mbstowcs(wcs, str, mbslen + 1) == (size_t) -1) {
perror("mbstowcs");
exit(ERROR_FAILURE);
}
Then using this conversion table from ucs to keysym, I managed to translate a widechar array to its corresponding sequences of Keycode, based on the example i've provided in my original question.
The last step was to feed my uinput keyboard with the X11 Keycode minus 8.