http://qs1969.pair.com?node_id=271673
Category: Miscellaneous
Author/Contact Info Curtis "Mr_Person" Hawthorne
Description:

While working on a project, I was trying to find a way to get the status of numlock and preferably be able to tell when it was pressed. belg4mit pointed out that it was possible to get the scan code for Numlock using the showkey program. I took a look at the showkey source and found out that it does several things to the keyboard mode that allows it to capture raw scan codes. The first part is pretty much the same as saying ReadMode 4; with Term::ReadKey, but the last part I hadn't seen before and it set the keyboard to "MEDIUMRAW" mode. On closer inspection, it used an ioctl call to the current filehandle with some constants from the kd.h header file in the Linux kernel sources. It then does a bitwise AND with each character and 0x7f to get the scancode and also tests if a bitwise AND with 0x80 is true in which case the key was released, false it was pressed.

This program just uses the hard coded values taken from the kd.h file instead of including it like showkey does. There's probably a better way to do this, but I didn't know of one that would work easily. It also doesn't include as much error checking as showkey to make sure your keyboard gets back to how it should be or as many options for output.

#!/usr/bin/perl

use Term::ReadKey;

use strict;
use warnings;

use constant KDSKBMODE          => 0x4B45;
use constant K_XLATE            => 0x01;
use constant K_MEDIUMRAW        => 0x02;

$SIG{ALRM} = sub {
        ioctl(STDIN, KDSKBMODE, K_XLATE); # Return to XLATE
        ReadMode 0;
        exit;
};

ReadMode 4;

ioctl(STDIN, KDSKBMODE, K_MEDIUMRAW); # Set keyboard to MEDIUMRAW

while(1) {
        my $char = getc(STDIN);
        print "keycode ", (ord($char) & 0x7f), (ord($char) & 0x80) ? "
+ release" : " press", "\n";
        alarm(10);
}