OSDN Git Service

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