1 /***************************************************************************
2 SCED - Schematic Capture Editor
3 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
4 Copyright 1990 Regents of the University of California.  All rights reserved.
5 Authors: 1981 Giles C. Billingsley  (parts of KIC layout editor)
6          1992 Stephen R. Whiteley
7 ****************************************************************************/
8 
9 /*
10  * SCED graphical and keyboard input.
11  */
12 
13 #include "spice.h"
14 #include "sced.h"
15 #include "scedmacs.h"
16 
17 
18 #ifdef __STDC__
19 static void new_fine_window(long,long,long,long);
20 static int  control_at(long,long);
21 static unsigned long actiontime(void);
22 static void point_input(long*,long*,char*,int*);
23 #else
24 static void new_fine_window();
25 static int  control_at();
26 static unsigned long actiontime();
27 static void point_input();
28 #endif
29 
30 #define DEBOUNCETIME 100
31 
32 /* button1: basic point operation
33  * button2: pan operation
34  * button3: window operation
35  * button4: return coords, no operation
36  */
37 
38 #define BUTTON1 1
39 #define BUTTON2 2
40 #define BUTTON3 4
41 #define BUTTON4 8
42 
43 /* Point() command characters */
44 #define ESC 27
45 #define BSP '\b'
46 #define DEL 127
47 #define NEWL 13
48 #define SPA  32
49 #define CTRL_A 1
50 #define CTRL_F 6
51 #define CTRL_G 7
52 #define CTRL_N 14
53 #define CTRL_T 20
54 #define CTRL_U 21
55 #define CTRL_V 22
56 #define CTRL_X 24
57 
58 static int OldButton3;  /* remember last button 3 */
59 static long OldButton3X,OldButton3Y;
60 
61 /* we keep track of the time between pointing events to debounce the cursor */
62 static unsigned long LastPointTime = 0;
63 
64 /* disable screen modifying functions such as scaling, pan. */
65 int LockOut;
66 
67 /* return from Point() if esc entered */
68 static int EscReturn;
69 
70 
71 void
Point()72 Point()
73 
74 {
75     /*
76      * When user has typed Condition, do Action.
77      *
78      * Condition
79      *     shortest unique prefix of Menu
80      * Action
81      *     Return with command selected stored in Parameters.kpCommand.
82      *
83      * Condition
84      *     ESC
85      * Action
86      *     Forget remembered type in, return if EscReturn == True.
87      *
88      * Condition
89      *     ctrl-a
90      * Action
91      *     Execute abort routine.
92      *
93      * Condition
94      *     point key or tablet stylus button Z
95      * Action
96      *     If user is pointing at a layer in the layer table viewport,
97      *     change the current layer.
98      *     If user is pointing at a command menu selection, return with
99      *     command selected stored as Parameters.kpCommand.
100      *     If user is pointing inside a layout viewport--coarse or fine--
101      *     return with Parameters.kpCommand[0] == EOS and cursor
102      *     descriptor up-to-date.
103      *
104      * Condition
105      *     ctrl-f or tablet stylus button 1
106      * Action
107      *     Wait for user to point.
108      *     Redisplay in fine viewport around where he pointed
109      *     if fine positioning is enabled, or pan otherwise.
110      *
111      * Condition
112      *     ctrl-g
113      * Action
114      *     Change scale of magnifying glass, or otherwise window, using
115      *     next two point actions.
116      *
117      * Condition
118      *     ctrl-n
119      * Action
120      *     Save the present view context in a list.
121      *
122      * Condition
123      *     ctrl-t or ctrl-v
124      * Action
125      *     Toggle position of magnifying glass, bottom or right.
126      *
127      */
128     char *TypeIn;
129     MENU *Menu;
130     unsigned long newtime;
131     int NumCommand,Buttons,Int1,Int2,Int3;
132     int Layer;
133     long X,Y,centerX,centerY;
134     char Key;
135     extern char *MenuABORT;
136 
137     /*
138      * The best way to handle interrupts reliably is to
139      * initialize the service routines as frequently as
140      * possible.  Therefore, . . .
141      */
142     InitSignals();
143     Menu = GetCurrentMenu();
144     Parameters.kpCommand[NumCommand = 0] = EOS;
145     Parameters.kpPointCoarseWindow = False;
146     if (OldButton3) {
147         OldButton3 = False;
148         FBSetRubberBanding(0);
149     }
150     LastPointTime = actiontime();
151 
152     loop {
153         loop {
154             point_input(&X,&Y,&Key,&Buttons);
155 
156             if (Key)
157                 break;
158 
159             if ((Buttons == BUTTON1 Or
160                 Buttons == BUTTON2 Or
161                 Buttons == BUTTON3 Or
162                 Buttons == BUTTON4) And
163                 (X < gi_maxx And X > 0 And Y < gi_maxy And Y > 0))
164                 break;
165 
166         }
167 
168         newtime = actiontime();
169         if (newtime > LastPointTime && newtime - LastPointTime < DEBOUNCETIME)
170             continue;
171         LastPointTime = newtime;
172 
173         switch (Key) {
174 
175             case 0:
176                 break;
177 
178             case BSP:
179             case DEL:
180                 if (NumCommand) NumCommand--;
181                 Parameters.kpCommand[NumCommand] = EOS;
182                 continue;
183 
184             case ESC:
185                 Parameters.kpCommand[NumCommand = 0] = EOS;
186                 /* SRW ** so we know if esc was entered */
187                 Parameters.kpCommand[1] = ESC;
188                 if (EscReturn) return;
189                 continue;
190 
191             case NEWL:
192                 Parameters.kpCommand[NumCommand = 0] = EOS;
193                 if (control_at(X,Y)) return;
194                 continue;
195 
196             case '!':
197                 /* shell command */
198                 if (LockOut) continue; /* ignore */
199                 ShowPrompt("! ");
200                 TypeIn = FBEdit(NULL);
201                 if (TypeIn != NULL)    {
202                     ShowProcess(TypeIn);
203                     ErasePrompt();
204                 }
205                 Parameters.kpCommand[NumCommand = 0] = EOS;
206                 continue;
207 
208             case CTRL_A:
209                 /* SRW ** abort gracefully */
210                 strcpy(Parameters.kpCommand,MenuABORT);
211                 NumCommand = 0;
212                 return;
213 
214             case CTRL_F:
215                 if (LockOut) continue;  /* ignore ^F */
216                 Parameters.kpCommand[NumCommand = 0] = EOS;
217                 SaveLastView();
218                 /* SRW ** pan if coarse viewport only */
219                 if (Parameters.kpRedisplayControl == COARSEVIEWPORTONLY) {
220                     if (!InBox(X,Y,View->kvCoarseViewport)) {
221                         NotPointingAtLayout();
222                         continue;
223                     }
224                     PToL(View->kvCoarseWindow,&X,&Y);
225                     InitCoarseWindow(X,Y,(long)View->kvCoarseWindow->kaWidth);
226                     InitFineWindow(X,Y);
227                     EraseLargeCoarseViewport();
228                     Redisplay(View->kvCoarseWindow);
229                 }
230                 else
231                     FinePosition(X,Y,Key);
232                 /*
233                  * This is necessary for debouncing.
234                  * It takes time to redisplay, so we set the time of the last
235                  * pointing event when the redisplay is finished.
236                  */
237                 LastPointTime = actiontime();
238                 continue;
239 
240             case CTRL_G:
241                 if (LockOut) continue; /* ignore ^G */
242                 Parameters.kpCommand[NumCommand = 0] = EOS;
243                 if (Parameters.kpCellName[0] == EOS)
244                     return;
245                 loop {
246                     ShowPrompt("Point to diagonal of area to be magnified.");
247                     point_input(&X,&Y,&Key,&Buttons);
248                     if (Key == ESC) goto skip;
249                     if (Buttons == BUTTON1) {
250                         if (InBox(X,Y,View->kvCoarseViewport))
251                             PToL(View->kvCoarseWindow,&X,&Y);
252                         elif (InBox(X,Y,View->kvFineViewport))
253                             PToL(View->kvFineWindow,&X,&Y);
254                         else {
255                             NotPointingAtLayout();
256                             continue;
257                         }
258                         OldButton3X = X;
259                         OldButton3Y = Y;
260                         FBSetRubberBanding('R');
261                         break;
262                     }
263                 }
264                 loop {
265                     ShowPrompt("Point to second endpoint.");
266                     point_input(&X,&Y,&Key,&Buttons);
267                     if (Key == ESC) {
268                         FBSetRubberBanding(0);
269                         goto skip;
270                     }
271                     if (Buttons == BUTTON1) {
272                         if (InBox(X,Y,View->kvCoarseViewport))
273                             PToL(View->kvCoarseWindow,&X,&Y);
274                         elif (InBox(X,Y,View->kvFineViewport))
275                             PToL(View->kvFineWindow,&X,&Y);
276                         else {
277                             NotPointingAtLayout();
278                             continue;
279                         }
280                         FBSetRubberBanding(0);
281                         break;
282                     }
283                 }
284                 new_fine_window(OldButton3X,OldButton3Y,X,Y);
285 skip:
286                 ErasePrompt();
287                 continue;
288 
289             case CTRL_N:
290                 Parameters.kpCommand[NumCommand = 0] = EOS;
291                 SaveViewOnStack();
292                 continue;
293 
294             case CTRL_U:
295             case CTRL_X:
296             case SPA:
297                 NumCommand = 0;
298                 Parameters.kpCommand[0] = EOS;
299                 continue;
300 
301             case CTRL_T:
302             case CTRL_V:
303                 if (LockOut) continue;  /* ignore */
304                 Parameters.kpCommand[NumCommand = 0] = EOS;
305                 View->kvFineViewportOnBottom ^= 1;
306                 InitViewport();
307                 if (Parameters.kpRedisplayControl == COARSEVIEWPORTONLY)
308                     continue;
309                 SetPositioning();
310                 EraseLargeCoarseViewport();
311                 Redisplay(View->kvCoarseWindow);
312                 continue;
313 
314             default:
315                 Parameters.kpCommand[NumCommand++] = Key;
316                 if (NumCommand > 80) NumCommand = 80;
317                 Parameters.kpCommand[NumCommand] = EOS;
318                 /*
319                  * Test for shortest unique prefix, or prefix matching upper
320                  * case part of menu.  Stupid search is plenty fast.
321                  */
322                 Int3 = -1;
323                 Int2 = 0;
324                 for (Int1 = 0; Menu[Int1].mEntry != NULL; Int1++) {
325                     for (Int2 = 0; Int2 < NumCommand; Int2++) {
326                         char c = Menu[Int1].mPrefix[Int2];
327                         if (isupper(c)) c = tolower(c);
328                         if (Parameters.kpCommand[Int2] != c) break;
329                     }
330                     if (Parameters.kpCommand[Int2] == EOS And Int2 > 0) {
331                         if (!Menu[Int1].mPrefix[Int2]) {
332                             /* found a match */
333                             if (Int3 >= 0) {
334                                 /* oops, more than 1 match */
335                                 Int2 = -1;
336                                 break;
337                             }
338                             Int3 = Int1;
339                         }
340                     }
341                 }
342                 if (Int3 >= 0 && Int2 >= 0) {
343                     strcpy(Parameters.kpCommand,Menu[Int3].mEntry);
344                     return;
345                 }
346                 continue;
347         }
348         NumCommand = 0;
349         if (ButtonPress(Buttons,X,Y))
350             return;
351     }
352 }
353 
354 
355 int
ButtonPress(Buttons,X,Y)356 ButtonPress(Buttons,X,Y)
357 
358 int Buttons;
359 long X,Y;
360 {
361 
362     Parameters.kpCommand[0] = EOS;
363     if (Buttons == 0) {
364         /* shouldn't get here unless null from keyboard */
365         return (False);
366     }
367     if (Buttons == BUTTON1) {
368         if (control_at(X,Y)) return (True);
369         return (False);
370     }
371     if (Buttons == BUTTON2) {
372         if (LockOut) {              /* treat like button 0 */
373             Buttons = BUTTON1;
374             if (control_at(X,Y)) return (True);
375             return (False);
376         }
377         SaveLastView();
378         /* pan if coarse viewport only */
379         if (Parameters.kpRedisplayControl == COARSEVIEWPORTONLY) {
380             if (!InBox(X,Y,View->kvCoarseViewport)) {
381                 return (False);
382             }
383             PToL(View->kvCoarseWindow,&X,&Y);
384             InitCoarseWindow(X,Y,(long)View->kvCoarseWindow->kaWidth);
385             InitFineWindow(X,Y);
386             EraseLargeCoarseViewport();
387             Redisplay(View->kvCoarseWindow);
388         }
389         else
390             FinePosition(X,Y,(char)0);
391         LastPointTime = actiontime();
392         return (False);
393     }
394     if (Buttons == BUTTON3) {
395         if (Parameters.kpCellName[0] == EOS) return (False);
396         if (LockOut) {  /* treat like button 0 */
397             Buttons = BUTTON1;
398             if (control_at(X,Y)) return (True);
399             return (False);
400         }
401         if (Not OldButton3) {
402             if (InBox(X,Y,View->kvCoarseViewport))
403                 PToL(View->kvCoarseWindow,&X,&Y);
404             elif (InBox(X,Y,View->kvFineViewport))
405                 PToL(View->kvFineWindow,&X,&Y);
406             else {
407                 return (False);
408             }
409             OldButton3X = SCursor.kcRawX;
410             OldButton3Y = SCursor.kcRawY;
411             SCursor.kcRawX = X;
412             SCursor.kcRawY = Y;
413             FBSetRubberBanding('R');
414             SCursor.kcRawX = OldButton3X;
415             SCursor.kcRawY = OldButton3Y;
416             OldButton3X = X;
417             OldButton3Y = Y;
418             OldButton3 = True;
419         }
420         else {
421             if (InBox(X,Y,View->kvCoarseViewport))
422                 PToL(View->kvCoarseWindow,&X,&Y);
423             elif (InBox(X,Y,View->kvFineViewport))
424                 PToL(View->kvFineWindow,&X,&Y);
425             else {
426                 FBSetRubberBanding(0);
427                 return (False);
428             }
429             FBSetRubberBanding(0);
430             OldButton3 = False;
431             new_fine_window(OldButton3X,OldButton3Y,X,Y);
432         }
433         return (False);
434     }
435     if (Buttons == BUTTON4) {
436         return (False);
437     }
438     return (False);
439 }
440 
441 
442 static void
new_fine_window(OldX,OldY,X,Y)443 new_fine_window(OldX,OldY,X,Y)
444 
445 long OldX,OldY,X,Y;
446 {
447     long NewWindowWidth, Hei, Wid, Tmp, CenterX, CenterY;
448 
449     if (Parameters.kpRedisplayControl == COARSEVIEWPORTONLY) {
450 
451         SaveLastView();
452         Wid = X - OldX;
453         Hei = Y - OldY;
454         if (Wid < 0) Wid = -Wid;
455         if (Hei < 0) Hei = -Hei;
456         Tmp = Hei*
457             (View->kvCoarseViewport->kaWidth/
458             View->kvCoarseViewport->kaHeight);
459         NewWindowWidth = Max(Wid,Tmp);
460         if (NewWindowWidth <= 0)
461             NewWindowWidth = RESOLUTION;
462         Wid /= 2;
463         Hei /= 2;
464         InitCoarseWindow(Min(X,OldX)+Wid,
465             Min(Y,OldY)+Hei,NewWindowWidth);
466         InitFineWindow(Min(X,OldX)+Wid,
467             Min(Y,OldY)+Hei);
468         EraseLargeCoarseViewport();
469         Redisplay(View->kvCoarseWindow);
470     }
471     else {
472         if (X > OldX)
473             SwapInts(X,OldX);
474         if ((OldX - X) < 2) { /* two lambda minimum width */
475             ShowPrompt("Magnifying glass width too small.");
476             return;
477         }
478         SaveLastView();
479         if (Y > OldY)
480             SwapInts(Y,OldY);
481         CenterX = (OldX - X)/2 + X;
482         CenterY = (OldY - Y)/2 + Y;
483         View->kvFineWindow->kaWidth = OldX - X;
484         View->kvFineWindow->kaHeight =
485             View->kvFineWindow->kaWidth*
486             (View->kvFineViewport->kaHeight/
487             View->kvFineViewport->kaWidth);
488         EraseFineViewport();
489         InitFineWindow(CenterX,CenterY);
490         ShowFineViewport();
491     }
492 }
493 
494 
495 int
PointLoop(LookedAhead)496 PointLoop(LookedAhead)
497 
498 /* Loop until UNDO, a "non-safe" command, point to coarse window, or
499  * ESC is entered.  Return value used for dispatching in non-safe (i.e.,
500  * cell modifying) commands.
501  */
502 int *LookedAhead;
503 {
504     extern char *MenuUNDO;
505 
506     loop {
507         if (*LookedAhead == False) {
508             EscReturn = True;
509             Point();
510             EscReturn = False;
511         }
512         else
513             *LookedAhead = False;
514         if (Parameters.kpCommand[1] == ESC)
515             return (PL_ESC);
516         if (Parameters.kpCommand[0] != EOS) {
517             if (SafeCmds(LookedAhead))
518                 continue;
519             if (Matching(MenuUNDO)) return (PL_UND);
520             *LookedAhead = True;
521             return (PL_CMD);
522         }
523         if (Parameters.kpPointCoarseWindow)
524             return (PL_PCW);
525         NotPointingAtLayout();
526     }
527 }
528 
529 
530 int
PointLoopSafe(LookedAhead)531 PointLoopSafe(LookedAhead)
532 
533 /* Loop until UNDO, any  command, point to coarse window, or
534  * ESC is entered.  Return value used for dispatching in safe
535  * (i.e. non cell modifying) commands.
536  */
537 int *LookedAhead;
538 {
539 
540     loop {
541         EscReturn = True;
542         Point();
543         EscReturn = False;
544         if (Parameters.kpCommand[1] == ESC)
545             return (PL_ESC);
546         if (Parameters.kpCommand[0] != EOS) {
547             *LookedAhead = True;
548             return (PL_CMD);
549         }
550         if (Parameters.kpPointCoarseWindow)
551             return (PL_PCW);
552         NotPointingAtLayout();
553     }
554 }
555 
556 
557 int
PointColor(LookedAhead)558 PointColor(LookedAhead)
559 
560 /* Loop until UNDO, a non color setting command, point to coarse window, or
561  * ESC is entered.
562  */
563 int *LookedAhead;
564 {
565     extern char *MenuPLUSR,*MenuMINSR;
566     extern char *MenuPLUSG,*MenuMINSG;
567     extern char *MenuPLUSB,*MenuMINSB;
568     extern char *MenuRGB;
569     extern char *MenuUNDO;
570 
571     loop {
572         if (*LookedAhead == False) {
573             EscReturn = True;
574             Point();
575             EscReturn = False;
576         }
577         else
578             *LookedAhead = False;
579         if (Parameters.kpCommand[1] == ESC)
580             return (PL_ESC);
581         if (Parameters.kpCommand[0] != EOS) {
582 
583             if (Matching(MenuMINSB)) { AlterColor('b','-');  continue; }
584             if (Matching(MenuMINSG)) { AlterColor('g','-');  continue; }
585             if (Matching(MenuMINSR)) { AlterColor('r','-');  continue; }
586             if (Matching(MenuPLUSB)) { AlterColor('b','+');  continue; }
587             if (Matching(MenuPLUSG)) { AlterColor('g','+');  continue; }
588             if (Matching(MenuPLUSR)) { AlterColor('r','+');  continue; }
589             if (Matching(MenuRGB))   { RGB();                continue; }
590 
591             if (Matching(MenuUNDO))
592                 return (PL_UND);
593             *LookedAhead = True;
594             return (PL_CMD);
595         }
596         if (Parameters.kpPointCoarseWindow)
597             return (PL_PCW);
598         NotPointingAtLayout();
599     }
600 }
601 
602 
603 void
NotPointingAtLayout()604 NotPointingAtLayout()
605 
606 {
607     ShowPrompt("You aren't pointing in the layout viewport.");
608 }
609 
610 
611 void
FinePosition(X,Y,Key)612 FinePosition(X,Y,Key)
613 
614 long X,Y;
615 char Key;
616 {
617     int Buttons;
618 
619     if (Parameters.kpCellName[0] == EOS)
620         return;
621     if (Parameters.kpRedisplayControl == COARSEVIEWPORTONLY) {
622         ShowPrompt("Fine positioning isn't required.");
623         Parameters.kpCommand[0] = EOS;
624         return;
625     }
626     if (Key != EOS) {
627         ShowPrompt("Point to center of area you want magnified.");
628         loop {
629             point_input(&X,&Y,&Key,&Buttons);
630             if (Key == EOS Or Key == NEWL)
631                 break;
632         }
633     }
634     if (InBox(X,Y,View->kvCoarseViewport))
635         PToL(View->kvCoarseWindow,&X,&Y);
636     elif (InBox(X,Y,View->kvFineViewport))
637         PToL(View->kvFineWindow,&X,&Y);
638     else {
639         NotPointingAtLayout();
640         return;
641     }
642     EraseFineViewport();
643     InitFineWindow(X,Y);
644     ShowFineViewport();
645 }
646 
647 
648 static int
control_at(X,Y)649 control_at(X,Y)
650 
651 long X,Y;
652 {
653     int i, Row, Column;
654     MENU *Menu;
655     extern char *MenuPLACE;
656 
657     Parameters.kpPointCoarseWindow = False;
658     if (InBox(X,Y,View->kvCoarseViewport)) {
659         SCursor.kcInFine = False;
660         SCursor.kcPredX = SCursor.kcX;
661         SCursor.kcPredY = SCursor.kcY;
662         SCursor.kcX = X;
663         SCursor.kcY = Y;
664         SCursor.kcRawX = X;
665         SCursor.kcRawY = Y;
666         PToL(View->kvCoarseWindow,&SCursor.kcX,&SCursor.kcY);
667         PToL(View->kvCoarseWindow,&SCursor.kcRawX,&SCursor.kcRawY);
668         ClipToGridPoint(&SCursor.kcX,&SCursor.kcY);
669         SCursor.kcDX = SCursor.kcX-SCursor.kcPredX;
670         SCursor.kcDY = SCursor.kcY-SCursor.kcPredY;
671         Parameters.kpCommand[0] = '\0';
672         Parameters.kpPointCoarseWindow = True;
673         return (True);
674     }
675     if (InBox(X,Y,View->kvFineViewport)) {
676         SCursor.kcInFine = True;
677         SCursor.kcPredX = SCursor.kcX;
678         SCursor.kcPredY = SCursor.kcY;
679         SCursor.kcX = X;
680         SCursor.kcY = Y;
681         SCursor.kcRawX = X;
682         SCursor.kcRawY = Y;
683         PToL(View->kvFineWindow,&SCursor.kcX,&SCursor.kcY);
684         PToL(View->kvFineWindow,&SCursor.kcRawX,&SCursor.kcRawY);
685         ClipToGridPoint(&SCursor.kcX,&SCursor.kcY);
686         SCursor.kcDX = SCursor.kcX-SCursor.kcPredX;
687         SCursor.kcDY = SCursor.kcY-SCursor.kcPredY;
688         Parameters.kpCommand[0] = '\0';
689         Parameters.kpPointCoarseWindow = True;
690         return (True);
691     }
692     Menu = GetCurrentMenu();
693     Row = (gi_maxy-Y-3)/gi_fntheight+1;
694     Column = X/gi_fntwidth+1;
695     if (InBox((long)Column,(long)Row,&MenuViewport)) {
696         if (Column > 5)
697             Row += MenuViewport.kaY;
698         if (Menu == BasicMenu) {
699             for  (i = 0; ; i++)
700                 if (Menu[i].mEntry == NULL) break;
701 
702             if (i > Row - 1) {
703                 strcpy(Parameters.kpCommand,Menu[Row-1].mEntry);
704                 return (True);
705             }
706             if (Column <= 5)
707                 return (False);
708             if (i < MenuViewport.kaY)
709                 i = MenuViewport.kaY;
710             Row -= i;
711             for  (i = 0; ; i++)
712                 if (DeviceMenu[i].mEntry == NULL) break;
713             if (i > Row - 1) {
714                 /* hide the cell name after a null */
715                 sprintf(Parameters.kpCommand,"%s %s",MenuPLACE,
716                     DeviceMenu[Row-1].mEntry);
717                 Parameters.kpCommand[strlen(MenuPLACE)] = '\0';
718                 return (True);
719             }
720         }
721         else {
722             for  (i = 0; ; i++)
723                 if (Menu[i].mEntry == NULL) break;
724             if (i > Row - 1) {
725                 strcpy(Parameters.kpCommand,Menu[Row-1].mEntry);
726                 return (True);
727             }
728         }
729     }
730     return (False);
731 }
732 
733 
734 static unsigned long
actiontime()735 actiontime()
736 
737 {
738     return ((unsigned long)1000*seconds());
739 }
740 
741 
742 static void
point_input(x,y,key,but)743 point_input(x,y,key,but)
744 
745 long *x, *y;
746 char *key;
747 int *but;
748 {
749     REQUEST request;
750     RESPONSE response;
751 
752     request.option = point_option;
753     DevInput(&request,&response);
754     *x = response.x;
755     *y = response.y;
756     *key = 0;
757     *but = 0;
758     if (response.option == char_option) {
759         *key = (isupper(response.reply.ch) ?
760             tolower(response.reply.ch) : response.reply.ch);
761     }
762     else {
763         *but = response.reply.button;
764     }
765     return;
766 }
767