Here is another implementation of the same interface. Its init
function performs the same kind of initialization as the other version, but using the operating system's keyboard files /dev/cons
and /dev/consctl
. In the Inferno environment, operations corresponding to the Unix stty
primitive are accomplished by writing messages to a control file associated with the file that handles the data.
implement Ir; include "ir.m"; include "sys.m"; FD : import Sys; sys : Sys; cctlfd : ref FD; init (keys : chan of int): int { dfd : ref FD; sys = load Sys Sys->PATH; cctlfd = sys->open("/dev/consctl", sys->OWRITE); if (cctlfd == nil) return -1; sys->write(cctlfd, array of byte "rawon", 5); dfd = sys->open("/dev/cons", sys->OREAD); if(dfd == nil) return -1; spawn reader(keys, dfd); return 0; }A fine point: the variable
cctlfd
that contains the FD
for the control device is declared external to the init
function, even though it appears to be used only inside it. Programming cleanliness suggests that its declaration be moved inside, but here that will not work. Device control files in the Inferno system retain settings like raw mode only while they remain open. If cctlfd
were declared inside init
, then returning from init
would destroy the last reference to the FD
for the control file, and the device would be closed automatically.
The reader function for this module has the same structure as the first example, but doesn't have to worry about a noisy infrared detector:
reader(keys : chan of int, dfd : ref FD) { n : int; b := array[1] of byte; for(;;) { n = sys->read(dfd, b, 1); if (n != 1) break; case int b[0] { '0' => n = Ir->Zero; '1' => n = Ir->One; .... 16r7f => n = Ir->Mute; * => n = Ir->Error; } keys <-= n; } keys <-= Ir->Error; }