Article 5020 of comp.lang.perl: Xref: feenix.metronet.com alt.sources:1708 comp.lang.perl:5020 Path: feenix.metronet.com!spssig.spss.com!kuhub.cc.ukans.edu!wupost!howland.reston.ans.net!europa.eng.gtefsd.com!uunet!bloom-beacon.mit.edu!senator-bedfellow.mit.edu!news!jsc Newsgroups: alt.sources,comp.lang.perl Subject: Morse Code practice program Message-ID: From: jsc@monolith.mit.edu (Jin S Choi) Date: 15 Aug 1993 19:14:24 GMT Distribution: world Organization: Massachvsetts Institvte of Technology NNTP-Posting-Host: monolith.mit.edu Comments: Hyperbole mail buttons accepted, v3.07. Lines: 330 I wrote this a while ago to practice for a ham license (which I haven't gotten yet), and thought it might be of interest to someone out there. Basically, it lets you enter morse at the keyboard and writes out the letters. It's written in perl with a short X11 program used for I/O. It needs to be able to detect how long a key is held down, and this was the easiest way I could think of to do it. The X program just throws up a window and outputs a 'd' on a keypress event, and a 'u' on a keyrelease. It can be replaced by any program which does the same thing. If you find this interesting, let me know. ---------------------------------------------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # morse.pl # keypress.c # This archive created: Sun Aug 15 15:05:18 1993 export PATH; PATH=/bin:$PATH if test -f 'morse.pl' then echo shar: will not over-write existing file "'morse.pl'" else cat << \SHAR_EOF > 'morse.pl' #!/usr/local/bin/perl # morse code practice program # Written by Jin S. Choi . require 'sys/syscall.ph'; require 'sys/time.ph'; $timeval = 'll'; # struct timeval $tp = pack($timeval, 0, 0); # pre-extend $tp to size of two longs $SIG{'INT'} = cleanup; if ($ENV{'DISPLAY'}) { system("xset -r"); # turn off autorepeat } close STDIN; open(STDIN, "keypressX11 |") || die $!; select(STDIN); $|++; select(STDOUT); $|++; %morse = ( ".-", "a", "-...", "b", "-.-.", "c", "-..", "d", ".", "e", "..-.", "f", "--.", "g", "....", "h", "..", "i", ".---", "j", "-.-", "k", ".-..", "l", "--", "m", "-.", "n", "---", "o", ".--.", "p", "--.-", "q", ".-.", "r", "...", "s", "-", "t", "..-", "u", "...-", "v", ".--", "w", "-..-", "x", "-.--", "y", "--..", "z", ".-.-.-", ".", "--..--", ",", "..--..", "?", "-..-.", "/", ".-.-.", "+", "-----", "0", ".----", "1", "..---", "2", "...--", "3", "....-", "4", ".....", "5", "-....", "6", "--...", "7", "---..", "8", "----.", "9", "-...-", "BT", ".-.-.", "AR", "...-.-", "SK", ); &calibrate_lengths; while (1) { if (&get_down > $c) { $letter .= '-'; } else { $letter .= '.'; } if (!&get_up($sc)) { # at least interletter space print $morse{$letter}; $letter = ''; if (!&get_up(2*$sc)) { # interword space print " "; &get_up; } } } sub key_ready { local($timeout) = @_; local($rin, $nfd); vec($rin, fileno(STDIN), 1) = 1; return $nfd = select($rin,undef,undef,$timeout); } sub gettimeofday { ## returns time in seconds local($sec, $usec); syscall(&SYS_gettimeofday, $tp, 0); ($sec, $usec) = unpack($timeval, $tp); $sec + $usec/1000000; } sub timediff { ## returns seconds since $mark &gettimeofday - $mark; } sub get_down { ## Returns time of the current keypress. $mark should have already ## been set by the keypress before this function is called. Sets ## $mark at key release. local($retval); &key_ready; &cleanup("inconsistency\n") if getc(STDIN) ne 'u'; $retval = &timediff; $mark = &gettimeofday; $retval; } sub get_up { local($timeout) = @_; local($retval); return 0 unless &key_ready($timeout); &cleanup("inconsistency\n") if getc(STDIN) ne 'd'; $retval = &timediff; $mark = &gettimeofday; $retval; } sub min { # returns the min of a list local($min) = $_[0]; foreach (@_) { $min = $_ if $_ < $min; } $min; } sub max { # returns the min of a list local($max) = $_[0]; foreach (@_) { $max = $_ if $_ > $max; } $max; } sub calibrate_lengths { ## find out what the user considers a dash or and a dot print "Enter the following: --- ... --- ...\n"; &key_ready; &cleanup("inconsistency\n") if getc(STDIN) ne 'd'; $mark = &gettimeofday; $dash[0] = &get_down; $shortspace[0] = &get_up; $dash[1] = &get_down; $shortspace[1] = &get_up; $dash[2] = &get_down; $longspace[0] = &get_up; $dot[0] = &get_down; $shortspace[2] = &get_up; $dot[1] = &get_down; $shortspace[3] = &get_up; $dot[2] = &get_down; $longspace[1] = &get_up; $dash[3] = &get_down; $shortspace[4] = &get_up; $dash[4] = &get_down; $shortspace[5] = &get_up; $dash[5] = &get_down; $longspace[2] = &get_up; $dot[3] = &get_down; $shortspace[6] = &get_up; $dot[4] = &get_down; $shortspace[7] = &get_up; $dot[5] = &get_down; &get_up; ## Take the longest dot and the shortest dash, make halfway point ## the criterion for deciding. $c = (&min(@dash) + &max(@dot)) / 2; ## same for the spaces $sc = (&min(@longspace) + &max(@shortspace)) / 2; } sub cleanup { local($msg) = @_; print $msg if $msg && $msg ne "INT"; print "cleaning up\n"; if ($ENV{'DISPLAY'}) { system("xset r"); # turn on autorepeat } exit; } SHAR_EOF chmod +x 'morse.pl' fi # end of overwriting check if test -f 'keypress.c' then echo shar: will not over-write existing file "'keypress.c'" else cat << \SHAR_EOF > 'keypress.c' #include #include void close_window(void); void event_loop(void); void wait_until_visible(void); Display *dpy; Window win; int screen_num; void main() { /* connect to the X server */ if ((dpy = XOpenDisplay(NULL)) == NULL) { fprintf(stderr, "screen: Cannot connect to the X server.\n"); exit(1); } screen_num = DefaultScreen(dpy); /* create the window */ win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 200, 200, 1, BlackPixel(dpy, screen_num), WhitePixel(dpy, screen_num)); XSelectInput(dpy, win, KeyPressMask | KeyReleaseMask | ExposureMask); XMapWindow(dpy, win); wait_until_visible(); event_loop(); close_window(); } void event_loop(void) { XEvent event; while (1) { XNextEvent(dpy, &event); switch(event.type) { case MappingNotify: XRefreshKeyboardMapping((XMappingEvent *) &event); break; case KeyPress: printf("d"); fflush(stdout); break; case KeyRelease: printf("u"); fflush(stdout); break; default: break; } } } void close_window(void) { XDestroyWindow(dpy, win); XCloseDisplay(dpy); } void wait_until_visible(void) { XEvent event; do XNextEvent(dpy, &event); while (event.type != Expose); } SHAR_EOF fi # end of overwriting check # End of shell archive exit 0 -- Jin Choi |NeXTmail, MIME accepted, RIPEM and PGP public keys available jsc@mit.edu |by finger to monolith.mit.edu and key servers MD5 of RIPEM Public Key: D262D5F296E23901E064103AB4359F75 PGP fingerprint: A2 AB 40 DD E9 28 89 34 B0 BE 4E 09 2A 05 E0 2F