mirror of
https://codeberg.org/noisytoot/notnotdnethack.git
synced 2024-11-14 13:26:10 +00:00
Ron Nazarov
b5245a400c
This made it impossible to repeat a single command more than 32767 times, or take out/put in a partial stack of more than 32767 items. It's now capped at INT_MAX (2147483647 with 32-bit int) instead and uses C23 stdckdint.h macros to avoid signed integer overflows (which are undefined behaviour). If stdckdint.h is unavailable (it was only added in GCC 14), uses the GCC __builtin_*_overflow functions, which are supported since GCC 5. If these too are unavailable, falls back to an implementation using C11 _Generic. The fallback ckd_mul implementation just casts to a long long, so won't work for anything larger than a 32-bit integer (assuming 64-bit long long), which is fine for now since nothing since it's only used on ints. I'm not sure the fallback implementations are even necessary, since we already require either C23 or a GCC extension (__VA_OPT__) for macromagic.
876 lines
19 KiB
C
876 lines
19 KiB
C
/* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/
|
|
|
|
#include "curses.h"
|
|
#include "hack.h"
|
|
#include "wincurs.h"
|
|
#include "cursmisc.h"
|
|
#include "cursstat.h"
|
|
#include "func_tab.h"
|
|
#include "dlb.h"
|
|
|
|
#include <ctype.h>
|
|
#include <limits.h>
|
|
|
|
/* Misc. curses interface functions */
|
|
|
|
/* Private declarations */
|
|
|
|
static int curs_x = -1;
|
|
static int curs_y = -1;
|
|
|
|
static int parse_escape_sequence(void);
|
|
|
|
/* Macros for Control and Alt keys */
|
|
|
|
#ifndef M
|
|
# define M(c) ((c) - 128)
|
|
#endif
|
|
#ifndef C
|
|
# define C(c) (0x1f & (c))
|
|
#endif
|
|
|
|
|
|
/* Read a character of input from the user */
|
|
|
|
int
|
|
curses_read_char(void)
|
|
{
|
|
int ch, tmpch;
|
|
|
|
ch = getch();
|
|
tmpch = ch;
|
|
ch = curses_convert_keys(ch);
|
|
|
|
if (ch == 0) {
|
|
ch = DOESCAPE; /* map NUL to ESC since nethack doesn't expect NUL */
|
|
}
|
|
#if defined(ALT_0) && defined(ALT_9) /* PDCurses, maybe others */
|
|
if ((ch >= ALT_0) && (ch <= ALT_9)) {
|
|
tmpch = (ch - ALT_0) + '0';
|
|
ch = M(tmpch);
|
|
}
|
|
#endif
|
|
|
|
#if defined(ALT_A) && defined(ALT_Z) /* PDCurses, maybe others */
|
|
if ((ch >= ALT_A) && (ch <= ALT_Z)) {
|
|
tmpch = (ch - ALT_A) + 'a';
|
|
ch = M(tmpch);
|
|
}
|
|
#endif
|
|
|
|
#ifdef KEY_RESIZE
|
|
/* Handle resize events via get_nh_event, not this code */
|
|
if (ch == KEY_RESIZE) {
|
|
ch = DOESCAPE; /* NetHack doesn't know what to do with KEY_RESIZE */
|
|
}
|
|
#endif
|
|
|
|
if (counting && !isdigit(ch)) { /* Dismiss count window if necissary */
|
|
curses_count_window(NULL);
|
|
curses_refresh_nethack_windows();
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
/* Turn on or off the specified color and / or attribute */
|
|
|
|
void
|
|
curses_toggle_color_attr(WINDOW * win, int color, int attr, int onoff)
|
|
{
|
|
int curses_color;
|
|
|
|
/* Map color disabled */
|
|
if ((!iflags.wc_color) && (win == mapwin)) {
|
|
return;
|
|
}
|
|
|
|
/* GUI color disabled */
|
|
if ((!iflags.wc2_guicolor) && (win != mapwin)) {
|
|
return;
|
|
}
|
|
|
|
if (color == 0) { /* make black fg visible */
|
|
# ifdef USE_DARKGRAY
|
|
if (iflags.wc2_darkgray) {
|
|
if (can_change_color() && (COLORS > 16)) {
|
|
/* colorpair for black is already darkgray */
|
|
} else { /* Use bold for a bright black */
|
|
|
|
wattron(win, A_BOLD);
|
|
}
|
|
} else
|
|
# endif/* USE_DARKGRAY */
|
|
color = CLR_BLUE;
|
|
}
|
|
curses_color = color + 1;
|
|
if (COLORS < 16) {
|
|
if (curses_color > 8 && curses_color < 17)
|
|
curses_color -= 8;
|
|
else if (curses_color > (17 + 16))
|
|
curses_color -= 16;
|
|
}
|
|
if (onoff == ON) { /* Turn on color/attributes */
|
|
if (color != NONE) {
|
|
if ((((color > 7) && (color < 17)) ||
|
|
(color > 17 + 17)) && (COLORS < 16)) {
|
|
wattron(win, A_BOLD);
|
|
}
|
|
wattron(win, COLOR_PAIR(curses_color));
|
|
}
|
|
|
|
if (attr != NONE) {
|
|
wattron(win, attr);
|
|
}
|
|
} else { /* Turn off color/attributes */
|
|
|
|
if (color != NONE) {
|
|
if ((color > 7) && (COLORS < 16)) {
|
|
wattroff(win, A_BOLD);
|
|
}
|
|
# ifdef USE_DARKGRAY
|
|
if ((color == 0) && (!can_change_color() || (COLORS <= 16))) {
|
|
wattroff(win, A_BOLD);
|
|
}
|
|
# else
|
|
if (iflags.use_inverse) {
|
|
wattroff(win, A_REVERSE);
|
|
}
|
|
# endif/* DARKGRAY */
|
|
wattroff(win, COLOR_PAIR(curses_color));
|
|
}
|
|
|
|
if (attr != NONE) {
|
|
wattroff(win, attr);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* clean up and quit - taken from tty port */
|
|
|
|
void
|
|
curses_bail(const char *mesg)
|
|
{
|
|
clearlocks();
|
|
curses_exit_nhwindows(mesg);
|
|
terminate(EXIT_SUCCESS);
|
|
}
|
|
|
|
|
|
/* Return a winid for a new window of the given type */
|
|
|
|
winid
|
|
curses_get_wid(int type)
|
|
{
|
|
winid ret;
|
|
static winid menu_wid = 20; /* Always even */
|
|
static winid text_wid = 21; /* Always odd */
|
|
|
|
switch (type) {
|
|
case NHW_MESSAGE:
|
|
return MESSAGE_WIN;
|
|
case NHW_MAP:
|
|
return MAP_WIN;
|
|
case NHW_STATUS:
|
|
return STATUS_WIN;
|
|
case NHW_MENU:
|
|
ret = menu_wid;
|
|
break;
|
|
case NHW_TEXT:
|
|
ret = text_wid;
|
|
break;
|
|
default:
|
|
impossible("curses_get_wid: unsupported window type");
|
|
ret = -1;
|
|
}
|
|
|
|
while (curses_window_exists(ret)) {
|
|
ret += 2;
|
|
if ((ret + 2) > 10000) { /* Avoid "wid2k" problem */
|
|
ret -= 9900;
|
|
}
|
|
}
|
|
|
|
if (type == NHW_MENU) {
|
|
menu_wid += 2;
|
|
} else {
|
|
text_wid += 2;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* Allocate a copy of the given string. If null, return a string of
|
|
* zero length.
|
|
*
|
|
* This is taken from copy_of() in tty/wintty.c.
|
|
*/
|
|
|
|
char *
|
|
curses_copy_of(const char *s)
|
|
{
|
|
if (!s)
|
|
s = "";
|
|
return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s);
|
|
}
|
|
|
|
|
|
/* Determine the number of lines needed for a string for a dialog window
|
|
of the given width */
|
|
|
|
int
|
|
curses_num_lines(const char *str, int width)
|
|
{
|
|
int last_space, count;
|
|
int curline = 1;
|
|
char substr[BUFSZ];
|
|
char tmpstr[BUFSZ];
|
|
|
|
strncpy(substr, str, BUFSZ-1);
|
|
substr[BUFSZ-1] = '\0';
|
|
|
|
while (strlen(substr) > width) {
|
|
last_space = 0;
|
|
|
|
for (count = 0; count <= width; count++) {
|
|
if (substr[count] == ' ')
|
|
last_space = count;
|
|
|
|
}
|
|
if (last_space == 0) { /* No spaces found */
|
|
last_space = count - 1;
|
|
}
|
|
for (count = (last_space + 1); count < strlen(substr); count++) {
|
|
tmpstr[count - (last_space + 1)] = substr[count];
|
|
}
|
|
tmpstr[count - (last_space + 1)] = '\0';
|
|
strcpy(substr, tmpstr);
|
|
curline++;
|
|
}
|
|
|
|
return curline;
|
|
}
|
|
|
|
|
|
/* Break string into smaller lines to fit into a dialog window of the
|
|
given width */
|
|
|
|
char *
|
|
curses_break_str(const char *str, int width, int line_num)
|
|
{
|
|
int last_space, count;
|
|
char *retstr;
|
|
int curline = 0;
|
|
int strsize = strlen(str);
|
|
char substr[strsize+1];
|
|
char curstr[strsize+1];
|
|
char tmpstr[strsize+1];
|
|
|
|
strcpy(substr, str);
|
|
|
|
while (curline < line_num) {
|
|
if (strlen(substr) == 0) {
|
|
break;
|
|
}
|
|
curline++;
|
|
last_space = 0;
|
|
for (count = 0; count <= width; count++) {
|
|
if (substr[count] == ' ') {
|
|
last_space = count;
|
|
} else if (substr[count] == '\0') {
|
|
last_space = count;
|
|
break;
|
|
}
|
|
}
|
|
if (last_space == 0) { /* No spaces found */
|
|
last_space = count - 1;
|
|
}
|
|
for (count = 0; count < last_space; count++) {
|
|
curstr[count] = substr[count];
|
|
}
|
|
curstr[count] = '\0';
|
|
if (substr[count] == '\0') {
|
|
break;
|
|
}
|
|
for (count = (last_space + 1); count < strlen(substr); count++) {
|
|
tmpstr[count - (last_space + 1)] = substr[count];
|
|
}
|
|
tmpstr[count - (last_space + 1)] = '\0';
|
|
strcpy(substr, tmpstr);
|
|
}
|
|
|
|
if (curline < line_num) {
|
|
return NULL;
|
|
}
|
|
|
|
retstr = curses_copy_of(curstr);
|
|
|
|
return retstr;
|
|
}
|
|
|
|
|
|
/* Return the remaining portion of a string after hacking-off line_num lines */
|
|
|
|
char *
|
|
curses_str_remainder(const char *str, int width, int line_num)
|
|
{
|
|
int last_space, count;
|
|
char *retstr;
|
|
int curline = 0;
|
|
int strsize = strlen(str) + 1;
|
|
char substr[strsize];
|
|
char curstr[strsize];
|
|
char tmpstr[strsize];
|
|
|
|
strncpy(substr, str, strsize);
|
|
|
|
while (curline < line_num) {
|
|
if (strlen(substr) == 0) {
|
|
break;
|
|
}
|
|
curline++;
|
|
last_space = 0;
|
|
for (count = 0; count <= width; count++) {
|
|
if (substr[count] == ' ') {
|
|
last_space = count;
|
|
} else if (substr[count] == '\0') {
|
|
last_space = count;
|
|
break;
|
|
}
|
|
}
|
|
if (last_space == 0) { /* No spaces found */
|
|
last_space = count - 1;
|
|
}
|
|
for (count = 0; count < last_space; count++) {
|
|
curstr[count] = substr[count];
|
|
}
|
|
curstr[count] = '\0';
|
|
if (substr[count] == '\0') {
|
|
break;
|
|
}
|
|
for (count = (last_space + 1); count < strlen(substr); count++) {
|
|
tmpstr[count - (last_space + 1)] = substr[count];
|
|
}
|
|
tmpstr[count - (last_space + 1)] = '\0';
|
|
strcpy(substr, tmpstr);
|
|
}
|
|
|
|
if (curline < line_num) {
|
|
return NULL;
|
|
}
|
|
|
|
retstr = curses_copy_of(substr);
|
|
|
|
return retstr;
|
|
}
|
|
|
|
|
|
/* Determine if the given NetHack winid is a menu window */
|
|
|
|
boolean
|
|
curses_is_menu(winid wid)
|
|
{
|
|
if ((wid > 19) && !(wid % 2)) { /* Even number */
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/* Determine if the given NetHack winid is a text window */
|
|
|
|
boolean
|
|
curses_is_text(winid wid)
|
|
{
|
|
if ((wid > 19) && (wid % 2)) { /* Odd number */
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/* Replace certain characters with portable drawing characters if
|
|
cursesgraphics option is enabled */
|
|
|
|
int
|
|
curses_convert_glyph(int ch, int glyph)
|
|
{
|
|
int symbol;
|
|
|
|
#ifdef REINCARNATION
|
|
if (Is_rogue_level(&u.uz)) {
|
|
return ch;
|
|
}
|
|
#endif
|
|
|
|
/* Save some processing time by returning if the glyph represents
|
|
an object that we don't have custom characters for */
|
|
if (!glyph_is_cmap(glyph)) {
|
|
return ch;
|
|
}
|
|
|
|
symbol = glyph_to_cmap(glyph);
|
|
|
|
/* If user selected a custom character for this object, don't
|
|
override this. */
|
|
if (((glyph_is_cmap(glyph)) && (ch != showsyms[symbol]))) {
|
|
return ch;
|
|
}
|
|
|
|
switch (symbol) {
|
|
case S_vwall:
|
|
return ACS_VLINE;
|
|
case S_hwall:
|
|
return ACS_HLINE;
|
|
case S_tlcorn:
|
|
return ACS_ULCORNER;
|
|
case S_trcorn:
|
|
return ACS_URCORNER;
|
|
case S_blcorn:
|
|
return ACS_LLCORNER;
|
|
case S_brcorn:
|
|
return ACS_LRCORNER;
|
|
case S_crwall:
|
|
return ACS_PLUS;
|
|
case S_tuwall:
|
|
return ACS_BTEE;
|
|
case S_tdwall:
|
|
return ACS_TTEE;
|
|
case S_tlwall:
|
|
return ACS_RTEE;
|
|
case S_trwall:
|
|
return ACS_LTEE;
|
|
case S_tree:
|
|
return ACS_PLMINUS;
|
|
case S_deadtree:
|
|
return ACS_PLMINUS;
|
|
case S_corr:
|
|
return ACS_CKBOARD;
|
|
case S_litcorr:
|
|
return ACS_CKBOARD;
|
|
}
|
|
|
|
return ch;
|
|
}
|
|
|
|
|
|
/* Move text cursor to specified coordinates in the given NetHack window */
|
|
|
|
void
|
|
curses_move_cursor(winid wid, int x, int y)
|
|
{
|
|
int sx, sy, ex, ey;
|
|
int xadj = 0;
|
|
int yadj = 0;
|
|
|
|
#ifndef PDCURSES
|
|
WINDOW *win = curses_get_nhwin(MAP_WIN);
|
|
#endif
|
|
|
|
if (wid != MAP_WIN) {
|
|
return;
|
|
}
|
|
#ifdef PDCURSES
|
|
/* PDCurses seems to not handle wmove correctly, so we use move and
|
|
physical screen coordinates instead */
|
|
curses_get_window_xy(wid, &xadj, &yadj);
|
|
#endif
|
|
curs_x = x + xadj;
|
|
curs_y = y + yadj;
|
|
curses_map_borders(&sx, &sy, &ex, &ey, x, y);
|
|
|
|
if (curses_window_has_border(wid)) {
|
|
curs_x++;
|
|
curs_y++;
|
|
}
|
|
|
|
if ((x >= sx) && (x <= ex) && (y >= sy) && (y <= ey)) {
|
|
curs_x -= sx;
|
|
curs_y -= sy;
|
|
#ifdef PDCURSES
|
|
move(curs_y, curs_x);
|
|
#else
|
|
wmove(win, curs_y, curs_x);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
/* Perform actions that should be done every turn before nhgetch() */
|
|
|
|
void
|
|
curses_prehousekeeping(void)
|
|
{
|
|
#ifndef PDCURSES
|
|
WINDOW *win = curses_get_nhwin(MAP_WIN);
|
|
#endif /* PDCURSES */
|
|
|
|
if ((curs_x > -1) && (curs_y > -1)) {
|
|
curs_set(1);
|
|
#ifdef PDCURSES
|
|
/* PDCurses seems to not handle wmove correctly, so we use move
|
|
and physical screen coordinates instead */
|
|
move(curs_y, curs_x);
|
|
#else
|
|
wmove(win, curs_y, curs_x);
|
|
#endif /* PDCURSES */
|
|
curses_refresh_nhwin(MAP_WIN);
|
|
}
|
|
}
|
|
|
|
|
|
/* Perform actions that should be done every turn after nhgetch() */
|
|
|
|
void
|
|
curses_posthousekeeping(void)
|
|
{
|
|
curs_set(0);
|
|
curses_decrement_highlights(FALSE);
|
|
curses_clear_unhighlight_message_window();
|
|
}
|
|
|
|
|
|
void
|
|
curses_view_file(const char *filename, boolean must_exist)
|
|
{
|
|
winid wid;
|
|
anything identifier;
|
|
char buf[BUFSZ];
|
|
menu_item *selected = NULL;
|
|
dlb *fp = dlb_fopen(filename, "r");
|
|
|
|
if ((fp == NULL) && (must_exist)) {
|
|
pline("Cannot open %s for reading!", filename);
|
|
}
|
|
|
|
if (fp == NULL) {
|
|
return;
|
|
}
|
|
|
|
wid = curses_get_wid(NHW_MENU);
|
|
curses_create_nhmenu(wid);
|
|
identifier = zeroany;
|
|
|
|
while (dlb_fgets(buf, BUFSZ, fp) != NULL) {
|
|
curses_add_menu(wid, NO_GLYPH, &identifier, 0, 0, A_NORMAL, buf, FALSE);
|
|
}
|
|
|
|
dlb_fclose(fp);
|
|
curses_end_menu(wid, "");
|
|
curses_select_menu(wid, PICK_NONE, &selected);
|
|
}
|
|
|
|
|
|
void
|
|
curses_rtrim(char *str)
|
|
{
|
|
char *s;
|
|
|
|
for (s = str; *s != '\0'; ++s);
|
|
if (s == str)
|
|
return;
|
|
for (--s; isspace(*s) && s > str; --s);
|
|
if (s == str)
|
|
*s = '\0';
|
|
else
|
|
*(++s) = '\0';
|
|
}
|
|
|
|
|
|
/* Read numbers until non-digit is encountered, and return number
|
|
in int form. */
|
|
|
|
int
|
|
curses_get_count(int first_digit)
|
|
{
|
|
int current_count = first_digit;
|
|
int current_char;
|
|
|
|
current_char = curses_read_char();
|
|
|
|
while (isdigit(current_char)) {
|
|
if (ckd_mul(¤t_count, current_count, 10)) {
|
|
current_count = INT_MAX;
|
|
} else if (ckd_add(¤t_count, current_count, current_char - '0')) {
|
|
current_count = INT_MAX;
|
|
}
|
|
|
|
pline("Count: %d", current_count);
|
|
current_char = curses_read_char();
|
|
}
|
|
|
|
ungetch(current_char);
|
|
|
|
if (current_char == DOESCAPE) { /* Cancelled with escape */
|
|
current_count = -1;
|
|
}
|
|
|
|
return current_count;
|
|
}
|
|
|
|
|
|
/* Convert the given NetHack text attributes into the format curses
|
|
understands, and return that format mask. */
|
|
|
|
int
|
|
curses_convert_attr(int attr)
|
|
{
|
|
int curses_attr;
|
|
|
|
switch (attr) {
|
|
case ATR_NONE:
|
|
curses_attr = A_NORMAL;
|
|
break;
|
|
case ATR_ULINE:
|
|
curses_attr = A_UNDERLINE;
|
|
break;
|
|
case ATR_BOLD:
|
|
curses_attr = A_BOLD;
|
|
break;
|
|
case ATR_BLINK:
|
|
curses_attr = A_BLINK;
|
|
break;
|
|
case ATR_INVERSE:
|
|
curses_attr = A_REVERSE;
|
|
break;
|
|
default:
|
|
curses_attr = A_NORMAL;
|
|
}
|
|
|
|
return curses_attr;
|
|
}
|
|
|
|
|
|
/* Map letter attributes from a string to bitmask. Return mask on
|
|
success, or 0 if not found */
|
|
|
|
int
|
|
curses_read_attrs(char *attrs)
|
|
{
|
|
int retattr = 0;
|
|
|
|
if (strchr(attrs, 'b') || strchr(attrs, 'B')) {
|
|
retattr = retattr | A_BOLD;
|
|
}
|
|
if (strchr(attrs, 'i') || strchr(attrs, 'I')) {
|
|
retattr = retattr | A_REVERSE;
|
|
}
|
|
if (strchr(attrs, 'u') || strchr(attrs, 'U')) {
|
|
retattr = retattr | A_UNDERLINE;
|
|
}
|
|
if (strchr(attrs, 'k') || strchr(attrs, 'K')) {
|
|
retattr = retattr | A_BLINK;
|
|
}
|
|
#ifdef A_ITALIC
|
|
if (strchr(attrs, 't') || strchr(attrs, 'T')) {
|
|
retattr = retattr | A_ITALIC;
|
|
}
|
|
#endif
|
|
#ifdef A_RIGHTLINE
|
|
if (strchr(attrs, 'r') || strchr(attrs, 'R')) {
|
|
retattr = retattr | A_RIGHTLINE;
|
|
}
|
|
#endif
|
|
#ifdef A_LEFTLINE
|
|
if (strchr(attrs, 'l') || strchr(attrs, 'L')) {
|
|
retattr = retattr | A_LEFTLINE;
|
|
}
|
|
#endif
|
|
|
|
return retattr;
|
|
}
|
|
|
|
|
|
/* Convert special keys into values that NetHack can understand.
|
|
Currently this is limited to arrow keys, but this may be expanded. */
|
|
|
|
int
|
|
curses_convert_keys(int key)
|
|
{
|
|
int ret = key;
|
|
|
|
if (ret == '\033') {
|
|
ret = parse_escape_sequence();
|
|
}
|
|
|
|
/* Handle arrow keys */
|
|
switch (key) {
|
|
case KEY_LEFT:
|
|
if (iflags.num_pad) {
|
|
ret = '4';
|
|
} else {
|
|
ret = 'h';
|
|
}
|
|
break;
|
|
case KEY_RIGHT:
|
|
if (iflags.num_pad) {
|
|
ret = '6';
|
|
} else {
|
|
ret = 'l';
|
|
}
|
|
break;
|
|
case KEY_UP:
|
|
if (iflags.num_pad) {
|
|
ret = '8';
|
|
} else {
|
|
ret = 'k';
|
|
}
|
|
break;
|
|
case KEY_DOWN:
|
|
if (iflags.num_pad) {
|
|
ret = '2';
|
|
} else {
|
|
ret = 'j';
|
|
}
|
|
break;
|
|
#ifdef KEY_A1
|
|
case KEY_A1:
|
|
if (iflags.num_pad) {
|
|
ret = '7';
|
|
} else {
|
|
ret = 'y';
|
|
}
|
|
break;
|
|
#endif /* KEY_A1 */
|
|
#ifdef KEY_A3
|
|
case KEY_A3:
|
|
if (iflags.num_pad) {
|
|
ret = '9';
|
|
} else {
|
|
ret = 'u';
|
|
}
|
|
break;
|
|
#endif /* KEY_A3 */
|
|
#ifdef KEY_C1
|
|
case KEY_C1:
|
|
if (iflags.num_pad) {
|
|
ret = '1';
|
|
} else {
|
|
ret = 'b';
|
|
}
|
|
break;
|
|
#endif /* KEY_C1 */
|
|
#ifdef KEY_C3
|
|
case KEY_C3:
|
|
if (iflags.num_pad) {
|
|
ret = '3';
|
|
} else {
|
|
ret = 'n';
|
|
}
|
|
break;
|
|
#endif /* KEY_C3 */
|
|
#ifdef KEY_B2
|
|
case KEY_B2:
|
|
if (iflags.num_pad) {
|
|
ret = '5';
|
|
} else {
|
|
ret = 'g';
|
|
}
|
|
break;
|
|
#endif /* KEY_B2 */
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* Process mouse events. Mouse movement is processed until no further
|
|
mouse movement events are available. Returns 0 for a mouse click
|
|
event, or the first non-mouse key event in the case of mouse
|
|
movement. */
|
|
|
|
int
|
|
curses_get_mouse(int *mousex, int *mousey, int *mod)
|
|
{
|
|
int key = '\033';
|
|
|
|
#ifdef NCURSES_MOUSE_VERSION
|
|
MEVENT event;
|
|
|
|
if (getmouse(&event) == OK) { /* When the user clicks left mouse button */
|
|
if (event.bstate & BUTTON1_CLICKED) {
|
|
/* See if coords are in map window & convert coords */
|
|
if (wmouse_trafo(mapwin, &event.y, &event.x, TRUE)) {
|
|
key = 0; /* Flag mouse click */
|
|
*mousex = event.x;
|
|
*mousey = event.y;
|
|
|
|
if (curses_window_has_border(MAP_WIN)) {
|
|
(*mousex)--;
|
|
(*mousey)--;
|
|
}
|
|
|
|
*mod = CLICK_1;
|
|
}
|
|
}
|
|
}
|
|
#endif /* NCURSES_MOUSE_VERSION */
|
|
|
|
return key;
|
|
}
|
|
|
|
|
|
static int
|
|
parse_escape_sequence(void)
|
|
{
|
|
#ifndef PDCURSES
|
|
int ret;
|
|
|
|
timeout(10);
|
|
|
|
ret = getch();
|
|
|
|
if (ret != ERR) { /* Likely an escape sequence */
|
|
if (((ret >= 'a') && (ret <= 'z')) || ((ret >= '0') && (ret <= '9'))) {
|
|
ret |= 0x80; /* Meta key support for most terminals */
|
|
} else if (ret == 'O') { /* Numeric keypad */
|
|
ret = getch();
|
|
if ((ret != ERR) && (ret >= 112) && (ret <= 121)) {
|
|
ret = ret - 112 + '0'; /* Convert to number */
|
|
} else {
|
|
ret = '\033'; /* Escape */
|
|
}
|
|
}
|
|
} else {
|
|
ret = '\033'; /* Just an escape character */
|
|
}
|
|
|
|
timeout(-1);
|
|
|
|
return ret;
|
|
#else
|
|
return '\033';
|
|
#endif /* !PDCURSES */
|
|
}
|
|
|
|
|
|
/* This is a kludge for the statuscolors patch which calls tty-specific
|
|
functions, which causes a compiler error if TTY_GRAPHICS is not
|
|
defined. Adding stub functions to avoid this. */
|
|
|
|
#ifndef TTY_GRAPHICS
|
|
extern void
|
|
term_start_color(int color)
|
|
{
|
|
}
|
|
|
|
extern void
|
|
term_start_attr(int attr)
|
|
{
|
|
}
|
|
|
|
extern void
|
|
term_end_color(void)
|
|
{
|
|
}
|
|
|
|
extern void
|
|
term_end_attr(int attr)
|
|
{
|
|
}
|
|
#endif /* !TTY_GRAPGICS */
|