linux – Catch USB keyboard connection

Question:

Linux. There is a program (script) that constantly hangs and pokes at the keyboard from time to time using xinput . Initially, the program received the keyboard ID manually, then it began to automatically search for the required one in the xinput output xinput to the specified line (for example, "SIGMACHIP USB Keyboard" ). Everything worked fine until it was necessary to connect a keyboard via KVM. As a result, when switching the keyboard, it turns off, then connects again, as a result, the ID is lost.

Seemingly not a question, I made a rule for udev , according to which, when the keyboard is connected, the program kicks and looks for it again. But here the first problem arose: for some reason the rule for ACTION=="add" (and "remove" too) works many times in a row, here is an example of a log from one switch, with nanoseconds:

[2017-03-28 00:55:02.706646142] add
[2017-03-28 00:55:02.741458338] add
[2017-03-28 00:55:02.743809711] add
[2017-03-28 00:55:02.746796922] add
[2017-03-28 00:55:02.755381196] add
[2017-03-28 00:55:02.755918337] add
[2017-03-28 00:55:02.756454043] add
[2017-03-28 00:55:02.763367644] add
[2017-03-28 00:55:02.765260538] add
[2017-03-28 00:55:02.766500092] add
[2017-03-28 00:55:02.769976530] add
[2017-03-28 00:55:02.770717800] add
[2017-03-28 00:55:02.777717611] add
[2017-03-28 00:55:02.788441617] add

And what to do about it is not entirely clear.

But the real problem is still number two: can you do without rules at all? Ideally, the script should be self-contained and do not require any additional actions, catch the keyboard connection on its own. This is real? If, after all, not, then how to overcome multiple triggering of the rule?


$ cat /etc/udev/rules.d/10-local.rules
ACTION=="add", SUBSYSTEMS=="usb", \
    ATTRS{idVendor}=="1c4f", ATTRS{idProduct}=="0002", \
    RUN+="/opt/bin/kvm-kb add k:%k n:%n p:%p"

Answer:

It seems to me that one could try using inotify instead of udev. I took a ready-made example and corrected only the path to the folder in which the USB devices are created:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/inotify.h>

#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

int main( int argc, char **argv ) 
{
  int length, i = 0;
  int fd;
  int wd;
  char buffer[BUF_LEN];

  fd = inotify_init();

  if ( fd < 0 ) {
    perror( "inotify_init" );
  }

  wd = inotify_add_watch( fd, "/dev/bus/usb/002", 
                         IN_MODIFY | IN_CREATE | IN_DELETE );
  length = read( fd, buffer, BUF_LEN );  

  if ( length < 0 ) {
    perror( "read" );
  }  

  while ( i < length ) {
    struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
    if ( event->len ) {
      if ( event->mask & IN_CREATE ) {
        if ( event->mask & IN_ISDIR ) {
          printf( "The directory %s was created.\n", event->name );       
        }
        else {
          printf( "The file %s was created.\n", event->name );
        }
      }
      else if ( event->mask & IN_DELETE ) {
        if ( event->mask & IN_ISDIR ) {
          printf( "The directory %s was deleted.\n", event->name );       
        }
        else {
          printf( "The file %s was deleted.\n", event->name );
        }
      }
      else if ( event->mask & IN_MODIFY ) {
        if ( event->mask & IN_ISDIR ) {
          printf( "The directory %s was modified.\n", event->name );
        }
        else {
          printf( "The file %s was modified.\n", event->name );
        }
      }
    }
    i += EVENT_SIZE + event->len;
  }

  ( void ) inotify_rm_watch( fd, wd );
  ( void ) close( fd );

  exit( 0 );
}

Connecting a flash drive catches 100%, but with a disconnection – some misunderstandings …

Scroll to Top