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