RECORDER Jeffrey S. Shulman Last revised on: July 7, 1984 1. Introduction RECORDER is a package that allows you to record and playback mouse and keyboard events. These events are recorded as you perform them in (more or1 less ) real time. During playback these recorded events arere-performedasif you were there doing it again. RECORDER performs these feats of magic by redefining the low level mouse and keyboard handlers. Specifically RECORDER provides its own versions of GETMOUSESTATE and \GETSYSBUF (as well as a slightly modified version of \KEYHANDLER1.) 2. Use To use you first load RECORDER.DCOM. After this file is loaded it will BKSYSBUF its initialization function as well as a HARDRESET (this is necessary in order for the modified \KEYHANDLER1 to take affect.) 2.1. Starting a recording To start a recording session you use the function RECORD.START. This function returns immediately with the array the recording will be placed in. This array is a SMALLP array of \RASIZE elements. At this point the recording has not actually started. You should now position the mouse where you want it to be when the recording starts. To actually start the recording you press the CONTROL and LEFT SHIFT key simultaneously (this fact also appears in the PROMPTWINDOW after you call RECORD.START as a reminder.) When these keys are pressed the recording starts. The message Recording.... will appear in the PROMPTWINDOW. Recording proceeds until either you press CTRL-LSHIFT again or the array fills up. When either of these events occur the message stopped. will appear in the PROMPTWINDOW. A sync event (described below) is recorded automatically when you start and when you stop a recording. 1 N.B. Due to the way playback occurs interrupts will not be seen in real time. For example, if you were pretty-printing a long function to the typescript window and ^E'ed it in the middle, the printing would (during recording) stop immediately. However, during playback, the ^E would not be seen until the pretty-printing was finished. 1 Thus, an example of the sequence of events would be: (SETQ A (RECORD.START)) position the mouse to the starting position Press CTRL-LSHIFT perform the desired actions Press CTRL-LSHIFT This array may be saved on a file using the UGLYVARS File Package command. The function SQUEEZE.RECORDING, described below, can be used to eliminate much of the dead space. 2.2. Playing back a previous recording To playback a previous recording you may use the function REPLAY whose single argument is the array returned by a previous call to RECORD.START. REPLAY will set in motion what is needed to playback an old recording and will return after the playback is finished. During playback the mouse and keyboard will NOT respond to anything you do. The only exceptions to this are: 1. Pressing CTRL-LSHIFT will stop playback and return control to you. 2. Pressing CTRL-LSHIFT-DELETE (the emergency interrupt) will stop playback and reset the system. You will again receive control of the keyboard and mouse when the playback is finished. If you typed what was in the previous "How to record" example you would play it back via: (REPLAY A) 3. Synchronization During playback you may wish to perform some "outside" event. For example while the mouse was moving around or when choosing various menu items you might want to print some accompanying text. An easy method of synchronizing just these kinds of things is provided so that things "happen" at the appropriate moment. During playback this synchronization is accomplished by the function RP.SYNC. If while playback is happening a sync event occurs (more about how to put one in below) the recording will essentially suspend itself until a call to RP.SYNC has been performed. If a call to RP.SYNC occurs before a sync event it will not return from it until this sync event happens. A sync event is automatically recorded at the start and at the end of each recording. 2 The function REPLAY is really a call to PLAYBACK.START followed by two calls to RP.SYNC (one for the start of the recording and one for the ending.) The function PLAYBACK.START (whose single argument in the recording array) is what really starts playback of a previous recording. This function queues up the recording for playback and returns immediately. You should use this function and provide your own RP.SYNC's if you want to "do" something during a playback. This should be come clear by an example. Suppose you wanted to print "I will now move to menu X", move to the menu, print "Now I will select an item from this menu" and then select an item from this menu. During recording you would move the mouse over to the menu, cause a sync event, and then select the menu item. A function that would playback this back correctly would look like: (LAMBDA (RECORDED-ARRAY) (PLAYBACK.START RECORDED-ARRAY) (printout T "I will now move to menu X" T) (RP.SYNC) (RP.SYNC) (printout T "Now I will select an item from this menu" T) (RP.SYNC)) What happens in this function is: 1. The recording is queued up. Since the act of making the recording puts in a sync event at the start, the mouse does not move. 2. "I will now move to menu X" is printed. 3. The first (RP.SYNC) starts the playback. The mouse begins moving to the menu. 4. The second (RP.SYNC) does not return until the second sync event happens. This is the one that was intentionally put in during recording. 5. "Now I will select an item from this menu" is printed after the second sync event. 6. The third (RP.SYNC) waits for the last sync event that was automatically recorded when the recording stopped to happen. 3.1. Sync events Sync events are caused to occur during recording by pressing the sync key. This key's number (returned by \KEYNAMETONUMBER) is bound to the global variable \SYNC.KEY. The default is 91 which is the AGAIN key on the 3 Dandelion's keyboard. When this key is pressed during recording a sync event is recorded at that instant. Feedback is provided by printing a letter S in the PROMPTWINDOW each time this key is pressed. N.B.: If you are not careful it is possible to have the wrong number of sync events to the number of RP.SYNC function calls. This could cause the mouse to freeze waiting for a RP.SYNC function call (which you cannot type in yourself since the keyboard is locked out during playback.) Should this happen it is possible to stop playback and regain control via the CTRL-LSHIFT abort. 4. Caveats It should go without saying that it is important for the same exact set of circumstances to exist before any given playback as they did when the recording was made. Little gotcha's will pop up in the unexpected places so it is important to "set up" before any playback. An example of a gotcha are popup menus that use the MENUOFFSET field to determine where they will next appear. If this is different at playback time from what it was at record time the results will not be the same (N.B.: the global menus WindowMenu, IconWindowMenu and BackgroundMenu are examples menus that use the MENUOFFSET field. Since these are the most commonly used menus that are all set to NIL (so they will be recreated from their corresponding Commands list) by both RECORD.START and PLAYBACK.START.) 5. Miscellaneous stuff During playback mouse key presses are indicated by the letter L, M and R shown along the bottom of the cursor bitmap (at the obvious positions.) The function SQUEEZE.RECORDING is provided to eliminate dead space at the end of a recording array. Its single argument is an array previously returned by RECORD.START. Its value is a new array of minimum size. i Table of Contents 1. Introduction 0 2. Use 0 2.1. Starting a recording 0 2.2. Playing back a previous recording 1 3. Synchronization 1 3.1. Sync events 2 4. Caveats 3 5. Miscellaneous stuff 3