3 * Summary: Platform-independent console IO functions.
4 * Created by: dshaligram on Wed Jun 20 19:00:52 2007 UTC
21 extern int unixcurses_get_vi_key(int keyin
);
23 static keycode_type
_numpad2vi(keycode_type key
)
26 key
= unixcurses_get_vi_key(key
);
30 case CK_UP
: key
= 'k'; break;
31 case CK_DOWN
: key
= 'j'; break;
32 case CK_LEFT
: key
= 'h'; break;
33 case CK_RIGHT
: key
= 'l'; break;
34 case 1001: key
= 'b'; break;
35 case 1002: key
= 'j'; break;
36 case 1003: key
= 'n'; break;
37 case 1004: key
= 'h'; break;
38 case 1005: key
= '.'; break;
39 case 1006: key
= 'l'; break;
40 case 1007: key
= 'y'; break;
41 case 1008: key
= 'k'; break;
42 case 1009: key
= 'u'; break;
44 if (key
>= '1' && key
<= '9')
46 const char *vikeys
= "bjnh.lyku";
47 return keycode_type(vikeys
[key
- '1']);
53 int unmangle_direction_keys(int keyin
, KeymapContext keymap
,
54 bool fake_ctrl
, bool fake_shift
)
57 // Kludging running and opening as two character sequences
58 // for Unix systems. This is an easy way out... all the
59 // player has to do is find a termcap and numlock setting
60 // that will get curses the numbers from the keypad. This
61 // will hopefully be easy.
63 /* can we say yuck? -- haranp */
64 if (fake_ctrl
&& keyin
== '*')
66 keyin
= getchm(keymap
);
68 keyin
= CONTROL(toupper(_numpad2vi(keyin
)));
70 else if (fake_shift
&& keyin
== '/')
72 keyin
= getchm(keymap
);
74 keyin
= toupper(_numpad2vi(keyin
));
77 // Old DOS keypad support
80 /* FIXME haranp - hackiness */
81 const char DOSidiocy
[10] = { "OPQKSMGHI" };
82 const char DOSunidiocy
[10] = { "bjnh.lyku" };
83 const int DOScontrolidiocy
[9] =
85 117, 145, 118, 115, 76, 116, 119, 141, 132
87 keyin
= getchm(keymap
);
88 for (int j
= 0; j
< 9; ++j
)
90 if (keyin
== DOSidiocy
[j
])
92 keyin
= DOSunidiocy
[j
];
95 if (keyin
== DOScontrolidiocy
[j
])
97 keyin
= CONTROL(toupper(DOSunidiocy
[j
]));
104 // [dshaligram] More lovely keypad mangling.
108 case '1': return 'b';
109 case '2': return 'j';
110 case '3': return 'n';
111 case '4': return 'h';
112 case '6': return 'l';
113 case '7': return 'y';
114 case '8': return 'k';
115 case '9': return 'u';
118 default: return unixcurses_get_vi_key(keyin
);
122 case '1': return 'B';
123 case '2': return 'J';
124 case '3': return 'N';
125 case '4': return 'H';
126 case '6': return 'L';
127 case '7': return 'Y';
128 case '8': return 'K';
129 case '9': return 'U';
136 // Wrapper around cgotoxy that can draw a fake cursor for Unix terms where
137 // cursoring over darkgrey or black causes problems.
138 void cursorxy(int x
, int y
)
140 #if defined(USE_TILE)
142 coord_def gc
= crawl_view
.screen2grid(ep
);
143 tiles
.place_cursor(CURSOR_MOUSE
, gc
);
145 if (Options
.use_fake_cursor
)
148 cgotoxy(x
, y
, GOTO_CRT
);
150 cgotoxy(x
, y
, GOTO_CRT
);
154 // cprintf that stops outputting when wrapped
155 // Conceptually very similar to wrapcprintf()
156 int nowrapcprintf(int wrapcol
, const char *s
, ...)
158 char buf
[1000]; // Hard max
162 // XXX: If snprintf isn't available, vsnprintf probably isn't, either.
163 const int len
= vsnprintf(buf
, sizeof buf
, s
, args
);
166 // Sanity checking to prevent buffer overflows
167 const int maxlen
= std::min(std::max(wrapcol
+ 1 - wherex(), 0), len
);
169 // Force the string to terminate at maxlen
173 return std::min(len
, maxlen
);
176 // convenience wrapper (hah) for nowrapcprintf
177 // FIXME: should pass off to nowrapcprintf() instead of doing it manually
178 int nowrap_eol_cprintf(const char *s
, ...)
180 const int wrapcol
= get_number_of_cols() - 1;
181 char buf
[1000]; // Hard max
185 // XXX: If snprintf isn't available, vsnprintf probably isn't, either.
186 const int len
= vsnprintf(buf
, sizeof buf
, s
, args
);
189 // Sanity checking to prevent buffer overflows
190 const int maxlen
= std::min(std::max(wrapcol
+ 1 - wherex(), 0), len
);
192 // Force the string to terminate at maxlen
196 return std::min(len
, maxlen
);
199 // cprintf that knows how to wrap down lines (primitive, but what the heck)
200 int wrapcprintf(int wrapcol
, const char *s
, ...)
202 char buf
[1000]; // Hard max
206 // XXX: If snprintf isn't available, vsnprintf probably isn't, either.
207 int len
= vsnprintf(buf
, sizeof buf
, s
, args
);
214 int x
= wherex(), y
= wherey();
216 if (x
> wrapcol
) // Somebody messed up!
219 int avail
= wrapcol
- x
+ 1;
231 if ((len
-= avail
) > 0)
238 int cancelable_get_line(char *buf
, int len
, input_history
*mh
,
239 int (*keyproc
)(int &ch
))
241 flush_prev_message();
243 mouse_control
mc(MOUSE_MODE_MORE
);
244 line_reader
reader(buf
, len
, get_number_of_cols());
245 reader
.set_input_history(mh
);
246 reader
.set_keyproc(keyproc
);
248 return reader
.read_line();
252 /////////////////////////////////////////////////////////////
256 input_history::input_history(size_t size
)
257 : history(), pos(), maxsize(size
)
265 void input_history::new_input(const std::string
&s
)
269 if (history
.size() == maxsize
)
272 history
.push_back(s
);
274 // Force the iterator to the end (also revalidates it)
278 const std::string
*input_history::prev()
283 if (pos
== history
.begin())
289 const std::string
*input_history::next()
294 if (pos
== history
.end() || ++pos
== history
.end())
295 pos
= history
.begin();
300 void input_history::go_end()
305 void input_history::clear()
311 /////////////////////////////////////////////////////////////////////////
314 line_reader::line_reader(char *buf
, size_t sz
, int wrap
)
315 : buffer(buf
), bufsz(sz
), history(NULL
), region(GOTO_CRT
),
316 start(coord_def(0,0)), keyfn(NULL
), wrapcol(wrap
),
317 cur(NULL
), length(0), pos(-1)
321 line_reader::~line_reader()
325 std::string
line_reader::get_text() const
330 void line_reader::set_input_history(input_history
*i
)
335 void line_reader::set_keyproc(keyproc fn
)
340 void line_reader::cursorto(int ncx
)
342 int x
= (start
.x
+ ncx
- 1) % wrapcol
+ 1;
343 int y
= start
.y
+ (start
.x
+ ncx
- 1) / wrapcol
;
344 int diff
= y
- cgetsize(region
).y
;
347 // There's no space left in the region, so we scroll it.
348 // XXX: cscroll only implemented for GOTO_MSG.
349 // XXX: wrapcprintf works in GOTO_SCREEN; in particular
350 // it wraps to the screen's first column, so this
351 // won't work for regions that don't start at the
353 cscroll(diff
, region
);
356 cgotoxy(start
.x
, start
.y
, region
);
357 wrapcprintf(wrapcol
, "%s", buffer
);
359 cgotoxy(x
, y
, region
);
362 int line_reader::read_line(bool clear_previous
)
367 cursor_control
con(true);
372 region
= get_cursor_region();
373 start
= cgetpos(region
);
375 length
= strlen(buffer
);
377 // Remember the previous cursor position, if valid.
378 if (pos
< 0 || pos
> length
)
384 wrapcprintf(wrapcol
, "%s", buffer
);
394 int ch
= getchm(getch_ck
);
396 #if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES)
397 // Don't return a partial string if a HUP signal interrupted things
398 if (crawl_state
.seen_hups
)
407 int whattodo
= (*keyfn
)(ch
);
411 if (history
&& length
)
412 history
->new_input(buffer
);
415 else if (whattodo
== -1)
422 int ret
= process_key(ch
);
428 void line_reader::backspace()
445 wrapcprintf(wrapcol
, "%s ", cur
);
450 bool line_reader::is_wordchar(int c
)
452 return isalnum(c
) || c
== '_' || c
== '-';
455 void line_reader::kill_to_begin()
457 if (!pos
|| cur
== buffer
)
462 wrapcprintf(wrapcol
, "%s%*s", cur
, cur
- buffer
, "");
463 memmove(buffer
, cur
, length
- pos
);
470 void line_reader::killword()
472 if (!pos
|| cur
== buffer
)
475 bool foundwc
= false;
478 if (is_wordchar(cur
[-1]))
487 int line_reader::process_key(int ch
)
499 const std::string
*text
= (ch
== CK_UP
) ? history
->prev()
505 length
= text
->length();
506 if (length
>= static_cast<int>(bufsz
))
508 memcpy(buffer
, text
->c_str(), length
);
512 int clear
= length
< olen
? olen
- length
: 0;
513 wrapcprintf(wrapcol
, "%s%*s", buffer
, clear
, "");
523 if (history
&& length
)
524 history
->new_input(buffer
);
529 // Kill to end of line.
530 int erase
= length
- pos
;
535 wrapcprintf(wrapcol
, "%*s", erase
, "");
544 while (c
- buffer
< length
)
553 wrapcprintf(wrapcol
, "%s ", cur
);
601 if (isprint(ch
) && length
< static_cast<int>(bufsz
) - 1)
605 char *c
= buffer
+ length
- 1;
612 *cur
++ = static_cast<char>(ch
);
618 wrapcprintf(wrapcol
, "%s", cur
);
627 /////////////////////////////////////////////////////////////////////////////
628 // Of mice and other mice.
630 static std::queue
<c_mouse_event
> mouse_events
;
632 coord_def
get_mouse_pos()
634 // lib$(OS) has to maintain mousep. This function is just the messenger.
635 return (crawl_view
.mousep
);
638 c_mouse_event
get_mouse_event()
640 if (mouse_events
.empty())
641 return c_mouse_event();
643 c_mouse_event ce
= mouse_events
.front();
648 void new_mouse_event(const c_mouse_event
&ce
)
650 mouse_events
.push(ce
);
653 static void _flush_mouse_events()
655 while (!mouse_events
.empty())
659 void c_input_reset(bool enable_mouse
, bool flush
)
661 crawl_state
.mouse_enabled
= (enable_mouse
&& Options
.mouse_input
);
662 set_mouse_enabled(crawl_state
.mouse_enabled
);
665 _flush_mouse_events();