2

Been away from Perl awhile and would like to modify a script I wrote as an art project long ago. The original script uses Term::ReadKey to allow the user to type arbitrary text into a Mac/Linux terminal. As they type, the text creates various floaty patterns in the terminal. I want to adapt the script so, instead of reading keys as they're input, it can read from text files written periodically by another process. But it would need to read in characters in some controllable way (not all at once) so as to (roughly) emulate human typing.

What I've tried: Term::ReadKey's man page says it can read from a filehandle instead of STDIN - but for some reason, I could not get this to work, with either a standard file or a FIFO. I also tried reading in text from a file using "open" and putting the characters into an array. But iterating through the array got complicated because of the need to add delays between characters without pausing the rest of the script. ( I can envision this as a potential solution, but I'm not sure how best to design it to allow time delays to be controllable without the script becoming unwieldy.)

Wondering if there's a relatively simple way to approach this - assuming it's feasible at all?

Here's the "meat" of the existing script (have removed various subroutines that add additional effects based on various keypresses.)

#!/usr/bin/perl

use Time::HiRes(usleep);
use Term::ReadKey;


$|=1;

$starttime = time;
$startphrase = '                    ';

$startsleepval = 3000;

$phrase = $startphrase;
$sleepval = $startsleepval;
$dosleep = 1;


$SIG{'INT'}=\&quitsub;
$SIG{'QUIT'}=\&quitsub;

# One Ctrl-C clears text and resets program.  # Three Ctrl-C's to quit.

sub quitsub {print color 'reset' if ($dosleep); $phrase = $startphrase; $sleepval=$startsleepval; $SIG{'INT'}=\&secondhit;}
sub secondhit { $SIG{'INT'}=\&outtahere; }
sub outtahere {print color 'reset'; sleep 1; print "\n\n\t\t\t\n\n"; exit(0);}


while (1) {
    print "$phrase  ";
    if ($dosleep) {
        usleep ($sleepval);
    }
    ReadMode 3;

    ##### Here is where it reads from the terminal.  Can characters be read from a file in a similar sequential fashion? #####
    $key = ReadKey(-1);
    $now = time;
    if ((defined($key)) and ($now > $starttime + 5)) {
        $phrase = $phrase.$key;
        $SIG{'INT'}=\&quitsub;
    }
    # user can also create interesting effects with spacebar, tab and arrow keys.

    ReadMode 0; # this may appear redundant, but has a subtle visual effect. At least that's what I commented in the original 2003 script.

}

# end main loop

1 Answers1

1

The problem here is that your script can try to read from the file all you want, but if the process that actually writes to the file flushes all at once, you're going to get everything together.

Also, a few things:

  • if you really want to use ReadKey, you should probably use ReadMode 5 if you don't know the CR or CR/LF use of your file.

  • also check Term::ReadKey and you'll see that you probably want something like ReadKey 0, $file

  • it's probably best if you drop Term::ReadKey completely and use File::Tail instead, looping over the added characters one at a time

  • Your final code is most likely going to be something that goes through an array of characters, just as you've already tried to do.

ChatterOne
  • 3,381
  • 1
  • 18
  • 24
  • Interesting ideas, but I've not gotten any of them to work. File::Tail didn't seem to help with the timing problems. Tried all your Term::ReadKey suggestions, but the problem isn't that the characters spit out all at once; when I read from a filehandle the characters don't spit out at all. Tried normal file as well as fifo. – artistwhocodes Jan 07 '16 at 08:25