forked from CleverRaven/Cataclysm-DDA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinput.h
971 lines (868 loc) · 37.2 KB
/
input.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
#pragma once
#ifndef CATA_SRC_INPUT_H
#define CATA_SRC_INPUT_H
#include <functional>
#include <iosfwd>
#include <map>
#include <set>
#include <string>
#include <vector>
#if defined(__ANDROID__)
#include <algorithm>
#include <list>
#endif
#include "point.h"
#include "translations.h"
enum action_id : int;
class hotkey_queue;
namespace cata
{
template<typename T>
class optional;
} // namespace cata
namespace catacurses
{
class window;
} // namespace catacurses
// Curses key constants
static constexpr int KEY_ESCAPE = 27;
static constexpr int KEY_MIN =
0x101; /* minimum extended key value */ //<---------not used
static constexpr int KEY_BREAK =
0x101; /* break key */ //<---------not used
static constexpr int KEY_DOWN = 0x102; /* down arrow */
static constexpr int KEY_UP = 0x103; /* up arrow */
static constexpr int KEY_LEFT = 0x104; /* left arrow */
static constexpr int KEY_RIGHT = 0x105; /* right arrow*/
static constexpr int KEY_HOME =
0x106; /* home key */
static constexpr int KEY_BACKSPACE =
0x107; /* Backspace */ //<---------not used
static constexpr int KEY_DC = 0x14A; /* Delete Character */
static constexpr int KEY_F0 = 0x108;
inline constexpr int KEY_F( const int n )
{
return KEY_F0 + n; /* F1, F2, etc*/
}
static constexpr int F_KEY_NUM_BEG = 0;
static constexpr int F_KEY_NUM_END = 63;
inline constexpr int F_KEY_NUM( const int key )
{
return key - KEY_F0;
}
inline constexpr bool IS_F_KEY( const int key )
{
return key >= KEY_F( F_KEY_NUM_BEG ) && key <= KEY_F( F_KEY_NUM_END );
}
/** @return true if the given character is in the range of basic ASCII control characters */
inline constexpr bool IS_CTRL_CHAR( const int key )
{
// https://en.wikipedia.org/wiki/C0_and_C1_control_codes#Basic_ASCII_control_codes
return key >= 0 && key < ' ';
}
/** @return true if the given character is an ASCII control char but should not be rendered with "CTRL+" */
inline constexpr bool IS_NAMED_CTRL_CHAR( const int key )
{
return key == '\t' || key == '\n' || key == KEY_ESCAPE || key == KEY_BACKSPACE;
}
inline constexpr int KEY_NUM( const int n )
{
return 0x30 + n; /* Numbers 0, 1, ..., 9 */
}
static constexpr int KEY_NPAGE = 0x152; /* page down */
static constexpr int KEY_PPAGE = 0x153; /* page up */
static constexpr int KEY_ENTER = 0x157; /* enter */
static constexpr int KEY_BTAB = 0x161; /* back-tab = shift + tab */
static constexpr int KEY_END = 0x168; /* End */
// Platform independent key code (though largely based on SDL key code)
//
// These and other code related to keyboard_code event should NOT be guarded with
// platform macros, since they are required to load and save keyboard_code events,
// which should always be done regardless whether the platform supports it, otherwise
// custom keybindings might be lost when someone switches e.g. from tiles to curses
// and save the keybindings, and switches back to tiles later.
namespace keycode
{
enum : int {
backspace = 0x08,
tab = 0x09,
return_ = 0x0D,
escape = 0x1B,
space = 0x20,
f1 = 0x4000003A,
f2 = 0x4000003B,
f3 = 0x4000003C,
f4 = 0x4000003D,
f5 = 0x4000003E,
f6 = 0x4000003F,
f7 = 0x40000040,
f8 = 0x40000041,
f9 = 0x40000042,
f10 = 0x40000043,
f11 = 0x40000044,
f12 = 0x40000045,
home = 0x4000004A,
ppage = 0x4000004B,
end = 0x4000004D,
npage = 0x4000004E,
right = 0x4000004F,
left = 0x40000050,
down = 0x40000051,
up = 0x40000052,
kp_divide = 0x40000054,
kp_multiply = 0x40000055,
kp_minus = 0x40000056,
kp_plus = 0x40000057,
kp_enter = 0x40000058,
kp_1 = 0x40000059,
kp_2 = 0x4000005A,
kp_3 = 0x4000005B,
kp_4 = 0x4000005C,
kp_5 = 0x4000005D,
kp_6 = 0x4000005E,
kp_7 = 0x4000005F,
kp_8 = 0x40000060,
kp_9 = 0x40000061,
kp_0 = 0x40000062,
kp_period = 0x40000063,
f13 = 0x40000068,
f14 = 0x40000069,
f15 = 0x4000006A,
f16 = 0x4000006B,
f17 = 0x4000006C,
f18 = 0x4000006D,
f19 = 0x4000006E,
f20 = 0x4000006F,
f21 = 0x40000070,
f22 = 0x40000071,
f23 = 0x40000072,
f24 = 0x40000073,
};
} // namespace keycode
static constexpr int LEGEND_HEIGHT = 11;
static constexpr int BORDER_SPACE = 2;
bool is_mouse_enabled();
bool is_keycode_mode_supported();
std::string get_input_string_from_file( const std::string &fname = "input.txt" );
// Mouse buttons and movement input
enum class MouseInput : int {
LeftButtonPressed = 1,
LeftButtonReleased,
RightButtonPressed,
RightButtonReleased,
ScrollWheelUp,
ScrollWheelDown,
Move
};
enum class input_event_t : int {
error,
timeout,
// used on platforms with only character/text input, such as curses
keyboard_char,
// used on platforms with raw keycode input, such as non-android sdl
keyboard_code,
gamepad,
mouse
};
enum class keymod_t {
ctrl,
alt,
shift,
};
/**
* An instance of an input, like a keypress etc.
*
* Gamepad, mouse and keyboard keypresses will be represented as `int`.
* Whether a gamepad, mouse or keyboard was used can be checked using the
* `type` member.
*
*/
struct input_event {
input_event_t type;
std::set<keymod_t> modifiers; // Keys that need to be held down for
// this event to be activated.
std::vector<int> sequence; // The sequence of key or mouse events that
// triggers this event. For single-key
// events, simply make this of size 1.
point mouse_pos; // Mouse click co-ordinates, if applicable
// Actually entered text (if any), UTF-8 encoded, might be empty if
// the input is not UTF-8 or not even text.
std::string text;
std::string edit;
bool edit_refresh;
#if defined(__ANDROID__)
// Used exclusively by the quick shortcuts to determine how stale a shortcut is
int shortcut_last_used_action_counter = 0;
#endif
input_event() : edit_refresh( false ) {
type = input_event_t::error;
}
input_event( int s, input_event_t t )
: type( t ), edit_refresh( false ) {
sequence.push_back( s );
}
// overloaded function for a mouse input
// made for a cleaner code, to get rid of static_cast's from scoped enum to int
//
// Instead of:
//
// input_event( static_cast<int>( MouseInput::Move ), ... )
// input_event( static_cast<int>( MouseInput::LeftButtonPressed ), ... )
// input_event( static_cast<int>( MouseInput::RightButtonPressed ), ... )
//
// we now can just use
//
// input_event( MouseInput::Move, ... )
// input_event( MouseInput::LeftButtonPressed, ... )
// input_event( MouseInput::RightButtonPressed, ... )
//
input_event( const MouseInput s, input_event_t t )
: type( t ), edit_refresh( false ) {
sequence.push_back( static_cast<int>( s ) );
}
input_event( const std::set<keymod_t> &mod, int s, input_event_t t );
int get_first_input() const;
void add_input( const int input ) {
sequence.push_back( input );
}
// overloaded function for a mouse input
// made for a cleaner code, to get rid of static_cast's from scoped enum to int
//
// Instead of:
//
// add_input( static_cast<int>( MouseInput::Move ) )
// add_input( static_cast<int>( MouseInput::LeftButtonPressed ) )
// add_input( static_cast<int>( MouseInput::RightButtonPressed ) )
//
// we now can just use
//
// add_input( MouseInput::Move )
// add_input( MouseInput::LeftButtonPressed )
// add_input( MouseInput::RightButtonPressed )
//
void add_input( const MouseInput mouse_input ) {
sequence.push_back( static_cast<int>( mouse_input ) );
}
bool operator==( const input_event &other ) const {
return type == other.type && modifiers == other.modifiers && sequence == other.sequence;
}
bool operator!=( const input_event &other ) const;
std::string long_description() const;
std::string short_description() const;
/**
* Lexicographical order considering input event type,
* modifiers, and key code sequence.
*/
static bool compare_type_mod_code( const input_event &lhs, const input_event &rhs );
};
/**
* A set of attributes for an action
*/
struct action_attributes {
action_attributes() : is_user_created( false ) {}
bool is_user_created;
translation name;
std::vector<input_event> input_events;
};
// Definitions for joystick/gamepad.
// On the joystick there's a maximum of 256 key states.
// So for joy axis events, we simply use a number larger
// than that.
constexpr int JOY_0 = 0;
constexpr int JOY_1 = 1;
constexpr int JOY_2 = 2;
constexpr int JOY_3 = 3;
constexpr int JOY_4 = 4;
constexpr int JOY_5 = 5;
constexpr int JOY_6 = 6;
constexpr int JOY_7 = 7;
constexpr int JOY_8 = 8;
constexpr int JOY_9 = 9;
constexpr int JOY_10 = 10;
constexpr int JOY_11 = 11;
constexpr int JOY_12 = 12;
constexpr int JOY_13 = 13;
constexpr int JOY_14 = 14;
constexpr int JOY_15 = 15;
constexpr int JOY_16 = 16;
constexpr int JOY_17 = 17;
constexpr int JOY_18 = 18;
constexpr int JOY_19 = 19;
constexpr int JOY_20 = 20;
constexpr int JOY_21 = 21;
constexpr int JOY_22 = 22;
constexpr int JOY_23 = 23;
constexpr int JOY_24 = 24;
constexpr int JOY_25 = 25;
constexpr int JOY_26 = 26;
constexpr int JOY_27 = 27;
constexpr int JOY_28 = 28;
constexpr int JOY_29 = 29;
constexpr int JOY_30 = 30;
constexpr int JOY_LEFT = 256 + 1;
constexpr int JOY_RIGHT = 256 + 2;
constexpr int JOY_UP = 256 + 3;
constexpr int JOY_DOWN = 256 + 4;
constexpr int JOY_RIGHTUP = 256 + 5;
constexpr int JOY_RIGHTDOWN = 256 + 6;
constexpr int JOY_LEFTUP = 256 + 7;
constexpr int JOY_LEFTDOWN = 256 + 8;
enum class keyboard_mode {
// Accept character input and text input. Input in this mode
// may be manipulated by the system via IMEs or dead keys.
keychar,
// Accept raw key code input. Text input is not available in this
// mode. All keyboard events are directly fed to the program
// in this mode, bypassing IMEs and dead keys. Only supported on
// some platforms, such as non-android SDL. On other platforms
// this falls back to `keychar` automatically.
keycode,
};
/**
* Manages the translation from action IDs to associated input.
*
* Planned methods of input:
* 1. Single key press: a
* 2. Multi-key combination: `a
* 3. Gamepad button: A
*/
class input_manager
{
public:
// TODO: rewrite this to have several alternative input events for the same action
/**
* Get the input events associated with an action ID in a given context.
*
* @param action_descriptor The action ID to get the input events for.
* @param context The context in which to get the input events. Defaults to "default".
* @param overwrites_default If this is non-NULL, this will be used as return parameter and will be set to true if the default
* keybinding is overridden by something else in the given context.
*/
const std::vector<input_event> &get_input_for_action( const std::string &action_descriptor,
const std::string &context = "default", bool *overwrites_default = nullptr );
/**
* Return first char associated with an action ID in a given context.
*/
int get_first_char_for_action( const std::string &action_descriptor,
const std::string &context = "default" );
/**
* Initializes the input manager, aka loads the input mapping configuration JSON.
*/
void init();
/**
* Opposite of @ref init, save the data that has been loaded by @ref init,
* and possibly been modified.
*/
void save();
/**
* Return the previously pressed key, or 0 if there is no previous input
* or the previous input wasn't a key.
*/
int get_previously_pressed_key() const;
/**
* Get the keycode associated with the given key name.
*/
int get_keycode( input_event_t inp_type, const std::string &name ) const;
/**
* Get the key name associated with the given keyboard keycode.
*
* @param ch Character code.
* @param inp_type Whether the keycode is a gamepad or a keyboard code.
* @param portable If true, return a language independent and portable name
* of the key. This acts as the inverse to get_keyname:
* <code>get_keyname(get_keycode(a), , true) == a</code>
*/
std::string get_keyname( int ch, input_event_t inp_type, bool portable = false ) const;
/**
* curses getch() replacement.
*
* Defined in the respective platform wrapper, e.g. sdlcurse.cpp
*/
input_event get_input_event( keyboard_mode preferred_keyboard_mode = keyboard_mode::keycode );
/**
* Resize & refresh if necessary, process all pending window events, and ignore keypresses
*/
void pump_events();
/**
* Wait until the user presses a key. Mouse and similar input is ignored,
* only input events from the keyboard are considered.
*/
void wait_for_any_key();
/**
* Sets global input polling timeout as appropriate for the current interface system.
* Use `input_context::(re)set_timeout()` when possible so timeout will be properly
* reset when entering a new input context.
*/
void set_timeout( int delay );
void reset_timeout() {
set_timeout( -1 );
}
int get_timeout() const {
return input_timeout;
}
static keyboard_mode actual_keyboard_mode( keyboard_mode preferred_keyboard_mode );
private:
friend class input_context;
using t_input_event_list = std::vector<input_event>;
using t_actions = std::map<std::string, action_attributes>;
using t_action_contexts = std::map<std::string, t_actions>;
t_action_contexts action_contexts;
using t_key_to_name_map = std::map<int, std::string>;
t_key_to_name_map keyboard_char_keycode_to_keyname;
t_key_to_name_map keyboard_code_keycode_to_keyname;
t_key_to_name_map gamepad_keycode_to_keyname;
t_key_to_name_map mouse_keycode_to_keyname;
using t_name_to_key_map = std::map<std::string, int>;
t_name_to_key_map keyboard_char_keyname_to_keycode;
t_name_to_key_map keyboard_code_keyname_to_keycode;
t_name_to_key_map gamepad_keyname_to_keycode;
t_name_to_key_map mouse_keyname_to_keycode;
// See @ref get_previously_pressed_key
int previously_pressed_key;
// Maps the key names we see in keybindings.json and in-game to
// the keycode integers.
void init_keycode_mapping();
void add_keyboard_char_keycode_pair( int ch, const std::string &name );
void add_keyboard_code_keycode_pair( int ch, const std::string &name );
void add_gamepad_keycode_pair( int ch, const std::string &name );
void add_mouse_keycode_pair( MouseInput mouse_input, const std::string &name );
/**
* Load keybindings from a json file, override existing bindings.
* Throws std::string on errors
*/
void load( const std::string &file_name, bool is_user_preferences );
int input_timeout;
t_input_event_list &get_or_create_event_list( const std::string &action_descriptor,
const std::string &context );
void remove_input_for_action( const std::string &action_descriptor, const std::string &context );
void add_input_for_action( const std::string &action_descriptor, const std::string &context,
const input_event &event );
/**
* Get the attributes of the action associated with an action ID by
* searching the given context and the default context.
*
* @param action_id The action ID of the action to find.
* @param context The context in which to get the action. If not found,
* the "default" context will additionally be checked.
* Defaults to "default".
* @param overwrites_default If this is non-NULL, this will be used as a
* return parameter. It will be set to true if
* the found action was not in the default
* context. It will be set to false if the found
* action was in the default context.
*/
const action_attributes &get_action_attributes(
const std::string &action_id,
const std::string &context = "default",
bool *overwrites_default = nullptr );
/**
* Get a value to be used as the default name for a newly created action.
* This name should be used as a fallback in cases where it is necessary
* to create a new action.
*
* @param action_id The action ID of the action.
*
* @return If the action ID exists in the default context, the name of
* that action's name is returned. Otherwise, no_translation( action_id ) is
* returned.
*/
translation get_default_action_name( const std::string &action_id ) const;
};
// Singleton for our input manager.
extern input_manager inp_mngr;
/**
* Represents a context in which a set of actions can be performed.
*
* This class is responsible for registering possible actions
* (traditionally keypresses), handling input, and yielding the correct
* action string descriptors for given input.
*
* This turns this class into an abstraction method between actual
* input(keyboard, gamepad etc.) and game.
*/
class input_context
{
public:
#if defined(__ANDROID__)
// Whatever's on top is our current input context.
static std::list<input_context *> input_context_stack;
#endif
input_context() : registered_any_input( false ), category( "default" ),
coordinate_input_received( false ), handling_coordinate_input( false ) {
#if defined(__ANDROID__)
input_context_stack.push_back( this );
allow_text_entry = false;
#endif
}
// TODO: consider making the curses WINDOW an argument to the constructor, so that mouse input
// outside that window can be ignored
explicit input_context( const std::string &category,
const keyboard_mode preferred_keyboard_mode = keyboard_mode::keycode )
: registered_any_input( false ), category( category ),
coordinate_input_received( false ), handling_coordinate_input( false ),
preferred_keyboard_mode( preferred_keyboard_mode ) {
#if defined(__ANDROID__)
input_context_stack.push_back( this );
allow_text_entry = false;
#endif
}
#if defined(__ANDROID__)
virtual ~input_context() {
input_context_stack.remove( this );
}
// HACK: hack to allow creating manual keybindings for getch() instances, uilists etc. that don't use an input_context outside of the Android version
struct manual_key {
manual_key( int _key, const std::string &_text ) : key( _key ), text( _text ) {}
int key;
std::string text;
bool operator==( const manual_key &other ) const {
return key == other.key && text == other.text;
}
};
std::vector<manual_key> registered_manual_keys;
// If true, prevent virtual keyboard from dismissing after a key press while this input context is active.
// NOTE: This won't auto-bring up the virtual keyboard, for that use sdltiles.cpp is_string_input()
bool allow_text_entry;
void register_manual_key( manual_key mk );
void register_manual_key( int key, const std::string text = "" );
std::string get_action_name_for_manual_key( int key ) {
for( const auto &manual_key : registered_manual_keys ) {
if( manual_key.key == key ) {
return manual_key.text;
}
}
return std::string();
}
std::vector<manual_key> &get_registered_manual_keys() {
return registered_manual_keys;
}
std::string &get_category() {
return category;
}
std::vector<std::string> &get_registered_actions() {
return registered_actions;
}
bool is_action_registered( const std::string &action_descriptor ) const {
return std::find( registered_actions.begin(), registered_actions.end(),
action_descriptor ) != registered_actions.end();
}
input_context &operator=( const input_context &other ) {
registered_actions = other.registered_actions;
registered_manual_keys = other.registered_manual_keys;
allow_text_entry = other.allow_text_entry;
registered_any_input = other.registered_any_input;
category = other.category;
coordinate = other.coordinate;
coordinate_input_received = other.coordinate_input_received;
handling_coordinate_input = other.handling_coordinate_input;
next_action = other.next_action;
iso_mode = other.iso_mode;
action_name_overrides = other.action_name_overrides;
timeout = other.timeout;
return *this;
}
bool operator==( const input_context &other ) const {
return category == other.category &&
registered_actions == other.registered_actions &&
registered_manual_keys == other.registered_manual_keys &&
allow_text_entry == other.allow_text_entry &&
registered_any_input == other.registered_any_input &&
coordinate == other.coordinate &&
coordinate_input_received == other.coordinate_input_received &&
handling_coordinate_input == other.handling_coordinate_input &&
next_action == other.next_action &&
iso_mode == other.iso_mode &&
action_name_overrides == other.action_name_overrides &&
timeout == other.timeout;
}
bool operator!=( const input_context &other ) const {
return !( *this == other );
}
#endif
/**
* Register an action with this input context.
*
* Only registered actions will be returned by `handle_input()`, it's
* thus possible to have multiple actions associated with the same keypress,
* as long as they don't ever occur in the same input context.
*
* If `action_descriptor` is the special "ANY_INPUT", instead of ignoring
* unregistered keys, those keys will all be linked to this "ANY_INPUT"
* action.
*
* If `action_descriptor` is the special "COORDINATE", coordinate input will be processed
* and the specified coordinates can be retrieved using `get_coordinates()`. Currently the
* only form of coordinate input is mouse input(you can directly click coordinates on
* the screen).
*
* @param action_descriptor String of action id.
*/
void register_action( const std::string &action_descriptor );
/**
* Same as other @ref register_action function but allows a context specific
* action name. The given name is displayed instead of the name taken from
* the @ref input_manager.
*
* @param action_descriptor String of action id.
* @param name Name of the action, displayed to the user. If empty use the
* name reported by the input_manager.
*/
void register_action( const std::string &action_descriptor, const translation &name );
/**
* Get the set of available single character keyboard keys that do not
* conflict with any registered hotkeys. The result will only include
* characters from the requested_keys parameter that have no conflicts
* i.e. the set difference requested_keys - conflicts.
*
* @param requested_keys The set of single character hotkeys to
* potentially use. Defaults to all printable ascii.
*
* @return Returns the set of non-conflicting, single character keyboard
* keys suitable for use as hotkeys.
*/
std::string get_available_single_char_hotkeys(
std::string requested_keys =
"abcdefghijkpqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=:;'\",./<>?!@#$%^&*()_+[]\\{}|`~" );
using input_event_filter = std::function<bool( const input_event & )>;
// Helper functions to be used as @ref input_event_filter
static bool disallow_lower_case_or_non_modified_letters( const input_event &evt );
static bool allow_all_keys( const input_event &evt );
/**
* Get a description text for the key/other input method associated
* with the given action. If there are multiple bound keys, no more
* than max_limit will be described in the result. In addition, only
* keys satisfying evt_filter will be described.
*
* @param action_descriptor The action descriptor for which to return
* a description of the bound keys.
*
* @param max_limit No more than max_limit bound keys will be
* described in the returned description. A value of
* 0 indicates no limit.
*
* @param evt_filter Only keys satisfying this function will be
* described.
*/
std::string get_desc( const std::string &action_descriptor,
unsigned int max_limit = 0,
const input_event_filter &evt_filter = allow_all_keys ) const;
/**
* Get a description based on `text`. If a bound key for `action_descriptor`
* satisfying `evt_filter` is contained in `text`, surround the key with
* brackets and change the case if necessary (e.g. "(Y)es"). Otherwise
* prefix `text` with description of the first bound key satisfying
* `evt_filter`, surrounded in square brackets (e.g "[RETURN] Yes").
*
* @param action_descriptor The action descriptor for which to return
* a description of the bound keys.
*
* @param text The base text for action description
*
* @param evt_filter Only keys satisfying this function will be considered
* @param inline_fmt Action description format when a key is found in the
* text (for example "(a)ctive")
* @param separate_fmt Action description format when a key is not found
* in the text (for example "[X] active" or "[N/A] active")
*/
std::string get_desc( const std::string &action_descriptor,
const std::string &text,
const input_event_filter &evt_filter,
const translation &inline_fmt,
const translation &separate_fmt ) const;
std::string get_desc( const std::string &action_descriptor,
const std::string &text,
const input_event_filter &evt_filter = allow_all_keys ) const;
/**
* Equivalent to get_desc( act, get_action_name( act ), filter )
**/
std::string describe_key_and_name( const std::string &action_descriptor,
const input_event_filter &evt_filter = allow_all_keys ) const;
/**
* Handles input and returns the next action in the queue.
*
* This internally calls getch() or whatever other input method
* is available(e.g. gamepad).
*
* If the action is mouse input, returns "MOUSE".
*
* @return One of the input actions formerly registered with
* `register_action()`, or "ERROR" if an error happened.
*
*/
const std::string &handle_input();
const std::string &handle_input( int timeout );
/**
* Convert a direction action (UP, DOWN etc) to a delta vector.
*
* @return If the action is a movement action (UP, DOWN, ...),
* the delta vector associated with it. Otherwise returns an empty value.
* The returned vector will always have a z component of 0.
*/
cata::optional<tripoint> get_direction( const std::string &action ) const;
/**
* Get the coordinates associated with the last mouse click (if any).
*
* TODO: This right now is more or less specific to the map window,
* and returns the absolute map coordinate.
* Eventually this should be made more flexible.
*/
cata::optional<tripoint> get_coordinates( const catacurses::window &capture_win_ );
// Below here are shortcuts for registering common key combinations.
void register_directions();
void register_updown();
void register_leftright();
void register_cardinal();
/**
* Displays the possible actions in the current context and their
* keybindings.
* @param permit_execute_action If `true` the function allows the user to specify an action to execute
* @returns action_id of any action the user specified to execute, or ACTION_NULL if none
*/
action_id display_menu( bool permit_execute_action = false );
/**
* Temporary method to retrieve the raw input received, so that input_contexts
* can be used in screens where not all possible actions have been defined in
* keybindings.json yet.
*/
input_event get_raw_input();
/**
* Get coordinate of text level from mouse input, difference between this and get_coordinates is that one is getting pixel level coordinate.
*/
cata::optional<point> get_coordinates_text( const catacurses::window &capture_win ) const;
/**
* Get the human-readable name for an action.
*/
std::string get_action_name( const std::string &action_id ) const;
/* For the future, something like this might be nice:
* const std::string register_action(const std::string& action_descriptor, x, y, width, height);
* (x, y, width, height) would describe an area on the visible window that, if clicked, triggers the action.
*/
// (Press X (or Y)|Try) to Z
std::string press_x( const std::string &action_id ) const;
std::string press_x( const std::string &action_id, const std::string &key_bound,
const std::string &key_unbound ) const;
std::string press_x( const std::string &action_id, const std::string &key_bound_pre,
const std::string &key_bound_suf, const std::string &key_unbound ) const;
/**
* Keys (and only keys, other input types are not included) that
* trigger the given action.
* @param action_descriptor The action descriptor for which to get the bound keys.
* @param maximum_modifier_count Maximum number of modifiers allowed for
* the returned action. <0 means any number is allowed.
* @param restrict_to_printable If `true`, the function returns the bound
* keys only if they are printable (space counts as non-printable
* here). If `false`, all keys (whether they are printable or not)
* are returned.
* @param restrict_to_keyboard If `true`, the function returns the bound keys only
* if they are keyboard inputs. If `false`, all inputs, such as mouse
* inputs are included.
* @returns All keys bound to the given action descriptor.
*/
std::vector<input_event> keys_bound_to( const std::string &action_descriptor,
int maximum_modifier_count = -1,
bool restrict_to_printable = true,
bool restrict_to_keyboard = true ) const;
/**
* Get/Set edittext to display IME unspecified string.
*/
void set_edittext( const std::string &s );
std::string get_edittext();
void set_iso( bool mode = true );
/**
* Sets input polling timeout as appropriate for the current interface system.
* Use this method to set timeouts when using input_context, rather than calling
* the old timeout() method or using input_manager::(re)set_timeout, as using
* this method will cause input_event_t::timeout events to be generated correctly,
* and will reset timeout correctly when a new input context is entered.
*/
void set_timeout( int val );
void reset_timeout();
input_event first_unassigned_hotkey( const hotkey_queue &queue ) const;
input_event next_unassigned_hotkey( const hotkey_queue &queue, const input_event &prev ) const;
private:
std::vector<std::string> registered_actions;
std::string edittext;
public:
const std::string &input_to_action( const input_event &inp ) const;
bool is_event_type_enabled( input_event_t type ) const;
bool is_registered_action( const std::string &action_name ) const;
private:
bool registered_any_input;
std::string category; // The input category this context uses.
point coordinate;
bool coordinate_input_received;
bool handling_coordinate_input;
input_event next_action;
bool iso_mode = false; // should this context follow the game's isometric settings?
int timeout = -1;
keyboard_mode preferred_keyboard_mode = keyboard_mode::keycode;
/**
* When registering for actions within an input_context, callers can
* specify a custom action name that will override the action's normal
* name. This map stores those overrides. The key is the action ID and the
* value is the user-visible name.
*/
std::map<std::string, translation> action_name_overrides;
/**
* Returns whether action uses the specified input
*/
bool action_uses_input( const std::string &action_id, const input_event &event ) const;
/**
* Return a user presentable list of actions that conflict with the
* proposed keybinding. Returns an empty string if nothing conflicts.
*/
std::string get_conflicts( const input_event &event, const std::string &ignore_action ) const;
/**
* Clear an input_event from all conflicting keybindings that are
* registered by this input_context.
*
* @param event The input event to be cleared from conflicting
* keybindings.
*/
void clear_conflicting_keybindings( const input_event &event );
/**
* Filter a vector of strings by a phrase, returning only strings that contain the phrase.
*
* @param strings The vector of strings to filter
* @param phrase The phrase to search within each of the given strings
* @return A vector of the filtered strings
*/
std::vector<std::string> filter_strings_by_phrase( const std::vector<std::string> &strings,
const std::string &phrase ) const;
};
/**
* Check whether a gamepad is plugged in/available.
*
* Always false in non-SDL versions.
*/
bool gamepad_available();
// rotate a delta direction clockwise
void rotate_direction_cw( int &dx, int &dy );
class hotkey_queue
{
public:
// ctxt is only used for determining hotkey input type
// use input_context::first_unassigned_hotkey() instead to skip assigned actions
input_event first( const input_context &ctxt ) const;
// use input_context::next_unassigned_hotkey() instead to skip assigned actions
input_event next( const input_event &prev ) const;
/**
* In keychar mode:
* a-z, A-Z
* In keycode mode:
* a-z, shift a-z
*/
static const hotkey_queue &alphabets();
/**
* In keychar mode:
* 1-0, a-z, A-Z
* In keycode mode:
* 1-0, a-z, shift 1-0, shift a-z
*/
static const hotkey_queue &alpha_digits();
private:
std::vector<int> codes_keychar;
std::vector<int> codes_keycode;
std::vector<std::set<keymod_t>> modifiers_keycode;
};
#endif // CATA_SRC_INPUT_H