OSDN Git Service

[Implement] 一週間以上前のデバッグログの自動削除
[hengband/hengband.git] / src / io / input-key-acceptor.c
1 #include "io/input-key-acceptor.h"
2 #include "cmd-io/macro-util.h"
3 #include "game-option/map-screen-options.h"
4 #include "game-option/input-options.h"
5 #include "io/signal-handlers.h"
6 #include "term/gameterm.h"
7 #include "util/string-processor.h"
8 #include "world/world.h"
9
10 bool inkey_base; /* See the "inkey()" function */
11 bool inkey_xtra; /* See the "inkey()" function */
12 bool inkey_scan; /* See the "inkey()" function */
13 bool inkey_flag; /* See the "inkey()" function */
14
15 int num_more = 0;
16
17 /*
18  * This special pointer allows a sequence of keys to be "inserted" into
19  * the stream of keys returned by "inkey()".  This key sequence will not
20  * trigger any macros, and cannot be bypassed by the Borg.  It is used
21  * in Angband to handle "keymaps".
22  */
23 concptr inkey_next = NULL;
24
25 /* Save macro trigger string for use in inkey_special() */
26 static char inkey_macro_trigger_string[1024];
27
28 /*
29  * Local variable -- we are inside a "macro action"
30  *
31  * Do not match any macros until "ascii 30" is found.
32  */
33 static bool parse_macro = FALSE;
34
35 /*
36  * Local variable -- we are inside a "macro trigger"
37  *
38  * Strip all keypresses until a low ascii value is found.
39  */
40 static bool parse_under = FALSE;
41
42 /*
43  * Cancel macro action on the queue
44  */
45 static void forget_macro_action(void)
46 {
47     if (!parse_macro)
48         return;
49
50     while (TRUE) {
51         char ch;
52         if (term_inkey(&ch, FALSE, TRUE))
53             break;
54         if (ch == 0)
55             break;
56         if (ch == 30)
57             break;
58     }
59
60     parse_macro = FALSE;
61 }
62
63 /*
64  * Helper function called only from "inkey()"
65  *
66  * This function does almost all of the "macro" processing.
67  *
68  * We use the "term_key_push()" function to handle "failed" macros, as well
69  * as "extra" keys read in while choosing the proper macro, and also to hold
70  * the action for the macro, plus a special "ascii 30" character indicating
71  * that any macro action in progress is complete.  Embedded macros are thus
72  * illegal, unless a macro action includes an explicit "ascii 30" character,
73  * which would probably be a massive hack, and might break things.
74  *
75  * Only 500 (0+1+2+...+29+30) milliseconds may elapse between each key in
76  * the macro trigger sequence.  If a key sequence forms the "prefix" of a
77  * macro trigger, 500 milliseconds must pass before the key sequence is
78  * known not to be that macro trigger.
79  */
80 static char inkey_aux(void)
81 {
82     int k = 0, n, p = 0, w = 0;
83     char ch;
84     char *buf = inkey_macro_trigger_string;
85
86     num_more = 0;
87
88     if (parse_macro) {
89         if (term_inkey(&ch, FALSE, TRUE)) {
90             parse_macro = FALSE;
91         }
92     } else {
93         (void)(term_inkey(&ch, TRUE, TRUE));
94     }
95
96     if (ch == 30)
97         parse_macro = FALSE;
98
99     if (ch == 30)
100         return (ch);
101     if (parse_macro)
102         return (ch);
103     if (parse_under)
104         return (ch);
105
106     buf[p++] = ch;
107     buf[p] = '\0';
108     k = macro_find_check(buf);
109     if (k < 0)
110         return (ch);
111
112     while (TRUE) {
113         k = macro_find_maybe(buf);
114
115         if (k < 0)
116             break;
117
118         if (0 == term_inkey(&ch, FALSE, TRUE)) {
119             buf[p++] = ch;
120             buf[p] = '\0';
121             w = 0;
122         } else {
123             w += 1;
124             if (w >= 10)
125                 break;
126
127             term_xtra(TERM_XTRA_DELAY, w);
128         }
129     }
130
131     k = macro_find_ready(buf);
132     if (k < 0) {
133         while (p > 0) {
134             if (term_key_push(buf[--p]))
135                 return 0;
136         }
137
138         (void)term_inkey(&ch, TRUE, TRUE);
139         return (ch);
140     }
141
142     concptr pat = macro__pat[k];
143     n = strlen(pat);
144     while (p > n) {
145         if (term_key_push(buf[--p]))
146             return 0;
147     }
148
149     parse_macro = TRUE;
150     if (term_key_push(30))
151         return 0;
152
153     concptr act = macro__act[k];
154
155     n = strlen(act);
156     while (n > 0) {
157         if (term_key_push(act[--n]))
158             return 0;
159     }
160
161     return 0;
162 }
163
164 /*
165  * @brief キー入力を受け付けるメインルーチン / Get a keypress from the user.
166  * @param なし
167  * return キーを表すコード
168  */
169 char inkey(void)
170 {
171     char ch = 0;
172     bool done = FALSE;
173     term_type *old = Term;
174
175     if (inkey_next && *inkey_next && !inkey_xtra) {
176         ch = *inkey_next++;
177         inkey_base = inkey_xtra = inkey_flag = inkey_scan = FALSE;
178         return (ch);
179     }
180
181     inkey_next = NULL;
182     if (inkey_xtra) {
183         parse_macro = FALSE;
184         parse_under = FALSE;
185         term_flush();
186     }
187
188     int v;
189     (void)term_get_cursor(&v);
190
191     /* Show the cursor if waiting, except sometimes in "command" mode */
192     if (!inkey_scan && (!inkey_flag || hilite_player || current_world_ptr->character_icky)) {
193         (void)term_set_cursor(1);
194     }
195
196     term_activate(angband_term[0]);
197     char kk;
198     while (!ch) {
199         if (!inkey_base && inkey_scan && (0 != term_inkey(&kk, FALSE, FALSE))) {
200             break;
201         }
202
203         if (!done && (0 != term_inkey(&kk, FALSE, FALSE))) {
204             term_activate(old);
205             term_fresh();
206             term_activate(angband_term[0]);
207             current_world_ptr->character_saved = FALSE;
208
209             signal_count = 0;
210             done = TRUE;
211         }
212
213         if (inkey_base) {
214             int w = 0;
215             if (!inkey_scan) {
216                 if (0 == term_inkey(&ch, TRUE, TRUE)) {
217                     break;
218                 }
219
220                 break;
221             }
222
223             while (TRUE) {
224                 if (0 == term_inkey(&ch, FALSE, TRUE)) {
225                     break;
226                 } else {
227                     w += 10;
228                     if (w >= 100)
229                         break;
230
231                     term_xtra(TERM_XTRA_DELAY, w);
232                 }
233             }
234
235             break;
236         }
237
238         ch = inkey_aux();
239         if (ch == 29) {
240             ch = 0;
241             continue;
242         }
243
244         if (parse_under && (ch <= 32)) {
245             ch = 0;
246             parse_under = FALSE;
247         }
248
249         if (ch == 30) {
250             ch = 0;
251         } else if (ch == 31) {
252             ch = 0;
253             parse_under = TRUE;
254         } else if (parse_under) {
255             ch = 0;
256         }
257     }
258
259     term_activate(old);
260     term_set_cursor(v);
261     inkey_base = inkey_xtra = inkey_flag = inkey_scan = FALSE;
262     return (ch);
263 }
264
265 /*
266  * Get a keypress from the user.
267  * And interpret special keys as internal code.
268  *
269  * This function is a Mega-Hack and depend on pref-xxx.prf's.
270  * Currently works on Linux(UNIX), Windows, and Macintosh only.
271  */
272 int inkey_special(bool numpad_cursor)
273 {
274     static const struct {
275         concptr keyname;
276         int keyflag;
277     } modifier_key_list[] = {
278         { "shift-", SKEY_MOD_SHIFT },
279         { "control-", SKEY_MOD_CONTROL },
280         { NULL, 0 },
281     };
282
283     static const struct {
284         bool numpad;
285         concptr keyname;
286         int keycode;
287     } special_key_list[] = {
288         { FALSE, "Down]", SKEY_DOWN },
289         { FALSE, "Left]", SKEY_LEFT },
290         { FALSE, "Right]", SKEY_RIGHT },
291         { FALSE, "Up]", SKEY_UP },
292         { FALSE, "Page_Up]", SKEY_PGUP },
293         { FALSE, "Page_Down]", SKEY_PGDOWN },
294         { FALSE, "Home]", SKEY_TOP },
295         { FALSE, "End]", SKEY_BOTTOM },
296         { TRUE, "KP_Down]", SKEY_DOWN },
297         { TRUE, "KP_Left]", SKEY_LEFT },
298         { TRUE, "KP_Right]", SKEY_RIGHT },
299         { TRUE, "KP_Up]", SKEY_UP },
300         { TRUE, "KP_Page_Up]", SKEY_PGUP },
301         { TRUE, "KP_Page_Down]", SKEY_PGDOWN },
302         { TRUE, "KP_Home]", SKEY_TOP },
303         { TRUE, "KP_End]", SKEY_BOTTOM },
304         { TRUE, "KP_2]", SKEY_DOWN },
305         { TRUE, "KP_4]", SKEY_LEFT },
306         { TRUE, "KP_6]", SKEY_RIGHT },
307         { TRUE, "KP_8]", SKEY_UP },
308         { TRUE, "KP_9]", SKEY_PGUP },
309         { TRUE, "KP_3]", SKEY_PGDOWN },
310         { TRUE, "KP_7]", SKEY_TOP },
311         { TRUE, "KP_1]", SKEY_BOTTOM },
312         { FALSE, NULL, 0 },
313     };
314
315     static const struct {
316         concptr keyname;
317         int keycode;
318     } gcu_special_key_list[] = {
319         { "A", SKEY_UP },
320         { "B", SKEY_DOWN },
321         { "C", SKEY_RIGHT },
322         { "D", SKEY_LEFT },
323         { "1~", SKEY_TOP },
324         { "4~", SKEY_BOTTOM },
325         { "5~", SKEY_PGUP },
326         { "6~", SKEY_PGDOWN },
327         { NULL, 0 },
328     };
329
330     char buf[1024];
331     concptr str = buf;
332     char key;
333     int skey = 0;
334     int modifier = 0;
335     int i;
336     size_t trig_len;
337
338     /*
339      * Forget macro trigger ----
340      * It's important if we are already expanding macro action
341      */
342     inkey_macro_trigger_string[0] = '\0';
343
344     key = inkey();
345     trig_len = strlen(inkey_macro_trigger_string);
346     if (!trig_len)
347         return (int)((unsigned char)key);
348     if (trig_len == 1 && parse_macro) {
349         char c = inkey_macro_trigger_string[0];
350         forget_macro_action();
351         return (int)((unsigned char)c);
352     }
353
354     ascii_to_text(buf, inkey_macro_trigger_string);
355     if (prefix(str, "\\[")) {
356         str += 2;
357         while (TRUE) {
358             for (i = 0; modifier_key_list[i].keyname; i++) {
359                 if (prefix(str, modifier_key_list[i].keyname)) {
360                     str += strlen(modifier_key_list[i].keyname);
361                     modifier |= modifier_key_list[i].keyflag;
362                 }
363             }
364
365             if (!modifier_key_list[i].keyname)
366                 break;
367         }
368
369         if (!numpad_as_cursorkey)
370             numpad_cursor = FALSE;
371
372         for (i = 0; special_key_list[i].keyname; i++) {
373             if ((!special_key_list[i].numpad || numpad_cursor) && streq(str, special_key_list[i].keyname)) {
374                 skey = special_key_list[i].keycode;
375                 break;
376             }
377         }
378
379         if (skey) {
380             forget_macro_action();
381             return (skey | modifier);
382         }
383     }
384
385     if (prefix(str, "\\e[")) {
386         str += 3;
387
388         for (i = 0; gcu_special_key_list[i].keyname; i++) {
389             if (streq(str, gcu_special_key_list[i].keyname)) {
390                 return gcu_special_key_list[i].keycode;
391             }
392         }
393     }
394
395     inkey_macro_trigger_string[0] = '\0';
396     return (int)((unsigned char)key);
397 }