1 /**
2 * @file
3 * @brief System independent console IO functions
4 **/
5
6 #pragma once
7
8 #include <cctype>
9 #include <string>
10 #include <vector>
11
12 #include "enum.h"
13 #include "KeymapContext.h"
14
15 #ifdef USE_TILE_LOCAL
16 #include "tilebuf.h"
17 #include <SDL_keycode.h>
18 #endif
19
20 enum keyfun_action
21 {
22 KEYFUN_PROCESS,
23 KEYFUN_IGNORE,
24 KEYFUN_CLEAR,
25 KEYFUN_BREAK,
26 };
27
28 class input_history
29 {
30 public:
31 input_history(size_t size);
32
33 void new_input(const string &s);
34 void clear();
35
36 const string *prev();
37 const string *next();
38
39 void go_end();
40 private:
41 typedef list<string> string_list;
42
43 string_list history;
44 string_list::iterator pos;
45 size_t maxsize;
46 };
47
48 void cursorxy(int x, int y);
cursorxy(const coord_def & p)49 static inline void cursorxy(const coord_def& p) { cursorxy(p.x, p.y); }
50
51 // Converts a key to a direction key, converting keypad and other sequences
52 // to vi key sequences (shifted/control key directions are also handled). Non
53 // direction keys (hopefully) pass through unmangled.
54 int unmangle_direction_keys(int keyin, KeymapContext keymap = KMC_DEFAULT,
55 bool allow_fake_modifiers = true);
56
57 void nowrap_eol_cprintf(PRINTF(0, ));
58 void wrapcprintf(int wrapcol, const char *s, ...);
59 void wrapcprintf(const char *s, ...);
60
61 // Returns zero if user entered text and pressed Enter, otherwise returns the
62 // key pressed that caused the exit, usually Escape.
63 //
64 // If keyproc is provided, it must return 1 for normal processing, 0 to exit
65 // normally (pretend the user pressed Enter), or -1 to exit as if the user
66 // pressed Escape
67 int cancellable_get_line(char *buf,
68 int len,
69 input_history *mh = nullptr,
70 keyfun_action (*keyproc)(int &c) = nullptr,
71 const string &fill = "",
72 const string &tag = "");
73
74 // Do not use this templated function directly. Use the macro below instead.
cancellable_get_line_autohist_temp(char * buf,int len)75 template<int> static int cancellable_get_line_autohist_temp(char *buf, int len)
76 {
77 static input_history hist(10);
78 return cancellable_get_line(buf, len, &hist);
79 }
80
81 // This version of cancellable_get_line will automatically retain its own
82 // input history, independent of other calls to cancellable_get_line.
83 #define cancellable_get_line_autohist(buf, len) \
84 cancellable_get_line_autohist_temp<__LINE__>(buf, len)
85
86 struct c_mouse_event
87 {
88 coord_def pos;
89 int bstate;
90
91 enum button_state_type
92 {
93 BUTTON1 = 0x1,
94 BUTTON1_DBL = 0x2,
95 BUTTON2 = 0x4,
96 BUTTON2_DBL = 0x8,
97 BUTTON3 = 0x10,
98 BUTTON3_DBL = 0x20,
99 BUTTON4 = 0x40,
100 BUTTON4_DBL = 0x80,
101 BUTTON_SCRL_UP = 0x100,
102 BUTTON_SCRL_DN = 0x200,
103 };
104
c_mouse_eventc_mouse_event105 c_mouse_event() : pos(-1, -1), bstate(0)
106 {
107 }
108
posc_mouse_event109 c_mouse_event(const coord_def &c, int state = 0) : pos(c), bstate(state)
110 {
111 }
112
113 // Returns true for valid events.
114 operator bool () const
115 {
116 return bstate;
117 }
118
left_clickedc_mouse_event119 bool left_clicked() const
120 {
121 return bstate & BUTTON1;
122 }
123
right_clickedc_mouse_event124 bool right_clicked() const
125 {
126 return bstate & BUTTON3;
127 }
128
scroll_upc_mouse_event129 bool scroll_up() const
130 {
131 return bstate & (BUTTON4 | BUTTON4_DBL | BUTTON_SCRL_UP);
132 }
133
scroll_downc_mouse_event134 bool scroll_down() const
135 {
136 return bstate & (BUTTON2 | BUTTON2_DBL | BUTTON_SCRL_DN);
137 }
138 };
139
140 c_mouse_event get_mouse_event();
141 void new_mouse_event(const c_mouse_event &ce);
142 void c_input_reset(bool enable_mouse, bool flush = false);
143
144 // Keys that getch() must return for keys Crawl is interested in.
145 enum KEYS
146 {
147 CK_ENTER = '\r',
148 CK_BKSP = 8,
149 CK_ESCAPE = ESCAPE,
150
151 CK_DELETE = -255,
152
153 // This sequence of enums should not be rearranged.
154 CK_UP,
155 CK_DOWN,
156 CK_LEFT,
157 CK_RIGHT,
158
159 CK_INSERT,
160
161 CK_HOME,
162 CK_END,
163 CK_CLEAR,
164
165 CK_PGUP,
166 CK_PGDN,
167 CK_TAB_TILE, // unused
168
169 CK_SHIFT_UP,
170 CK_SHIFT_DOWN,
171 CK_SHIFT_LEFT,
172 CK_SHIFT_RIGHT,
173
174 CK_SHIFT_INSERT,
175
176 CK_SHIFT_HOME,
177 CK_SHIFT_END,
178 CK_SHIFT_CLEAR,
179
180 CK_SHIFT_PGUP,
181 CK_SHIFT_PGDN,
182 CK_SHIFT_TAB,
183
184 CK_CTRL_UP,
185 CK_CTRL_DOWN,
186 CK_CTRL_LEFT,
187 CK_CTRL_RIGHT,
188
189 CK_CTRL_INSERT,
190
191 CK_CTRL_HOME,
192 CK_CTRL_END,
193 CK_CTRL_CLEAR,
194
195 CK_CTRL_PGUP,
196 CK_CTRL_PGDN,
197 CK_CTRL_TAB,
198
199 #ifdef TOUCH_UI
200 // extra numpad keys for zoom
201 CK_NUMPAD_PLUS,
202 CK_NUMPAD_MINUS,
203 #endif
204
205 // ugly...
206 // TODO: should crawl just use one of these internally and convert?
207 #ifdef USE_TILE_LOCAL
208 CK_F12 = -SDLK_F12,
209 #elif defined(TARGET_OS_WINDOWS) // windows console
210 CK_F12 = -379, // -(VK_F12 | 256) // XX ...
211 #else // ncurses console
212 CK_F12 = -276, // -KEY_F12 from ncurses
213 #endif
214 CK_F11,
215 CK_F10,
216 CK_F9,
217 CK_F8,
218 CK_F7,
219 CK_F6,
220 CK_F5,
221 CK_F4,
222 CK_F3,
223 CK_F2,
224 CK_F1, // -265, aka -KEY_F1
225 CK_F0, // is this actually used?
226
227 // Mouse codes.
228 CK_MOUSE_MOVE = -9999,
229 CK_MOUSE_CMD,
230 CK_MOUSE_B1,
231 CK_MOUSE_B2,
232 CK_MOUSE_B3,
233 CK_MOUSE_B4,
234 CK_MOUSE_B5,
235 CK_MOUSE_CLICK,
236 CK_TOUCH_DUMMY, // so a non-event can be passed from handle_mouse to the controlling code
237 CK_REDRAW, // no-op to force redraws of things
238 CK_RESIZE,
239
240 CK_NO_KEY // so that the handle_mouse loop can be broken from early (for
241 // popups), and otherwise for keys to ignore
242 };
243
244 class cursor_control
245 {
246 public:
cursor_control(bool cursor_enabled)247 cursor_control(bool cursor_enabled)
248 : cstate(is_cursor_enabled())
249 {
250 set_cursor_enabled(cursor_enabled);
251 }
~cursor_control()252 ~cursor_control()
253 {
254 set_cursor_enabled(cstate);
255 }
256 private:
257 bool cstate;
258 };
259
260 enum edit_mode
261 {
262 EDIT_MODE_INSERT,
263 EDIT_MODE_OVERWRITE,
264 };
265
266 class draw_colour
267 {
268 public:
269 draw_colour(COLOURS fg, COLOURS bg);
270 ~draw_colour();
271 void set();
272 void reset();
273 private:
274 COLOURS foreground;
275 COLOURS background;
276 };
277
278 // Reads lines of text; used internally by cancellable_get_line.
279 class line_reader
280 {
281 public:
282 line_reader(char *buffer, size_t bufsz,
283 int wrap_col = get_number_of_cols());
284 virtual ~line_reader();
285
286 typedef keyfun_action (*keyproc)(int &key);
287
288 virtual int read_line(bool clear_previous = true, bool reset_cursor = false);
289 int read_line(const string &prefill);
290
291 string get_text() const;
292 void set_text(string s);
293
294 void set_input_history(input_history *ih);
295 void set_keyproc(keyproc fn);
296
297 void set_edit_mode(edit_mode m);
298 edit_mode get_edit_mode();
299
300 void set_colour(COLOURS fg, COLOURS bg);
301 void set_location(coord_def loc);
302
303 string get_prompt();
304 void set_prompt(string p);
305
306 void insert_char_at_cursor(int ch);
307 void overwrite_char_at_cursor(int ch);
308 #ifdef USE_TILE_WEB
309 void set_tag(const string &tag);
310 #endif
311
312 protected:
313 int read_line_core(bool reset_cursor);
314 int process_key_core(int ch);
315 virtual void print_segment(int start_point=0, int overprint=0);
316 virtual void cursorto(int newcpos);
317 virtual int getkey();
318
319 virtual int process_key(int ch);
320 void backspace();
321 void killword();
322 void kill_to_begin();
323 void calc_pos();
324
325 bool is_wordchar(char32_t c);
326
327 protected:
328 char *buffer;
329 size_t bufsz;
330 input_history *history;
331 GotoRegion region;
332 coord_def start;
333 keyproc keyfn;
334 int wrapcol;
335 edit_mode mode;
336 COLOURS fg_colour;
337 COLOURS bg_colour;
338 string prompt; // currently only used for webtiles input dialogs
339
340 #ifdef USE_TILE_WEB
341 string tag; // For identification on the Webtiles client side
342 #endif
343
344 // These are subject to change during editing.
345 char *cur;
346 int length;
347 int pos;
348 };
349
350 #ifdef USE_TILE_LOCAL
351 class fontbuf_line_reader : public line_reader
352 {
353 public:
354 fontbuf_line_reader(char *buffer, size_t bufsz,
355 FontBuffer &font_buf,
356 int wrap_col = get_number_of_cols());
357 int read_line(bool clear_previous = true, bool reset_cursor = false);
358
359 protected:
360 void print_segment(int start_point=0, int overprint=0);
361 void cursorto(int newcpos);
362 int getkey();
363
364 FontBuffer& m_font_buf;
365 };
366 #endif
367
368 class resumable_line_reader : public line_reader
369 {
370 public:
resumable_line_reader(char * buf,size_t sz)371 resumable_line_reader(char *buf, size_t sz) : line_reader(buf, sz, sz) { read_line(); };
putkey(int ch)372 int putkey(int ch) { return process_key_core(ch); };
373 protected:
getkey()374 virtual int getkey() override { return CK_NO_KEY; };
process_key(int ch)375 virtual int process_key(int ch) override
376 {
377 return ch == CK_NO_KEY ? CK_NO_KEY : line_reader::process_key(ch);
378 }
print_segment(int,int)379 virtual void print_segment(int, int) override {};
cursorto(int)380 void cursorto(int) override {};
381 int key;
382 };
383
384 typedef int keycode_type;
385
386 keyfun_action keyfun_num_and_char(int &ch);
387