1 #include "io/input-key-acceptor.h"
2 #include "cmd-io/macro-util.h"
3 #include "core/stuff-handler.h"
4 #include "core/window-redrawer.h"
5 #include "game-option/input-options.h"
6 #include "game-option/map-screen-options.h"
7 #include "io/signal-handlers.h"
8 #include "system/player-type-definition.h"
9 #include "term/gameterm.h"
10 #include "util/string-processor.h"
11 #include "world/world.h"
13 bool inkey_base; /* See the "inkey()" function */
14 bool inkey_xtra; /* See the "inkey()" function */
15 bool inkey_scan; /* See the "inkey()" function */
16 bool inkey_flag; /* See the "inkey()" function */
21 * This special pointer allows a sequence of keys to be "inserted" into
22 * the stream of keys returned by "inkey()". This key sequence will not
23 * trigger any macros, and cannot be bypassed by the Borg. It is used
24 * in Angband to handle "keymaps".
26 concptr inkey_next = nullptr;
28 /* Save macro trigger string for use in inkey_special() */
29 static char inkey_macro_trigger_string[1024];
32 * Local variable -- we are inside a "macro action"
34 * Do not match any macros until "ascii 30" is found.
36 static bool parse_macro = false;
39 * Local variable -- we are inside a "macro trigger"
41 * Strip all keypresses until a low ascii value is found.
43 static bool parse_under = false;
46 * @brief 全てのウィンドウの再描画を行う
50 static void all_term_fresh()
53 term_activate(angband_terms[0]);
56 p_ptr->window_flags |= PW_ALL;
59 term_activate(angband_terms[0]);
65 * Cancel macro action on the queue
67 static void forget_macro_action(void)
75 if (term_inkey(&ch, false, true)) {
90 * Helper function called only from "inkey()"
92 * This function does almost all of the "macro" processing.
94 * We use the "term_key_push()" function to handle "failed" macros, as well
95 * as "extra" keys read in while choosing the proper macro, and also to hold
96 * the action for the macro, plus a special "ascii 30" character indicating
97 * that any macro action in progress is complete. Embedded macros are thus
98 * illegal, unless a macro action includes an explicit "ascii 30" character,
99 * which would probably be a massive hack, and might break things.
101 * Only 500 (0+1+2+...+29+30) milliseconds may elapse between each key in
102 * the macro trigger sequence. If a key sequence forms the "prefix" of a
103 * macro trigger, 500 milliseconds must pass before the key sequence is
104 * known not to be that macro trigger.
106 static char inkey_aux(void)
108 int k = 0, n, p = 0, w = 0;
110 char *buf = inkey_macro_trigger_string;
115 if (term_inkey(&ch, false, true)) {
119 (void)(term_inkey(&ch, true, true));
138 k = macro_find_check(buf);
144 k = macro_find_maybe(buf);
150 if (0 == term_inkey(&ch, false, true)) {
160 term_xtra(TERM_XTRA_DELAY, w);
164 k = macro_find_ready(buf);
167 if (term_key_push(buf[--p])) {
172 (void)term_inkey(&ch, true, true);
176 concptr pat = macro__pat[k].data();
179 if (term_key_push(buf[--p])) {
185 if (term_key_push(30)) {
189 concptr act = macro__act[k].data();
193 if (term_key_push(act[--n])) {
202 * @brief キー入力を受け付けるメインルーチン / Get a keypress from the user.
203 * @param do_all_term_refresh trueであれば強制的にhandle_stuffと再描画を行う。デフォルト false
206 char inkey(bool do_all_term_refresh)
210 term_type *old = game_term;
212 if (inkey_next && *inkey_next && !inkey_xtra) {
214 inkey_base = inkey_xtra = inkey_flag = inkey_scan = false;
218 inkey_next = nullptr;
226 (void)term_get_cursor(&v);
228 /* Show the cursor if waiting, except sometimes in "command" mode */
229 if (!inkey_scan && (!inkey_flag || hilite_player || w_ptr->character_icky_depth > 0)) {
230 (void)term_set_cursor(1);
233 term_activate(angband_terms[0]);
236 if (!inkey_base && inkey_scan && (0 != term_inkey(&kk, false, false))) {
240 if (!done && (0 != term_inkey(&kk, false, false))) {
242 if (do_all_term_refresh) {
247 w_ptr->character_saved = false;
256 if (0 == term_inkey(&ch, true, true)) {
264 if (0 == term_inkey(&ch, false, true)) {
272 term_xtra(TERM_XTRA_DELAY, w);
285 if (parse_under && (ch <= 32)) {
292 } else if (ch == 31) {
295 } else if (parse_under) {
302 inkey_base = inkey_xtra = inkey_flag = inkey_scan = false;
307 * Get a keypress from the user.
308 * And interpret special keys as internal code.
310 * This function is a Mega-Hack and depend on pref-xxx.prf's.
311 * Currently works on Linux(UNIX), Windows, and Macintosh only.
313 int inkey_special(bool numpad_cursor)
315 static const struct {
318 } modifier_key_list[] = {
319 { "shift-", SKEY_MOD_SHIFT },
320 { "control-", SKEY_MOD_CONTROL },
324 static const struct {
328 } special_key_list[] = {
329 { false, "Down]", SKEY_DOWN },
330 { false, "Left]", SKEY_LEFT },
331 { false, "Right]", SKEY_RIGHT },
332 { false, "Up]", SKEY_UP },
333 { false, "Page_Up]", SKEY_PGUP },
334 { false, "Page_Down]", SKEY_PGDOWN },
335 { false, "Home]", SKEY_TOP },
336 { false, "End]", SKEY_BOTTOM },
337 { true, "KP_Down]", SKEY_DOWN },
338 { true, "KP_Left]", SKEY_LEFT },
339 { true, "KP_Right]", SKEY_RIGHT },
340 { true, "KP_Up]", SKEY_UP },
341 { true, "KP_Page_Up]", SKEY_PGUP },
342 { true, "KP_Page_Down]", SKEY_PGDOWN },
343 { true, "KP_Home]", SKEY_TOP },
344 { true, "KP_End]", SKEY_BOTTOM },
345 { true, "KP_2]", SKEY_DOWN },
346 { true, "KP_4]", SKEY_LEFT },
347 { true, "KP_6]", SKEY_RIGHT },
348 { true, "KP_8]", SKEY_UP },
349 { true, "KP_9]", SKEY_PGUP },
350 { true, "KP_3]", SKEY_PGDOWN },
351 { true, "KP_7]", SKEY_TOP },
352 { true, "KP_1]", SKEY_BOTTOM },
353 { false, nullptr, 0 },
356 static const struct {
359 } gcu_special_key_list[] = {
365 { "4~", SKEY_BOTTOM },
367 { "6~", SKEY_PGDOWN },
380 * Forget macro trigger ----
381 * It's important if we are already expanding macro action
383 inkey_macro_trigger_string[0] = '\0';
386 trig_len = strlen(inkey_macro_trigger_string);
388 return (int)((unsigned char)key);
390 if (trig_len == 1 && parse_macro) {
391 char c = inkey_macro_trigger_string[0];
392 forget_macro_action();
393 return (int)((unsigned char)c);
396 ascii_to_text(buf, inkey_macro_trigger_string, sizeof(buf));
397 if (prefix(str, "\\[")) {
400 for (i = 0; modifier_key_list[i].keyname; i++) {
401 if (prefix(str, modifier_key_list[i].keyname)) {
402 str += strlen(modifier_key_list[i].keyname);
403 modifier |= modifier_key_list[i].keyflag;
407 if (!modifier_key_list[i].keyname) {
412 if (!numpad_as_cursorkey) {
413 numpad_cursor = false;
416 for (i = 0; special_key_list[i].keyname; i++) {
417 if ((!special_key_list[i].numpad || numpad_cursor) && streq(str, special_key_list[i].keyname)) {
418 skey = special_key_list[i].keycode;
424 forget_macro_action();
425 return (skey | modifier);
429 if (prefix(str, "\\e[")) {
432 for (i = 0; gcu_special_key_list[i].keyname; i++) {
433 if (streq(str, gcu_special_key_list[i].keyname)) {
434 return gcu_special_key_list[i].keycode;
439 inkey_macro_trigger_string[0] = '\0';
440 return (int)((unsigned char)key);
444 * @brief 全てのウィンドウの描画を止める
446 void stop_term_fresh(void)
448 for (auto &angband_term : angband_terms) {
449 if (angband_term != nullptr) {
450 angband_term->never_fresh = true;
456 * @brief 全てのウィンドウの描画を再開する
458 void start_term_fresh(void)
460 for (auto &angband_term : angband_terms) {
461 if (angband_term != nullptr) {
462 angband_term->never_fresh = false;
468 * @brief マクロ実行中かの判定関数
469 * @return 実行中であればtrue
471 bool macro_running(void)
473 /* マクロ展開中のみ詳細に判定する */
475 int diff = angband_terms[0]->key_head - angband_terms[0]->key_tail;
477 /* 最終入力を展開した直後はdiff==1となる */
482 /* 最終入力の処理中はまだtrueを返す */
483 if (inkey_next && *inkey_next && !inkey_xtra) {