Subject: Keyboard auto-repeat

From: David Singer <[email-masked]>
Date: Wed, 2 Sep 87 21:01:21 EST

Date: Wed 2 Sep 87 13:23:54-PDT
From: David Singer <[email-masked]>
Subject: Keyboard auto-repeat
To: [email-masked]
Cc: [email-masked], [email-masked]

Here's a simple implementation of keyboard auto-repeat;  it should be loaded
before anything that wants the value of ascii_keymap (I load it in my
user.ps).  The initial and repeat delay is tunable through the REPEAT_private
dictionary.  Note that simply loading this file does NOT turn on auto-repeat;
use the autorepeat function to start it (and stoprepeat to stop it).

%%%
%%% Auto-repeat the keyboard.
%%%
%%% D.W. Singer
%%%   Schlumberger Palo Alto Research.
%%%
%%% Create a process which listens for keyboard down
%%%  transitions;  when one happens, remember the key and
%%%  keystate, and start a timer event.  When the timer fires
%%%  send out a new event and re-start it.  When the up
%%%  transition happens, cancel the timer.

/REPEAT_private 30 dict begin
    /initial_delay 1 3 div 60 div def		% 1/3 second
    /repeat_delay  1 20 div 60 div def		% 20 per second

    /repeater_process null def
    /repeater_event null def
    /interest_event null def
currentdict end def

%% Fix ascii_keymap so that it also contains encoded ascii,
%%  so that events can also be distributed with ascii strokes
%%  directly in them.

ascii_keymap maxlength 256 eq
{
    /ascii_keymap ascii_keymap 512 dict copy def
    0 1 255
    { ascii_keymap exch dup put } for
} if

/autorepeat {
    REPEAT_private /repeater_process
    {
	newprocessgroup

	REPEAT_private begin
	/interest_event createevent def
	interest_event /Action [ /DownTransition /UpTransition /AutoRepeat ] put
	interest_event /Priority 10 put
	interest_event /Name   ascii_keymap put
	%%interest_event /Name null put
	interest_event /Canvas null put
	interest_event /Exclusivity true put

	interest_event expressinterest
	/repeater_event null def

	{
	    awaitevent
	    dup /Action get /UpTransition eq
	    {
		%%(stopping\n) print
		redistributeevent
		repeater_event null eq not
		{ repeater_event recallevent
		  /repeater_event null def } if
	    }
	    {
		repeater_event null eq not
		{ %%(cancelling\n) print
		  repeater_event recallevent
		  /repeater_event null def } if

		/repeater_event createevent def
		[ /Action /Name /TimeStamp /ClientData
		  /XLocation /YLocation %%/Canvas
		]
		{ 2 copy get repeater_event 3 1 roll put } forall
		redistributeevent
		repeater_event /ClientData get /AutoRepeat eq
		%%repeater_event /Action get /AutoRepeat eq
	    	{
		    %%(repeating %\n) [ repeater_event /Name get ] printf
		    repeater_event /TimeStamp
			repeater_event /TimeStamp get repeat_delay add put
	    	}
		{
		    %%(starting %\n) [ repeater_event /Name get ] printf
		    repeater_event /TimeStamp
			repeater_event /TimeStamp get initial_delay add put
		} ifelse
		repeater_event /ClientData /AutoRepeat put
		repeater_event /Process null put
		%%repeater_event /Action /AutoRepeat put
		repeater_event sendevent
	    } ifelse
	} loop

    } fork put
} def

/stoprepeat { REPEAT_private /repeater_process get killprocess } def
-------