1 /* Getting and ungetting key strokes
2 
3    Copyright (c) 1997-2012 Free Software Foundation, Inc.
4 
5    This file is part of GNU Zile.
6 
7    GNU Zile is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11 
12    GNU Zile is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with GNU Zile; see the file COPYING.  If not, write to the
19    Free Software Foundation, Fifth Floor, 51 Franklin Street, Boston,
20    MA 02111-1301, USA.  */
21 
22 #include <config.h>
23 
24 #include <assert.h>
25 #include <sys/time.h>
26 
27 #include "main.h"
28 #include "extern.h"
29 
30 /* Maximum time to avoid screen updates when catching up with buffered
31    input, in milliseconds. */
32 #define MAX_RESYNC_MS 500
33 
34 /* These are not required for POSIX.1-2001, and not always defined in
35    the system headers. */
36 #ifndef timeradd
37 #  define timeradd(_a, _b, _result)				\
38    do {								\
39 	(_result)->tv_sec  = (_a)->tv_sec + (_b)->tv_sec;	\
40 	(_result)->tv_usec = (_a)->tv_usec + (_b)->tv_usec;	\
41 	if ((_result)->tv_usec > 1000000) {			\
42 	  ++(_result)->tv_sec;					\
43 	  (_result)->tv_usec -= 1000000;			\
44 	}							\
45    }                                                            \
46    while (0)
47 #endif
48 
49 #ifndef timercmp
50 #  define timercmp(_a, _b, _CMP)				\
51    (((_a)->tv_sec == (_b)->tv_sec)				\
52     ? ((_a)->tv_usec _CMP (_b)->tv_usec)			\
53     : ((_a)->tv_sec  _CMP (_b)->tv_sec))
54 #endif
55 
56 static size_t _last_key;
57 
58 /* Return last key pressed */
59 size_t
lastkey(void)60 lastkey (void)
61 {
62   return _last_key;
63 }
64 
65 /*
66  * Get a keystroke, waiting for up to delay ms, and translate it into
67  * a keycode.
68  */
69 size_t
getkeystroke(int delay)70 getkeystroke (int delay)
71 {
72   _last_key = term_getkey (delay);
73 
74   if (_last_key != KBD_NOKEY && (thisflag & FLAG_DEFINING_MACRO))
75     add_key_to_cmd (_last_key);
76 
77   return _last_key;
78 }
79 
80 /*
81  * Return the next keystroke, refreshing the screen only when the input
82  * buffer is empty, or MAX_RESYNC_MS have elapsed since the last
83  * screen refresh.
84  */
85 size_t
getkey(int delay)86 getkey (int delay)
87 {
88   static struct timeval next_refresh = { 0, 0 };
89   static struct timeval refresh_wait = {
90     MAX_RESYNC_MS / 1000, (MAX_RESYNC_MS % 1000) * 1000 };
91   static struct timeval now;
92   size_t keycode = getkeystroke (0);
93 
94   gettimeofday (&now, NULL);
95 
96   if (keycode == KBD_NOKEY || !timercmp (&now, &next_refresh, <))
97     {
98       term_redisplay ();
99       term_refresh ();
100       timeradd (&now, &refresh_wait, &next_refresh);
101     }
102 
103   if (keycode == KBD_NOKEY)
104     keycode = getkeystroke (delay);
105 
106   return keycode;
107 }
108 
109 size_t
getkey_unfiltered(int mode)110 getkey_unfiltered (int mode)
111 {
112   int key = term_getkey_unfiltered (mode);
113   assert (key >= 0);
114 
115   _last_key = (size_t) key;
116   if (thisflag & FLAG_DEFINING_MACRO)
117     add_key_to_cmd (key);
118 
119   return key;
120 }
121 
122 /*
123  * Wait for GETKEY_DELAYED ms or until a key is pressed.  The key is
124  * then available with [x]getkey.
125  */
126 void
waitkey(void)127 waitkey (void)
128 {
129   ungetkey (getkey (GETKEY_DELAYED));
130 }
131 
132 /*
133  * Push a key into the input buffer.
134  */
135 void
pushkey(size_t key)136 pushkey (size_t key)
137 {
138   term_ungetkey (key);
139 }
140 
141 /*
142  * Unget a key as if it had not been fetched.
143  */
ungetkey(size_t key)144 void ungetkey (size_t key)
145 {
146   pushkey (key);
147 
148   if (thisflag & FLAG_DEFINING_MACRO)
149     remove_key_from_cmd ();
150 }
151