jim@athsys.uucp (Jim Becker) (02/21/89)
Finally! Here is the XGhost work that I have done. There are only four files in this shar, their usefulness is as follows: README.XGhost -- how/what/why XGhost is, release notes. casper.c -- little program that monitors XGhost status changes.patch -- `diff -c' format changes, executed from the core.src directory. (Note that this is my first time doing this, and it may need tweeking. I also started from a virgin X11R2..) sunCapture.c -- main record/playback logic for XGhost. This goes into the ddx/sun directory. I hope that this works ok; I'm not well versed in the mechanisms for this type of release. Additional changes to this, for R3 and any other additions, will have to be done by someone else. My current status is changing and I will not be able to continue enhancing this code. This code was created and tested on Sun 3/60 and Sun 3/50 running OS release 3.4. Good luck, have fun! -Jim Becker ...!sun!athsys!jim February 20th, 1989 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README.XGhost casper.c changes.patch sunCapture.c # Wrapped by jim@tityus on Mon Feb 20 11:19:09 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'README.XGhost' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README.XGhost'\" else echo shar: Extracting \"'README.XGhost'\" \(6539 characters\) sed "s/^X//" >'README.XGhost' <<'END_OF_FILE' X X XGhost.Sun Documentation X XThis is the description of the implementation and usage of the XGhost Xfeature now in the X Server logic for Sun machines. This addition is Xfor the X11R2 version of the code. The upgrade to R3 is something that XI don't have the time to do. We are also not yet running R3 here. X XThe release of this code to the net is the first time that I have Xdone such a thing, so I hope that what I am doing is corrct. I did Xa `diff -c' to create the file, then am sharing everything together. X XOverview X XThe XGhost functionality affords the user the ability to capture and Xplayback an arbitrary user session with the X Window System. This Xcapture/playback simulates the exact sequence of user input at the XFirm_event level (i.e. -- device driver) within the Server. X XIt is important to note that a sequence that is captured will only Xreplay in the same method if the machine state is identical at the Xcommencement of playback to that at commencement of capture. This Xmeans that this logic doesn't understand anything other than really Xlow level stuff, so the same low level stuff needs the same starting Xpoint to work correctly. Note also that the mouse sensitivity during Xstorage and playback has to be the same. X XIf anything goes astray in the playback the software will currently Xnot recognize this has happened. It will merrily continue along with Xghosting the user input. Make sure that you take this into account Xbefore putting "rm -Rf *" type operations into the script! I attempted Xto provide a shortcut to afford this, but it cause the playback to be Xinterrupted (it would pause until user input happened). Fixes that Xcorrect this would be helpful, as one currently has to wait for the Xduration of the session to gain control of the server once again. X X XUsage X XThere are two modes available, saving events and playing events. XNormally these would be mutually exclusive, but with minor changes to Xthe record logic they need not be. The signal to the logic that there Xis a change in the current state is signified by performing mouse Xclicks in the upper left hand corner of the screen. The mouse buttons Xeach stand for a different mode change, as follows: X X Left Button -- commence capture of events X X Middle Button -- conclude capture of events X X Right Button -- perform playback of events X XThe events that are stored and played back are saved in specific Xhardcoded files. These files are either created or opened upon desired Xaction. The files used are stored in the directory /usr/tmp and are as Xfollows: X X save.events -- file created with user events X X play.events -- file opened and played during playback X X debug.events -- optional debugging output file X XThe play.events file is created initially by a capture as a Xsave.events file. It needs to be moved or renamed before playback is Xexpected. The debugging file is useful if the logic isn't working or Xis being moved to another platform. There is an internal flag in the XsunCapture.c file that toggles this file creation. X XFiles that are active can be identified because the file mask is Xmodified to enable the execute bit. Once the file is no longer active Xthe bit is disabled. This can be used programmatically to (uggh) poll Xthe current state of the XGhost logic. It can also be checked with the X'-F' option of ls. Each time there is a capture event session the Xsave.events (and the possibly the debug.events) file(s) are rewritten. XThere is a program created, called casper.c, that outputs current Xstate via the state of an icon in the lower right corner of the Xdisplay screen. X XIt is important to move or rename save files that are desired to be Xretained. The best method to manage the files is a program that Xassigns significance to them by naming and moves them around as Xneeded. I intended to write one for our use, but it would not be Xavailable outside of my company, as it used proprietary UI technology. X XThe format of the files is ASCII, but it is compressed as much as Xpossible to save space. There is no compression of the mouse events or Xother events, as that would not function for our need. This is easy to Xdo, but in our case would not work. To determine the complete format Xof the files look to the source code. X XDuring capture the autorepeat feature of the server is disabled. XDuring playback the terminal bell is disabled. These are due to funky Xprogrammatic needs; the call to usleep() upsets the timer interrupt. XThe call to usleep() could be replaced by a timeout call to select(), Xbut I do not have the time to make this modification. X XFiles Modified X XThere was the addition of only one file, sunCapture.c, to implement Xthe save logic. Other files in the ddx/sun directory that had to be Xmodified are the following: X X sunInit.c, sunKbd.c, sunMouse.c, Imakefile X XThe changes are available in a diff patch file. The other file that Xhad to be changed (that took me FOREVER to find!!) is the file: X X os/4.2bsd/connection.c X XThere is just a single line change in there, that resets the signal Xhandler and timer for me after it is used in the ReadBuffer() routine. XMake sure that you put this in, as not having it will cause the Xplayback to hang you! X XThere is a quick hack program, casper.c, that provides iconic feedback Xof the current state of the XGhost. Build it and run it in the Xbackground. X X XConclusion X XThe logic plays back events at the same speed as the initial input. XMaking this playback faster requires additional logic to synchronize Xdifferent types of resource usage completion. This is beyond the scope Xof the input mechanisms, and is "an exercise for the reader". X XThe method used for the timing of the events should probably use a Xdelta time between events, rather than a delta from the beginning of Xthe run. This is useful so one can concatenate different sessions Xtogether for a longer run. Also the keystrokes should probabily be Xmapped in the events, so it is easier to read what the user typed if Xlooking at events. A will leave this completion for others. X XI hope that this effort is useful and functions as a sturdy bridge Xuntil said time when the X Consortium completes and distributes their Xsolution. X XSorry that this took so long to get out, it was somewhat of a battle Xto have it actually happen. Any fixes or additions that are Xaccomplished would be of interest to me, please give me feedback as Xappropriate. I am moving to Sun Microsystems in the next few weeks Xalso, so mail responses may take a little while after the 23rd. Hope Xthat this helps !! X X X-Jim Becker ...!sun!athsys!jim February 20, 1989 X X END_OF_FILE if test 6539 -ne `wc -c <'README.XGhost'`; then echo shar: \"'README.XGhost'\" unpacked with wrong size! fi # end of 'README.XGhost' fi if test -f 'casper.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'casper.c'\" else echo shar: Extracting \"'casper.c'\" \(15366 characters\) sed "s/^X//" >'casper.c' <<'END_OF_FILE' X/* X * casper.c -- program to watch XGhost status X * X * This program is used to provide a graphical display of the X * current state of the XGhost logic in the X Server. The method X * used is to watch for the execute bit(s) in the save/playback X * hardcoded files that the XGhost server logic modifies. The X * output of this program is simply the correct iconic form to X * represent the nature of the currect activity of the XGhost. X * X * This program currently puts the initial icon in the lower-right X * corner of the screen. This should be generalized w/ geometry X * interpretation. (It's just a `quick hack'...) X * X * Jim Becker February 14, 1989 X */ X X#include <ctype.h> X#include <stdio.h> X#include <time.h> X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/dir.h> X X#include <X11/Xlib.h> X#include <X11/Xatom.h> X#include <X11/Xutil.h> X X#define DELAY_TIME 3 X X#define WIDTH 64 X#define HEIGHT 64 X#define TOP_RECT 46 X#define BORDER_WIDTH 2 X X#define TRUE 1 X#define FALSE 0 X X#define applic_name "Casper" X#define playback_file "/usr/tmp/play.events" X#define save_file "/usr/tmp/save.events" X Xtypedef enum {Inactive, Record, Playback} XGhostState; X XXGhostState CurrentState, PriorState; XDisplay *display; XVisual visual; XXSetWindowAttributes X attributes; XWindow RootWin; XWindow window; XPixmap inactive, record, playback; XGC gc, gcb; X X/* X * ==== These are iconic images already created an bundled herein ==== X */ X#define inactive_width 64 X#define inactive_height 64 Xstatic char inactive_bits[] = { X 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x00, 0x00, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x80, X 0x01, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x80, 0x01, 0xfc, 0x01, 0x08, X 0x10, 0x00, 0x7f, 0x80, 0x01, 0xff, 0x07, 0x04, 0x20, 0xc0, 0xff, 0x81, X 0x81, 0xff, 0x0f, 0xfe, 0x7f, 0xe0, 0xff, 0x83, 0xc1, 0xff, 0x1f, 0xfe, X 0x7f, 0xf0, 0xff, 0x87, 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, X 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, 0xf1, 0xff, 0x7f, 0x00, X 0x00, 0xfc, 0xff, 0x9f, 0xf1, 0xff, 0x7f, 0xd0, 0x7b, 0xfc, 0xff, 0x9f, X 0xf1, 0xdf, 0x7f, 0x50, 0x48, 0xfc, 0xf7, 0x9f, 0xf1, 0x8f, 0x7f, 0x50, X 0x38, 0xfc, 0xe3, 0x9f, 0xf1, 0xdf, 0x7f, 0x50, 0x48, 0xfc, 0xf7, 0x9f, X 0xf1, 0xff, 0x7f, 0xde, 0x7b, 0xfc, 0xff, 0x9f, 0xf1, 0xff, 0x7f, 0x00, X 0x00, 0xfc, 0xff, 0x9f, 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, X 0xe1, 0xff, 0x3f, 0x80, 0x01, 0xf8, 0xff, 0x8f, 0xc1, 0xff, 0x1f, 0x80, X 0x01, 0xf0, 0xff, 0x87, 0x81, 0xff, 0x0f, 0xa0, 0x05, 0xe0, 0xff, 0x83, X 0x01, 0xff, 0x07, 0xc0, 0x03, 0xc0, 0xff, 0x81, 0x01, 0xfc, 0x01, 0x80, X 0x01, 0x00, 0x7f, 0x80, 0x01, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x80, X 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, X 0x00, 0x00, 0x00, 0x80, 0x61, 0x00, 0x60, 0x00, 0x01, 0x00, 0x00, 0x80, X 0xe1, 0x00, 0x70, 0x00, 0x01, 0x00, 0x00, 0x80, 0xc1, 0x01, 0x38, 0x00, X 0x01, 0x00, 0x80, 0x80, 0x81, 0x03, 0x1c, 0x00, 0x01, 0x00, 0x80, 0x80, X 0x01, 0x07, 0x0e, 0x00, 0x01, 0x00, 0xe0, 0x83, 0x01, 0x0e, 0x07, 0x3e, X 0x9f, 0x8f, 0x8f, 0x80, 0x01, 0x9c, 0x03, 0x22, 0x91, 0x88, 0x80, 0x80, X 0x01, 0xf8, 0x01, 0x22, 0x91, 0x88, 0x8f, 0x80, 0x01, 0xf0, 0x00, 0x22, X 0x91, 0x08, 0x88, 0x80, 0x01, 0xf0, 0x00, 0x3e, 0x91, 0x8f, 0x8f, 0x80, X 0x01, 0xf8, 0x01, 0x20, 0x00, 0x00, 0x00, 0x80, 0x01, 0x9c, 0x03, 0x20, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x0e, 0x07, 0x20, 0xff, 0xff, 0xff, 0x80, X 0x01, 0x07, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x80, 0x81, 0x03, 0x1c, 0x3e, X 0xfc, 0xff, 0x3f, 0x80, 0xc1, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x80, X 0xe1, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x80, 0x61, 0x00, 0x60, 0xfe, X 0xff, 0xff, 0xff, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, X 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf9, 0xff, 0xff, 0xff, X 0xff, 0xff, 0xff, 0x9f, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, X 0x1d, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xfd, 0xfd, 0xff, 0xff, X 0xff, 0xff, 0xff, 0xbf, 0xfd, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, X 0xfd, 0xfd, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xbf, 0xfd, 0xfd, 0xff, 0xff, X 0x7f, 0xff, 0xff, 0xbf, 0xfd, 0xfd, 0xfd, 0xf7, 0x1f, 0xec, 0xff, 0xbf, X 0xfd, 0xfd, 0xc1, 0xeb, 0x70, 0x7f, 0x37, 0xbc, 0xfd, 0xfd, 0xdd, 0xdd, X 0x7e, 0x6f, 0xb7, 0xbd, 0xfd, 0xfd, 0xdd, 0xc1, 0x7e, 0x6f, 0x37, 0xbc, X 0xfd, 0xfd, 0xdd, 0xdd, 0x7e, 0xef, 0xba, 0xbf, 0x1d, 0xc0, 0xdd, 0xdd, X 0x70, 0xef, 0x3d, 0xbc, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, X 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x01, 0x00, 0x00, 0x00, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, X 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; X X#define record_width 64 X#define record_height 64 Xstatic char record_bits[] = { X 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x00, 0x00, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0x80, X 0x01, 0x00, 0x00, 0x80, 0x0c, 0x00, 0x00, 0x80, 0x01, 0xfc, 0x01, 0x00, X 0x19, 0x00, 0x7f, 0x80, 0x01, 0xff, 0x07, 0x00, 0x32, 0xc0, 0xff, 0x81, X 0x81, 0xff, 0x0f, 0xfe, 0x7f, 0xe0, 0xff, 0x83, 0xc1, 0xff, 0x1f, 0xfe, X 0x7f, 0xf0, 0xff, 0x87, 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, X 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, 0xf1, 0xff, 0x7f, 0x00, X 0x00, 0xfc, 0xff, 0x9f, 0xf1, 0xff, 0x7f, 0xd0, 0x7b, 0xfc, 0xff, 0x9f, X 0xf1, 0xdf, 0x7f, 0x50, 0x48, 0xfc, 0xf7, 0x9f, 0xf1, 0x8f, 0x7f, 0x50, X 0x38, 0xfc, 0xe3, 0x9f, 0xf1, 0xdf, 0x7f, 0x50, 0x48, 0xfc, 0xf7, 0x9f, X 0xf1, 0xff, 0x7f, 0xde, 0x7b, 0xfc, 0xff, 0x9f, 0xf1, 0xff, 0x7f, 0x00, X 0x00, 0xfc, 0xff, 0x9f, 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, X 0xe1, 0xff, 0x7f, 0x81, 0xa1, 0xf8, 0xff, 0x8f, 0xc1, 0xff, 0x9f, 0x82, X 0x41, 0xf1, 0xff, 0x87, 0x81, 0xff, 0x0f, 0xa5, 0x85, 0xe2, 0xff, 0x83, X 0x01, 0xff, 0x07, 0xca, 0x03, 0xc5, 0xff, 0x81, 0x01, 0xfc, 0x01, 0x94, X 0x01, 0x0a, 0x7f, 0x80, 0x01, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x80, X 0x01, 0x00, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x80, 0x01, 0x00, 0x00, 0x05, X 0x80, 0x02, 0x00, 0x80, 0x61, 0x00, 0xe0, 0x02, 0x41, 0x01, 0x00, 0x80, X 0xe1, 0x00, 0x70, 0x01, 0xa1, 0x00, 0x00, 0x80, 0xc1, 0x01, 0x38, 0x00, X 0x01, 0x00, 0x80, 0x80, 0x81, 0x03, 0x1c, 0x00, 0x01, 0x00, 0x80, 0x80, X 0x01, 0x07, 0x0e, 0x00, 0x01, 0x00, 0xe0, 0x83, 0x01, 0x0e, 0x07, 0x3e, X 0x9f, 0x8f, 0x8f, 0x80, 0x01, 0x9c, 0x03, 0x22, 0x91, 0x88, 0x80, 0x80, X 0x01, 0xf8, 0x01, 0x22, 0x91, 0x88, 0x8f, 0x80, 0x01, 0xf0, 0x00, 0x22, X 0x91, 0x08, 0x88, 0x80, 0x01, 0xf0, 0x00, 0x3e, 0x91, 0x8f, 0x8f, 0x80, X 0x01, 0xf8, 0x01, 0x20, 0x00, 0x00, 0x00, 0x80, 0x01, 0x9c, 0x03, 0x20, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x0e, 0x07, 0x20, 0xff, 0xff, 0xff, 0x80, X 0x01, 0x07, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x80, 0x81, 0x03, 0x1c, 0x3e, X 0xfc, 0xff, 0x3f, 0x80, 0xc1, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x80, X 0xe1, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x80, 0x61, 0x00, 0x60, 0xfe, X 0xff, 0xff, 0xff, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, X 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf9, 0xff, 0xff, 0xff, X 0xff, 0xff, 0xff, 0x9f, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, X 0x1d, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xdd, 0xf7, 0xff, 0xff, X 0xff, 0xff, 0xff, 0xbf, 0xdd, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, X 0xdd, 0xf7, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xbf, 0xdd, 0xf7, 0xff, 0xff, X 0xff, 0xfb, 0xff, 0xbf, 0x1d, 0xf8, 0xff, 0xff, 0xfd, 0xdb, 0xff, 0xbf, X 0x5d, 0x3e, 0x0c, 0x83, 0xe1, 0xfb, 0xff, 0xbf, 0xdd, 0xbc, 0xed, 0xbb, X 0x6d, 0xd8, 0x6c, 0xb8, 0xdd, 0x39, 0xec, 0xbb, 0x7d, 0xdb, 0x6a, 0xbb, X 0xdd, 0xb3, 0xef, 0xbb, 0x7d, 0xdb, 0x66, 0xb8, 0xdd, 0x37, 0x0c, 0x83, X 0x7d, 0xd8, 0xee, 0xbb, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xb8, X 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x01, 0x00, 0x00, 0x00, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, X 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; X X#define playback_width 64 X#define playback_height 64 Xstatic char playback_bits[] = { X 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x01, 0x00, 0x00, 0x00, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, X 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x80, 0x01, 0xfc, 0x01, 0x00, X 0x18, 0x00, 0x7f, 0x80, 0x01, 0xff, 0x07, 0x00, 0x30, 0xc0, 0xff, 0x81, X 0x81, 0xff, 0x0f, 0xfe, 0x7f, 0xe0, 0xff, 0x83, 0xc1, 0xff, 0x1f, 0xfe, X 0x7f, 0xf0, 0xff, 0x87, 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, X 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, 0xf1, 0xff, 0x7f, 0x00, X 0x00, 0xfc, 0xff, 0x9f, 0xf1, 0xff, 0x7f, 0xd0, 0x7b, 0xfc, 0xff, 0x9f, X 0xf1, 0xdf, 0x7f, 0x50, 0x48, 0xfc, 0xf7, 0x9f, 0xf1, 0x8f, 0x7f, 0x50, X 0x38, 0xfc, 0xe3, 0x9f, 0xf1, 0xdf, 0x7f, 0x50, 0x48, 0xfc, 0xf7, 0x9f, X 0xf1, 0xff, 0x7f, 0xde, 0x7b, 0xfc, 0xff, 0x9f, 0xf1, 0xff, 0x7f, 0x00, X 0x00, 0xfc, 0xff, 0x9f, 0xe1, 0xff, 0x3f, 0x00, 0x00, 0xf8, 0xff, 0x8f, X 0xe1, 0xff, 0xff, 0x80, 0x61, 0xf8, 0xff, 0x8f, 0xc1, 0xff, 0x9f, 0x81, X 0xc1, 0xf0, 0xff, 0x87, 0x81, 0xff, 0x0f, 0xa3, 0x85, 0xe1, 0xff, 0x83, X 0x01, 0xff, 0x07, 0xc6, 0x03, 0xc3, 0xff, 0x81, 0x01, 0xfc, 0x01, 0x8c, X 0x01, 0x06, 0x7f, 0x80, 0x01, 0xf8, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x80, X 0x01, 0x00, 0x00, 0x06, 0x00, 0x03, 0x00, 0x80, 0x01, 0x00, 0x00, 0x03, X 0x80, 0x01, 0x00, 0x80, 0x61, 0x00, 0xe0, 0x01, 0xc1, 0x00, 0x00, 0x80, X 0xe1, 0x00, 0xf0, 0x00, 0x61, 0x00, 0x00, 0x80, 0xc1, 0x01, 0x38, 0x00, X 0x01, 0x00, 0x80, 0x80, 0x81, 0x03, 0x1c, 0x00, 0x01, 0x00, 0x80, 0x80, X 0x01, 0x07, 0x0e, 0x00, 0x01, 0x00, 0xe0, 0x83, 0x01, 0x0e, 0x07, 0x3e, X 0x9f, 0x8f, 0x8f, 0x80, 0x01, 0x9c, 0x03, 0x22, 0x91, 0x88, 0x80, 0x80, X 0x01, 0xf8, 0x01, 0x22, 0x91, 0x88, 0x8f, 0x80, 0x01, 0xf0, 0x00, 0x22, X 0x91, 0x08, 0x88, 0x80, 0x01, 0xf0, 0x00, 0x3e, 0x91, 0x8f, 0x8f, 0x80, X 0x01, 0xf8, 0x01, 0x20, 0x00, 0x00, 0x00, 0x80, 0x01, 0x9c, 0x03, 0x20, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x0e, 0x07, 0x20, 0xff, 0xff, 0xff, 0x80, X 0x01, 0x07, 0x0e, 0x20, 0x00, 0x00, 0x00, 0x80, 0x81, 0x03, 0x1c, 0x3e, X 0xfc, 0xff, 0x3f, 0x80, 0xc1, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x80, X 0xe1, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x80, 0x61, 0x00, 0x60, 0xfe, X 0xff, 0xff, 0xff, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, X 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xf9, 0xff, 0xff, 0xff, X 0xff, 0xff, 0xff, 0x9f, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, X 0x1d, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xdd, 0xf7, 0xff, 0xff, X 0xff, 0xff, 0xff, 0xb7, 0xdd, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb7, X 0xdd, 0xb7, 0xff, 0xff, 0xfe, 0xff, 0xef, 0xb7, 0xdd, 0xb7, 0xff, 0xff, X 0xfe, 0xff, 0xef, 0xb7, 0xdd, 0xb7, 0xef, 0xff, 0xfe, 0xfd, 0x6f, 0xb7, X 0x1d, 0xb8, 0xd7, 0xdd, 0xfe, 0x3a, 0xac, 0xb7, 0xdd, 0xbf, 0xbb, 0xdd, X 0x60, 0xb7, 0xcf, 0xb7, 0xdd, 0xbf, 0x83, 0xdd, 0x6e, 0xb0, 0xaf, 0xb7, X 0xdd, 0xbf, 0xbb, 0xc1, 0x6e, 0xb7, 0x6f, 0xbf, 0xdd, 0x3f, 0xbb, 0xdf, X 0x60, 0x37, 0xec, 0xb6, 0xfd, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xbf, X 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x01, 0x00, 0x00, 0x00, X 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, X 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}; X X X/* X * actual code! X */ X XInitializeProgram() X{ X XSizeHints xsize; X XSetWindowAttributes wattr; X int scrno; X int white, black; X XGCValues gcvalues; X int gcvaluemask; X int X,Y; X X display = XOpenDisplay( NULL ); X X if( display == NULL ) { X printf("** Can't access the display !! **\n"); X exit(1); X } X X scrno = DefaultScreen(display); X RootWin = RootWindow(display,scrno); X X white = WhitePixel(display,DefaultScreen(display)); X black = BlackPixel(display,DefaultScreen(display)); X X /* hardcode position to lower right edge of screen */ X X = DisplayWidth( display, scrno ) - WIDTH - BORDER_WIDTH * 2 - 2; X Y = DisplayHeight( display, scrno ) - HEIGHT - BORDER_WIDTH * 2 - 2; X X window = XCreateSimpleWindow( display, RootWin, X X, Y, WIDTH, HEIGHT, BORDER_WIDTH, X black, white ); X X if( window == NULL ) { X printf("** Can't open display window !! **\n"); X return FALSE; X } X X XChangeProperty( display, window, XA_WM_NAME, XA_STRING, 8, X PropModeReplace, applic_name, sizeof(applic_name) ); X X xsize.x = X; X xsize.y = Y; X xsize.width = WIDTH; X xsize.height = HEIGHT; X xsize.min_width = WIDTH; X xsize.min_height = HEIGHT; X xsize.max_width = WIDTH; X xsize.max_height = HEIGHT; X X xsize.flags = USPosition | USSize | X PPosition | PSize | X PMinSize | PMaxSize; X X XSetNormalHints( display, window, &xsize ); X X XSelectInput( display, window, ExposureMask ); X X XMapWindow( display, window ); X X /* create normal graphics contexts */ X gcvaluemask = GCFunction | X GCPlaneMask | X GCForeground | X GCBackground | X GCGraphicsExposures | X GCSubwindowMode ; X X gcvalues.function = GXcopy; X gcvalues.plane_mask = AllPlanes; X gcvalues.foreground = black; X gcvalues.background = white; X gcvalues.graphics_exposures X = FALSE; X gcvalues.subwindow_mode = IncludeInferiors; X X gc = XCreateGC( display, window, gcvaluemask, &gcvalues ); X X /* create inverting graphics context */ X gcvalues.foreground = white^black; X gcvalues.function = GXxor; X X gcb = XCreateGC( display, window, gcvaluemask, &gcvalues ); X X inactive = XCreateBitmapFromData( display, window, X inactive_bits, inactive_width, inactive_height ); X X record = XCreateBitmapFromData( display, window, X record_bits, record_width, record_height ); X X playback = XCreateBitmapFromData( display, window, X playback_bits, playback_width, playback_height ); X X CurrentState = PriorState = Inactive; X} X X XDetermineImage() X{ X struct stat filestatus; X X CurrentState = Inactive; X X if( stat( playback_file, &filestatus ) == 0 ) { X if( filestatus.st_mode & S_IEXEC ) X CurrentState = Playback; X else { X if( stat( save_file, &filestatus ) == 0 ) { X if( filestatus.st_mode & S_IEXEC ) X CurrentState = Record; X } X } X } X X if( CurrentState != PriorState ) { X UpdateImage(); X PriorState = CurrentState; X } X} X XUpdateImage() X{ X Pixmap pix; X X/* PrintState(); */ X X switch( CurrentState ) { X case Inactive: X pix = inactive; X break; X case Record: X pix = record; X break; X case Playback: X pix = playback; X break; X } X X XCopyArea( display, pix, window, gc, 0,0, X record_width, record_height, 0,0); /* all sizes are the same */ X X XFlush( display ); X} X X/* X * invert blinks the state while it is active X */ XBlinkState() X{ X XFillRectangle( display, window, gcb, 0, TOP_RECT, WIDTH, HEIGHT-TOP_RECT ); X} X XPrintState() X{ X char *p; X X switch( CurrentState ) { X case Inactive: X p = "Inactive"; X break; X case Record: X p = "Record"; X break; X case Playback: X p = "Playback"; X break; X } X X printf("current state is %s\n", p ); X} X Xmain() X{ X XEvent xevent; X X if( !InitializeProgram() ) { X printf("Can't startup, shutdown.\n"); X exit(1); X } X X while( TRUE ) { X X /* check current status */ X DetermineImage(); X X /* we don't do anything much here */ X while( XPending(display) ) { X X XNextEvent( display, &xevent ); X X switch( xevent.type ) { X case Expose: X UpdateImage(); X break; X default: X break; X } X X } X X sleep(DELAY_TIME); X X if( CurrentState == Record || X CurrentState == Playback ) X BlinkState(); X } X} X X X END_OF_FILE if test 15366 -ne `wc -c <'casper.c'`; then echo shar: \"'casper.c'\" unpacked with wrong size! fi # end of 'casper.c' fi if test -f 'changes.patch' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'changes.patch'\" else echo shar: Extracting \"'changes.patch'\" \(9102 characters\) sed "s/^X//" >'changes.patch' <<'END_OF_FILE' XCommon subdirectories: oldserver/ddx and server/ddx XCommon subdirectories: oldserver/os and server/os XCommon subdirectories: oldserver/ddx/sun and server/ddx/sun Xdiff -c -r oldserver/ddx/sun/Imakefile server/ddx/sun/Imakefile X*** oldserver/ddx/sun/Imakefile Mon Feb 20 10:06:15 1989 X--- server/ddx/sun/Imakefile Mon Feb 20 10:07:16 1989 X*************** X*** 2,7 **** X--- 2,8 ---- X sunInit.c \ X sunBW2.c \ X sunBW2zoid.c \ X+ sunCapture.c \ X sunCursor.c \ X sunIo.c \ X sunKbd.c \ XOnly in server/ddx/sun: README.XGhost XOnly in server/ddx/sun: change.list XOnly in server/ddx/sun: sunCapture.c Xdiff -c -r oldserver/ddx/sun/sunInit.c server/ddx/sun/sunInit.c X*** oldserver/ddx/sun/sunInit.c Mon Feb 20 10:05:43 1989 X--- server/ddx/sun/sunInit.c Thu Jan 12 13:39:08 1989 X*************** X*** 87,93 **** X *----------------------------------------------------------------------- X */ X /*ARGSUSED*/ X! static void X SigIOHandler(sig, code, scp) X int code; X int sig; X--- 87,93 ---- X *----------------------------------------------------------------------- X */ X /*ARGSUSED*/ X! /*static -- jcb */ void X SigIOHandler(sig, code, scp) X int code; X int sig; Xdiff -c -r oldserver/ddx/sun/sunKbd.c server/ddx/sun/sunKbd.c X*** oldserver/ddx/sun/sunKbd.c Mon Feb 20 10:05:44 1989 X--- server/ddx/sun/sunKbd.c Thu Jan 12 13:39:10 1989 X*************** X*** 61,66 **** X--- 61,67 ---- X extern CARD8 *sunModMap[]; X extern KeySymsRec sunKeySyms[]; X extern CARD16 keyModifiersList[]; X+ extern long EnabledDevices; X X static void sunBell(); X static void sunKbdCtrl(); X*************** X*** 139,144 **** X--- 140,149 ---- X return (!Success); X } X sysKbPriv.fd = kbdFd; X+ X+ /* define the device to the capture logic */ X+ cap_init( kbdFd, 1 ); X+ X (void) ioctl (kbdFd, KIOCTYPE, &sysKbPriv.type); X (void) ioctl (kbdFd, KIOCGTRANS, &sunKbPriv.trans); X #ifdef KB_SUN4 X*************** X*** 273,278 **** X--- 278,286 ---- X } X X RemoveEnabledDevice(kbdFd); X+ X+ /* terminate known connection to capture */ X+ cap_term( kbdFd ); X } X pKeyboard->on = FALSE; X break; X*************** X*** 302,311 **** X KbPrivPtr pPriv = (KbPrivPtr) pKeyboard->devicePrivate; X int kbdCmd; /* Command to give keyboard */ X int kbdOpenedHere; X! X! if (loudness == 0) { X return; X- } X X kbdOpenedHere = ( pPriv->fd < 0 ); X if ( kbdOpenedHere ) { X--- 310,319 ---- X KbPrivPtr pPriv = (KbPrivPtr) pKeyboard->devicePrivate; X int kbdCmd; /* Command to give keyboard */ X int kbdOpenedHere; X! X! /* jcb -- disable use of usleep() if timer signal is being used */ X! if ( cap_play_is_active() || loudness == 0) X return; X X kbdOpenedHere = ( pPriv->fd < 0 ); X if ( kbdOpenedHere ) { X*************** X*** 326,331 **** X--- 334,340 ---- X * Leave the bell on for a while == duration (ms) proportional to X * loudness desired with a 10 thrown in to convert from ms to usecs. X */ X+ X usleep (pPriv->ctrl->bell_duration * 1000); X X kbdCmd = KBD_CMD_NOBELL; X*************** X*** 414,421 **** X static Firm_event evBuf[MAXEVENTS]; /* Buffer for Firm_events */ X X pPriv = (KbPrivPtr) pKeyboard->devicePrivate; X- nBytes = read (pPriv->fd, evBuf, sizeof(evBuf)); X X if (nBytes < 0) { X if (errno == EWOULDBLOCK) { X *pNumEvents = 0; X--- 423,432 ---- X static Firm_event evBuf[MAXEVENTS]; /* Buffer for Firm_events */ X X pPriv = (KbPrivPtr) pKeyboard->devicePrivate; X X+ /* use the capture/playback read routine */ X+ nBytes = cap_read (pPriv->fd, evBuf, sizeof(evBuf)); X+ X if (nBytes < 0) { X if (errno == EWOULDBLOCK) { X *pNumEvents = 0; X*************** X*** 427,433 **** X *pNumEvents = nBytes / sizeof (Firm_event); X } X X! if (autoRepeatKeyDown && autoRepeatReady && X pPriv->ctrl->autoRepeat == AutoRepeatModeOn && *pNumEvents == 0) { X *pNumEvents = 1; /* Fake the event */ X evBuf[0].id = AUTOREPEAT_EVENTID; /* Flags autoRepeat event */ X--- 438,445 ---- X *pNumEvents = nBytes / sizeof (Firm_event); X } X X! /* jcb -- no auto repeat allowed for this server during capture !! (sorry) */ X! if ( cap_is_passive() && autoRepeatKeyDown && autoRepeatReady && X pPriv->ctrl->autoRepeat == AutoRepeatModeOn && *pNumEvents == 0) { X *pNumEvents = 1; /* Fake the event */ X evBuf[0].id = AUTOREPEAT_EVENTID; /* Flags autoRepeat event */ X*************** X*** 473,479 **** X X ptrPriv = (PtrPrivPtr) LookupPointerDevice()->devicePrivate; X X! if (autoRepeatKeyDown && fe->id == AUTOREPEAT_EVENTID) { X pPriv = (KbPrivPtr) pKeyboard->devicePrivate; X if (pPriv->ctrl->autoRepeat != AutoRepeatModeOn) { X autoRepeatKeyDown = 0; X--- 485,492 ---- X X ptrPriv = (PtrPrivPtr) LookupPointerDevice()->devicePrivate; X X! /* jcb -- no autorepeat allowed in this server during capture !! */ X! if ( cap_is_passive() && autoRepeatKeyDown && fe->id == AUTOREPEAT_EVENTID) { X pPriv = (KbPrivPtr) pKeyboard->devicePrivate; X if (pPriv->ctrl->autoRepeat != AutoRepeatModeOn) { X autoRepeatKeyDown = 0; X*************** X*** 535,541 **** X xE.u.u.type = KeyRelease; X } X X! if ((xE.u.u.type == KeyPress) && (keyModifiers == 0)) { X /* initialize new AutoRepeater event & mark AutoRepeater on */ X if (autoRepeatDebug) X ErrorF("sunKbdProcessEvent: VKEY_DOWN\n"); X--- 548,555 ---- X xE.u.u.type = KeyRelease; X } X X! /* jcb -- no auto repeat allowed for this server during capture !! */ X! if ( cap_is_passive() && (xE.u.u.type == KeyPress) && (keyModifiers == 0)) { X /* initialize new AutoRepeater event & mark AutoRepeater on */ X if (autoRepeatDebug) X ErrorF("sunKbdProcessEvent: VKEY_DOWN\n"); X*************** X*** 762,767 **** X--- 776,787 ---- X { X static struct timeval artv = { 0, 0 }; /* autorepeat timeval */ X X+ /* insure there is no time delay in select() if we are waiting for playback */ X+ if( cap_play_is_active() ) { X+ *pptv = NULL; X+ return; X+ } X+ X if (!autoRepeatKeyDown) X return; X X*************** X*** 790,795 **** X--- 810,819 ---- X pointer pReadmask; X { X struct timeval tv; X+ X+ /* don't do anything during playback */ X+ if( cap_play_is_active() ) X+ return; X X if (autoRepeatDebug) X ErrorF("sunWakeupHandler(ar=%d, err=%d):\n", autoRepeatKeyDown, err); Xdiff -c -r oldserver/ddx/sun/sunMouse.c server/ddx/sun/sunMouse.c X*** oldserver/ddx/sun/sunMouse.c Mon Feb 20 10:05:43 1989 X--- server/ddx/sun/sunMouse.c Thu Jan 12 13:39:12 1989 X*************** X*** 127,132 **** X--- 127,135 ---- X } X X sysMousePriv.fd = fd; X+ X+ /* define the device to the capture logic */ X+ cap_init( fd, 0 ); X } X } X X*************** X*** 171,176 **** X--- 174,182 ---- X VUIDSFORMAT, &oformat) < 0) { X Error ("VUIDSFORMAT"); X } X+ X+ /* terminate known connection to capture */ X+ cap_term( ((PtrPrivPtr)pMouse->devicePrivate)->fd ); X } X break; X X*************** X*** 251,257 **** X X pPriv = (PtrPrivPtr) pMouse->devicePrivate; X X! nBytes = read (pPriv->fd, evBuf, sizeof(evBuf)); X X if (nBytes < 0) { X if (errno == EWOULDBLOCK) { X--- 257,264 ---- X X pPriv = (PtrPrivPtr) pMouse->devicePrivate; X X! /* use the capture/playback read routine */ X! nBytes = cap_read (pPriv->fd, evBuf, sizeof(evBuf)); X X if (nBytes < 0) { X if (errno == EWOULDBLOCK) { X*************** X*** 330,335 **** X--- 337,359 ---- X X xE.u.keyButtonPointer.time = TVTOMILLI(fe->time); X X+ /* jcb -- mouse action in upper left signals change in capture/replay status */ X+ if( (pPriv->x < 10 && /* upper left corner */ X+ pPriv->y < 10) && X+ (fe->value == VKEY_UP) && /* mouse released */ X+ (fe->id == MS_LEFT || /* one of the buttons */ X+ fe->id == MS_MIDDLE || X+ fe->id == MS_RIGHT) ) { X+ X+ /* set to stable base for constant initialization coordinates */ X+ pPriv->x = 0; X+ pPriv->y = 0; X+ pSunPriv->mouseMoved = TRUE; X+ X+ /* dispatch the mouse click to do the appropriate action */ X+ cap_activate( fe->id ); X+ } X+ X switch (fe->id) { X case MS_LEFT: X case MS_MIDDLE: X*************** X*** 456,461 **** X--- 480,486 ---- X xE.u.keyButtonPointer.rootY = pPriv->y; X X (* pMouse->processInputProc) (&xE, pMouse); X+ X } X X /*- XCommon subdirectories: oldserver/os/4.2bsd and server/os/4.2bsd Xdiff -c -r oldserver/os/4.2bsd/connection.c server/os/4.2bsd/connection.c X*** oldserver/os/4.2bsd/connection.c Mon Feb 20 10:53:01 1989 X--- server/os/4.2bsd/connection.c Thu Jan 12 13:40:40 1989 X*************** X*** 325,330 **** X--- 325,334 ---- X * we must have read what we wanted. If we timed out, return FALSE */ X if(fTimeOut && debug_conns) X ErrorF("Timed out on connection %d\n", conn); X+ X+ /* jim becker -- reset the use of the timer that has been usurped!! */ X+ cap_reset_timer(); X+ X return (!fTimeOut); X } X END_OF_FILE if test 9102 -ne `wc -c <'changes.patch'`; then echo shar: \"'changes.patch'\" unpacked with wrong size! fi # end of 'changes.patch' fi if test -f 'sunCapture.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sunCapture.c'\" else echo shar: Extracting \"'sunCapture.c'\" \(14272 characters\) sed "s/^X//" >'sunCapture.c' <<'END_OF_FILE' X/* X * sunCapture.c -- code for ddx/sun record and playback X * of user events at the vuid level. X * X * This is the main module for this software functionality. X * This code is used to capture and playback the events that X * the user performs. This interfaces to the other software X * simply by replacing the read() call that is used by the X * keyboard and mouse drivers with a read() that performs X * the needed logic. Other support calls are sprinkled in X * ddx/sun code to perform initialization and activation X * of the various modes of this record/replay logic. X * X * Jim Becker -- December 22, 1988 X */ X X#include "sun.h" X#include <ctype.h> X#include <stdio.h> X#include <signal.h> X#include <sys/time.h> X X#define BADVAL -1 X#define MAXBUF 32 X#define DEBUG_FLAG FALSE X X#define SAVEFILE "/usr/tmp/save.events" X#define PLAYFILE "/usr/tmp/play.events" X#define DEBUGFILE "/usr/tmp/debug.events" X Xstatic short saveact = FALSE; Xstatic short playact = FALSE; Xstatic short dbugact = FALSE; X Xstatic int keyfd = BADVAL; Xstatic int moufd = BADVAL; Xstatic FILE *savefd; Xstatic FILE *playfd; Xstatic FILE *dbugfd; X Xstatic Firm_event locbuffer[MAXBUF]; Xstatic int keyecnt, mouecnt; Xstatic int eventcnt; Xstatic int actmask = 0766; Xstatic int passmask = 0666; Xstatic int timeexpired = TRUE; Xstatic int timestart = 0; Xstatic short debug_needed = DEBUG_FLAG; X Xstatic struct timeval tval; Xstatic struct timezone tzone; Xstatic struct itimerval value, ovalue; X X/* hooks to the signal IO processing */ Xextern int sunSigIO; Xextern void SigIOHandler(); X X/* predefines to local routines */ Xstatic void cap_init_debug(), cap_term_debug(), cap_output_debug(), X cap_open_play(), cap_close_play(), cap_open_save(), X cap_close_save(), cap_output_events(), cap_printf(), X cap_check_abort(); X X/* X * alarm handler routine -- sets flag signalling event is ready. X */ Xstatic void Xalarm_handler(sig, code, scp) Xint sig, code; Xstruct sigcontext *scp; X{ X /* signals that there are events in the wings for process */ X /* the following two flags are set also by SIGIO signals */ X sunSigIO++; X isItTimeToYield++; X X timeexpired = TRUE; X} X X X/* X * ==== Routines Called From External Sources ==== X */ X X/* X * initialize the file descriptor local copy (for definition) X */ Xvoid Xcap_init( fd, bool ) Xint fd; Xint bool; X{ X char *str; X X /* 0 = mouse; 1 = keyboard */ X if( bool == 0 ) X moufd = fd; X else X keyfd = fd; X} X X/* X * new vuid read routine. returns Firm_events to the user X * either from the virtual device or from the playback script. X * note that real reads during playback are lost. X */ Xint Xcap_read( fd, bufptr, bufsize ) Xint fd; Xchar *bufptr; Xint bufsize; X{ X int numbytes; X X if( playact ) X numbytes = cap_play_read( fd, bufptr, bufsize ); X else X numbytes = read( fd, bufptr, bufsize ); X X if( saveact && numbytes > 0 ) X cap_output_events( fd, bufptr, numbytes ); X X /* the following call _would_ allow premature abort of the playback */ X /* but the use of it causes the system to pause until some user input*/ X /* (note that I don't believe this _should_ happen, but it does....) */ X/* cap_check_abort(); */ X X return numbytes; X} X X/* X * terminate knowledge of an fd X */ Xvoid Xcap_term( fd ) Xint fd; X{ X if( fd == moufd ) X moufd = BADVAL; X else X if( fd == keyfd ) X keyfd = BADVAL; X X cap_close_save(); X} X X/* X * called to change the modes from the mouse button dispatcher X */ Xvoid Xcap_activate( button ) Xu_short button; X{ X switch( button ) { X case MS_LEFT: X cap_open_save(); X break; X case MS_MIDDLE: X cap_close_save(); X break; X case MS_RIGHT: X cap_open_play(); X break; X } X} X X X/* X * Reset the timer that ReadBuffer() stole (in os/4.2bsd/connection.c) !! X */ Xvoid Xcap_reset_timer() X{ X if( playact ) { X signal( SIGIO, SIG_IGN ); X signal( SIGALRM, alarm_handler ); X X setitimer( ITIMER_REAL, &value, &ovalue ); X } X} X X X/* X * state information used by rest of sun ddx X */ Xint Xcap_play_is_active() X{ X return playact; X} X X Xint Xcap_is_passive() X{ X return (playact || saveact ? FALSE : TRUE ); X} X X X X/* X * ==== Routines Used Internally ==== X */ X X/* X * open the playback file for the user X */ Xstatic void Xcap_open_play() X{ X playfd = fopen( PLAYFILE, "r" ); X X playact = (playfd != NULL); X X if( playact ) { X X /* make the mask appear active */ X chmod( PLAYFILE, actmask ); X X signal( SIGIO, SIG_IGN ); X signal( SIGALRM, alarm_handler ); X X gettimeofday( &tval, &tzone ); X X timestart = tval.tv_sec; X X eventcnt = 0; X X if( debug_needed == TRUE ) X cap_init_debug(); X X if( cap_load_next() == FALSE ) X cap_close_play(); X } X} X X/* X * terminate the playback file reading X */ Xstatic void Xcap_close_play() X{ X if( playact ) { X fclose(playfd); X playfd = NULL; X playact = FALSE; X X signal( SIGALRM, SIG_IGN ); X signal( SIGIO, SigIOHandler); X X /* make the mask appear passive */ X chmod( PLAYFILE, passmask ); X X cap_term_debug(); X } X} X X X/* X * initiate the save functionality X */ Xstatic void Xcap_open_save() X{ X savefd = fopen( SAVEFILE, "w" ); X X chmod( SAVEFILE, actmask ); X X saveact = (savefd != NULL); X X timestart = 0; X} X X/* X * terminate the save functionality X */ Xstatic void Xcap_close_save() X{ X if( saveact ) { X fclose(savefd); X savefd = NULL; X saveact = FALSE; X X chmod( SAVEFILE, passmask ); X } X} X X/* X * this is the main routine that either picks up the X * next loaded event from the playback file or simulates X * the actual situation during storage by returning X * failure status. The success of this routine returning X * the next event depends on: 1) The correct type of X * event (from matching fds) 2) The expiration of the X * event timer. The event timer goes off when the X * delta difference between the last event and the X * current event has elapsed. X */ Xstatic int Xcap_play_read( fd, bufptr, bufsize ) Xint fd; Xchar *bufptr; Xint bufsize; X{ X int bytesize; X X /* return either next event to the user or simulate EWOULDBLOCK */ X if( (((fd == moufd) && (mouecnt > 0)) || X ((fd == keyfd) && (keyecnt > 0))) && X timeexpired) { X X /* we have valid information, move it to user */ X /* buffer and return correct size in bytes */ X bytesize = (sizeof(Firm_event)) * eventcnt; X X bcopy( (char *)locbuffer, bufptr, bytesize ); X X /* pre-load the next event and setup timer for it */ X if( cap_load_next() == FALSE ) X cap_close_play(); X X return bytesize; X } X else { X errno = EWOULDBLOCK; X return BADVAL; X } X} X X/* X * load the next ASCII description of the X * events into the buffer. Note that the X * logic allows the time values to be generated X * in pairs (or better) that are reconstructed X * upon demand. (Thus saving space in the event X * file). X */ X Xstatic int Xcap_load_next() X{ X Firm_event *event = locbuffer; X Firm_event *levent = NULL; X int locnumevents; X int id, ptype, pair, evalue, sec, usec; X char etype; X char mtype; X int totusec; X int numparsed; X X /* back to zero! */ X mouecnt = keyecnt = eventcnt = 0; X X numparsed = fscanf(playfd,"%c%d", &etype, &eventcnt); X X if( numparsed != 2 ) X return FALSE; X X if( etype == 'm' ) X mouecnt = eventcnt; X else X keyecnt = eventcnt; X X locnumevents = eventcnt; X X while( locnumevents-- > 0 ) { X X id = ptype = pair = evalue = sec = usec = 0; X X if( etype == 'm' ) { X X fscanf(playfd, "_%c'%d:%x/%x", X &mtype, &evalue, &sec, &usec ); X X /* these are the only ones I have seen generated.. */ X switch( mtype ) { X case 'X': X id = LOC_X_DELTA; X ptype = FE_PAIR_ABSOLUTE; X pair = 130; /* (don't know significance!) */ X break; X case 'Y': X id = LOC_Y_DELTA; X ptype = FE_PAIR_ABSOLUTE; X pair = 131; /* (don't know significance!) */ X break; X case 'L': X id = MS_LEFT; X break; X case 'M': X id = MS_MIDDLE; X break; X case 'R': X id = MS_RIGHT; X break; X } X X } X else { X fscanf(playfd, "_%d'%d:%x/%x", X &id, &evalue, &sec, &usec ); X } X X /* zero then fill the event structure for user */ X bzero( (char *)event, sizeof(Firm_event) ); X X event->id = (u_short)id; X event->pair_type = (u_char)ptype; X event->pair = (u_char)pair; X event->value = evalue; X event->time.tv_sec = sec; X event->time.tv_usec = usec; X X /* fill in same time from last event if needed */ X if( levent != NULL && TVTOMILLI(event->time) == 0 ) { X event->time.tv_sec = levent->time.tv_sec; X event->time.tv_usec = levent->time.tv_usec; X } X else X event->time.tv_sec += timestart; X X /* set the last event to the current and bump ptr */ X levent = event++; X } X X fscanf(playfd,"\n"); X X /* is the debugging mode active ? */ X if( dbugact ) X cap_output_debug( (etype == 'm' ? moufd : keyfd ) ); X X /* determine delta value to next time event and set it */ X if( locbuffer[0].time.tv_usec < tval.tv_usec ) { X locbuffer[0].time.tv_usec += 1000000; X locbuffer[0].time.tv_sec -= 1; X } X X value.it_value.tv_sec = locbuffer[0].time.tv_sec - tval.tv_sec; X value.it_value.tv_usec = locbuffer[0].time.tv_usec - tval.tv_usec; X X /* insure that there are no strange numbers occuring... */ X if( value.it_value.tv_usec > 1000000 ) { X value.it_value.tv_sec += 1; X value.it_value.tv_usec %= 1000000; X } X else X if( value.it_value.tv_usec < 0 ) X value.it_value.tv_usec = 0; X X /* update current (relative) time of the last event in set */ X tval = locbuffer[eventcnt-1].time; X totusec = TVTOMILLI(value.it_value); X X /* insure some delay is there */ X if( totusec < 10 ) { X value.it_value.tv_sec = 0; X value.it_value.tv_usec= 10000; X } X X /* is the debugging logic active? */ X if( dbugact ) X cap_printf("timer(%d/%u)(%d)\n", value.it_value.tv_sec, X value.it_value.tv_usec, totusec ); X X /* clear timer expiration flag */ X timeexpired = FALSE; X X /* load the timer. This should always work... */ X setitimer( ITIMER_REAL, &value, &ovalue ); X X return TRUE; X} X X X/* X * output current events to the ASCII text file. The events X * output are compressed as much as possible as far as information X * content. This includes different fields for mouse and keyboard, X * as well as translation of mouse type and removal of redundant X * timing information. X */ X Xstatic void Xcap_output_events( fd, bufptr, bufsize ) Xint fd; Xchar *bufptr; Xint bufsize; X{ X Firm_event *event; X Firm_event *levent = NULL; X int numevents; X char etype; X char mtype; X char *format; X X event = (Firm_event *)bufptr; X numevents = bufsize / (sizeof(Firm_event)); X X if( fd == moufd ) X etype = 'm'; X else X etype = 'k'; X X fprintf(savefd,"%c%d", etype, numevents); X X /* check for first time event, set base time */ X if( timestart == 0 ) X timestart = event->time.tv_sec; X X while( numevents-- > 0 ) { X X /* we do different event formats for mouse and keyboard */ X /* in order to minimize size of output file.. */ X X if( etype == 'm' ) { X X /* these are the only ones I have seen generated.. */ X switch( event->id ) { X case LOC_X_DELTA: X mtype = 'X'; X break; X case LOC_Y_DELTA: X mtype = 'Y'; X break; X case MS_LEFT: X mtype = 'L'; X break; X case MS_MIDDLE: X mtype = 'M'; X break; X case MS_RIGHT: X mtype = 'R'; X break; X } X X /* surpress redundant time values by setting to zero */ X if( levent != NULL && X TVTOMILLI(event->time) == TVTOMILLI(levent->time) ) X format = "_%c'%d:0/0"; X else X format = "_%c'%d:%x/%x"; X X fprintf(savefd, format, X mtype, event->value, X event->time.tv_sec - timestart, X event->time.tv_usec ); X } X else { X X /* surpress redundant time values by setting to zero */ X if( levent != NULL && X TVTOMILLI(event->time) == TVTOMILLI(levent->time) ) X format = "_%d'%d:0/0"; X else X format = "_%d'%d:%x/%x"; X X fprintf(savefd, format, X event->id, event->value, X event->time.tv_sec - timestart, X event->time.tv_usec ); X X } X X /* save the last event, and get to the next */ X levent = event++; X } X X fprintf(savefd,"\n"); X} X X X/* X * this routine is used to check to see if the user has clicked X * the left mouse button during playback. If this is the case the X * playback is terminated. This is understood the next time we read. X * X * This Routine Is Currently Not Utilized Because The Read() Causes The X * Playback To Wait For Some User Event To Occur, Which Stops Everything. X */ Xstatic void Xcap_check_abort() X{ X Firm_event event; X int numbytes; X short gotleftclick = FALSE; X X /* read mouse events as long as we have them, left mouse terminates */ X numbytes = read( moufd, (char *)&event, sizeof(event) ); X X while( numbytes > 0 ) { X X if( event.id == MS_LEFT ) X gotleftclick = TRUE; X X numbytes = read( moufd, (char *)&event, sizeof(event) ); X } X X if( gotleftclick ) X cap_close_play(); X} X X X/* X * ==== Routines that are used for debugging ==== X * X * These are utilized if the DEBUG_FLAG is TRUE. X * X * Note that I don't care for #ifdefs for code.... X */ Xstatic void Xcap_init_debug() X{ X dbugfd = fopen( DEBUGFILE, "w" ); X X chmod( DEBUGFILE, actmask ); X X dbugact = (dbugfd != NULL); X X if( dbugact ) X cap_printf("**Initial debug entry**\n"); X} X Xstatic void Xcap_term_debug() X{ X if( dbugact ) { X cap_printf("**Final debug entry**\n"); X fclose(dbugfd); X dbugfd = NULL; X dbugact = FALSE; X X chmod( DEBUGFILE, passmask ); X } X} X Xstatic void Xcap_output_debug( fd ) Xint fd; X{ X Firm_event *event = locbuffer; X int numevents = eventcnt; X char etype; X char mtype; X X if( !dbugact ) X return; X X if( fd == moufd ) X etype = 'm'; X else X etype = 'k'; X X fprintf(dbugfd,"%c%d", etype, numevents); X X while( numevents-- > 0 ) { X X /* we do different event formats for mouse and keyboard */ X /* in order to minimize size of output file.. */ X X if( etype == 'm' ) { X X /* these are the only ones I have seen generated.. */ X switch( event->id ) { X case LOC_X_DELTA: X mtype = 'X'; X break; X case LOC_Y_DELTA: X mtype = 'Y'; X break; X case MS_LEFT: X mtype = 'L'; X break; X case MS_MIDDLE: X mtype = 'M'; X break; X case MS_RIGHT: X mtype = 'R'; X break; X } X X fprintf(dbugfd, "_%c'%d:%x/%x", X mtype, event->value, X event->time.tv_sec - timestart, X event->time.tv_usec ); X } X else { X X fprintf(dbugfd, "_%d'%d:%x/%x", X event->id, event->value, X event->time.tv_sec - timestart, X event->time.tv_usec ); X X } X X event++; X } X X fprintf(dbugfd,"\n"); X X fflush(dbugfd); X} X Xstatic void Xcap_printf( str, a,b,c,d ) Xchar *str; Xint a,b,c,d; X{ X if( dbugact ) { X fprintf(dbugfd, str, a,b,c,d ); X fflush(dbugfd); X } X} END_OF_FILE if test 14272 -ne `wc -c <'sunCapture.c'`; then echo shar: \"'sunCapture.c'\" unpacked with wrong size! fi # end of 'sunCapture.c' fi echo shar: End of shell archive. exit 0