From 8ad4f44fa747a32e0d476971beeaf2c0550f16e5 Mon Sep 17 00:00:00 2001 From: dshaligram Date: Wed, 20 Jun 2007 19:00:52 +0000 Subject: Experimental mouse support for ncurses (enable with mouse_input=yes in .crawlrc). git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1610 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/acr.cc | 53 +++- crawl-ref/source/beam.cc | 1 + crawl-ref/source/cio.cc | 582 ++++++++++++++++++++++++++++++++++++++++++ crawl-ref/source/cio.h | 226 ++++++++++++++++ crawl-ref/source/clua.cc | 1 + crawl-ref/source/debug.cc | 1 + crawl-ref/source/direct.cc | 71 +++--- crawl-ref/source/direct.h | 2 + crawl-ref/source/enum.h | 3 + crawl-ref/source/externs.h | 17 +- crawl-ref/source/initfile.cc | 6 + crawl-ref/source/item_use.cc | 1 + crawl-ref/source/libdos.cc | 34 +++ crawl-ref/source/libdos.h | 2 + crawl-ref/source/libunix.cc | 78 +++++- crawl-ref/source/libunix.h | 2 + crawl-ref/source/libutil.cc | 558 ---------------------------------------- crawl-ref/source/libutil.h | 142 +---------- crawl-ref/source/libw32c.cc | 42 ++- crawl-ref/source/libw32c.h | 7 +- crawl-ref/source/macro.cc | 17 +- crawl-ref/source/makefile.obj | 1 + crawl-ref/source/menu.cc | 1 + crawl-ref/source/message.cc | 2 +- crawl-ref/source/newgame.cc | 1 + crawl-ref/source/notes.cc | 1 + crawl-ref/source/player.cc | 46 ++-- crawl-ref/source/shopping.cc | 2 +- crawl-ref/source/skills2.cc | 99 ++++--- crawl-ref/source/spl-book.cc | 12 +- crawl-ref/source/spl-book.h | 4 +- crawl-ref/source/stash.cc | 1 + crawl-ref/source/travel.cc | 10 + crawl-ref/source/tutorial.cc | 2 +- crawl-ref/source/view.cc | 47 +++- 35 files changed, 1212 insertions(+), 863 deletions(-) create mode 100644 crawl-ref/source/cio.cc create mode 100644 crawl-ref/source/cio.h (limited to 'crawl-ref/source') diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 022c264ec7..df5ff8929d 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -74,6 +74,7 @@ #include "abyss.h" #include "branch.h" #include "chardump.h" +#include "cio.h" #include "cloud.h" #include "clua.h" #include "command.h" @@ -923,14 +924,23 @@ static void input() cursor_control con(true); crawl_state.waiting_for_command = true; - command_type cmd = get_next_cmd(); + c_input_reset(true); + + const command_type cmd = get_next_cmd(); + crawl_state.waiting_for_command = false; + if (cmd != CMD_MOUSE_MOVE) + c_input_reset(false); + // [dshaligram] If get_next_cmd encountered a Lua macro // binding, your turn may be ended by the first invoke of the // macro. if (!you.turn_is_over && cmd != CMD_NEXT_CMD) process_command( cmd ); + + if (cmd != CMD_MOUSE_MOVE) + c_input_reset(false, true); } if (you.turn_is_over) @@ -1127,7 +1137,6 @@ void process_command( command_type cmd ) break; case CMD_MAKE_NOTE: -// Options.tut_made_note = 0; make_user_note(); break; @@ -1342,13 +1351,6 @@ void process_command( command_type cmd ) break; case CMD_EXPLORE: - if (Options.tut_explored) - Options.tut_explored = 0; - if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS) - { - mpr("It would help if you knew where you were, first."); - break; - } // Start exploring start_explore(Options.explore_greedy); break; @@ -1414,9 +1416,37 @@ void process_command( command_type cmd ) break; case CMD_SHOUT: - yell(); /* in effects.cc */ + yell(); break; + case CMD_MOUSE_MOVE: + break; + + case CMD_MOUSE_CLICK: + { + // XXX: We should probably use specific commands such as + // CMD_MOUSE_TRAVEL and get rid of CMD_MOUSE_CLICK and + // CMD_MOUSE_MOVE. + c_mouse_event cme = get_mouse_event(); + if (cme && crawl_view.in_view_viewport(cme.pos)) + { + const coord_def dest = view2grid(cme.pos); + if (cme.left_clicked()) + { + if (in_bounds(dest)) + start_travel(dest.x, dest.y); + } + else if (cme.right_clicked()) + { + if (see_grid(dest.x, dest.y)) + full_describe_square(dest); + else + mpr("You can't see that place."); + } + } + break; + } + case CMD_DISPLAY_CHARACTER_STATUS: display_char_status(); break; @@ -2668,6 +2698,9 @@ command_type keycode_to_command( keycode_type key ) case CONTROL('W'): return CMD_FIX_WAYPOINT; case CONTROL('X'): return CMD_SAVE_GAME_NOW; case CONTROL('Z'): return CMD_SUSPEND_GAME; + + case CK_MOUSE_MOVE: return CMD_MOUSE_MOVE; + case CK_MOUSE_CLICK: return CMD_MOUSE_CLICK; default: return CMD_NO_CMD; } } diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index e5a11f1f2f..5027becf19 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -34,6 +34,7 @@ #include "externs.h" +#include "cio.h" #include "cloud.h" #include "effects.h" #include "enum.h" diff --git a/crawl-ref/source/cio.cc b/crawl-ref/source/cio.cc new file mode 100644 index 0000000000..d22729a7fa --- /dev/null +++ b/crawl-ref/source/cio.cc @@ -0,0 +1,582 @@ +/* + * File: cio.cc + * Summary: Platform-independent console IO functions. + * + * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-14T18:14:26.828542Z $ + */ + +#include "AppHdr.h" + +#include "cio.h" +#include "externs.h" +#include "macro.h" + +#include + +#ifdef UNIX +static keycode_type numpad2vi(keycode_type key) +{ + if (key >= '1' && key <= '9') + { + const char *vikeys = "bjnh.lyku"; + return keycode_type(vikeys[key - '1']); + } + return (key); +} +#endif + +int unmangle_direction_keys(int keyin, int km, bool fake_ctrl, bool fake_shift) +{ + const KeymapContext keymap = static_cast(km); +#ifdef UNIX + // Kludging running and opening as two character sequences + // for Unix systems. This is an easy way out... all the + // player has to do is find a termcap and numlock setting + // that will get curses the numbers from the keypad. This + // will hopefully be easy. + + /* can we say yuck? -- haranp */ + if (fake_ctrl && keyin == '*') + { + keyin = getchm(keymap); + // return control-key + keyin = CONTROL(toupper(numpad2vi(keyin))); + } + else if (fake_shift && keyin == '/') + { + keyin = getchm(keymap); + // return shift-key + keyin = toupper(numpad2vi(keyin)); + } +#else + // Old DOS keypad support + if (keyin == 0) + { + /* FIXME haranp - hackiness */ + const char DOSidiocy[10] = { "OPQKSMGHI" }; + const char DOSunidiocy[10] = { "bjnh.lyku" }; + const int DOScontrolidiocy[9] = + { + 117, 145, 118, 115, 76, 116, 119, 141, 132 + }; + keyin = getchm(keymap); + for (int j = 0; j < 9; ++j ) + { + if (keyin == DOSidiocy[j]) + { + keyin = DOSunidiocy[j]; + break; + } + if (keyin == DOScontrolidiocy[j]) + { + keyin = CONTROL(toupper(DOSunidiocy[j])); + break; + } + } + } +#endif + + // [dshaligram] More lovely keypad mangling. + switch (keyin) + { +#ifdef UNIX + case '1': return 'b'; + case '2': return 'j'; + case '3': return 'n'; + case '4': return 'h'; + case '6': return 'l'; + case '7': return 'y'; + case '8': return 'k'; + case '9': return 'u'; +#else + case '1': return 'B'; + case '2': return 'J'; + case '3': return 'N'; + case '4': return 'H'; + case '6': return 'L'; + case '7': return 'Y'; + case '8': return 'K'; + case '9': return 'U'; +#endif + } + + return (keyin); +} + +void get_input_line( char *const buff, int len ) +{ + buff[0] = 0; // just in case + +#if defined(UNIX) + get_input_line_from_curses( buff, len ); // implemented in libunix.cc +#elif defined(WIN32CONSOLE) + getstr( buff, len ); +#else + + // [dshaligram] Turn on the cursor for DOS. +#ifdef DOS + _setcursortype(_NORMALCURSOR); +#endif + + fgets( buff, len, stdin ); // much safer than gets() +#endif + + buff[ len - 1 ] = 0; // just in case + + // Removing white space from the end in order to get rid of any + // newlines or carriage returns that any of the above might have + // left there (ie fgets especially). -- bwr + const int end = strlen( buff ); + int i; + + for (i = end - 1; i >= 0; i++) + { + if (isspace( buff[i] )) + buff[i] = 0; + else + break; + } +} + +// Hacky wrapper around getch() that returns CK_ codes for keys +// we want to use in cancelable_get_line() and menus. +int c_getch() +{ +#if defined(DOS) || defined(UNIX) || defined(WIN32CONSOLE) + return getch_ck(); +#else + return m_getch(); +#endif +} + +// Wrapper around gotoxy that can draw a fake cursor for Unix terms where +// cursoring over darkgray or black causes problems. +void cursorxy(int x, int y) +{ +#ifdef UNIX + if (Options.use_fake_cursor) + fakecursorxy(x, y); + else + gotoxy(x, y); +#else + gotoxy(x, y); +#endif +} + +// cprintf that knows how to wrap down lines (primitive, but what the heck) +int wrapcprintf( int wrapcol, const char *s, ... ) +{ + char buf[1000]; // Hard max + va_list args; + va_start(args, s); + + // XXX: If snprintf isn't available, vsnprintf probably isn't, either. + int len = vsnprintf(buf, sizeof buf, s, args); + int olen = len; + va_end(args); + + char *run = buf; + while (len > 0) + { + int x = wherex(), y = wherey(); + + if (x > wrapcol) // Somebody messed up! + return 0; + + int avail = wrapcol - x + 1; + int c = 0; + if (len > avail) + { + c = run[avail]; + run[avail] = 0; + } + cprintf("%s", run); + + if (len > avail) + run[avail] = c; + + if ((len -= avail) > 0) + gotoxy(1, y + 1); + run += avail; + } + return (olen); +} + +int cancelable_get_line( char *buf, int len, int maxcol, + input_history *mh, int (*keyproc)(int &ch) ) +{ + line_reader reader(buf, len, maxcol); + reader.set_input_history(mh); + reader.set_keyproc(keyproc); + + return reader.read_line(); +} + + +///////////////////////////////////////////////////////////// +// input_history +// + +input_history::input_history(size_t size) + : history(), pos(), maxsize(size) +{ + if (maxsize < 2) + maxsize = 2; + + pos = history.end(); +} + +void input_history::new_input(const std::string &s) +{ + history.remove(s); + + if (history.size() == maxsize) + history.pop_front(); + + history.push_back(s); + + // Force the iterator to the end (also revalidates it) + go_end(); +} + +const std::string *input_history::prev() +{ + if (history.empty()) + return NULL; + + if (pos == history.begin()) + pos = history.end(); + + return &*--pos; +} + +const std::string *input_history::next() +{ + if (history.empty()) + return NULL; + + if (pos == history.end() || ++pos == history.end()) + pos = history.begin(); + + return &*pos; +} + +void input_history::go_end() +{ + pos = history.end(); +} + +void input_history::clear() +{ + history.clear(); + go_end(); +} + +///////////////////////////////////////////////////////////////////////// +// line_reader + +line_reader::line_reader(char *buf, size_t sz, int wrap) + : buffer(buf), bufsz(sz), history(NULL), start_x(0), + start_y(0), keyfn(NULL), wrapcol(wrap), cur(NULL), + length(0), pos(-1) +{ +} + +std::string line_reader::get_text() const +{ + return (buffer); +} + +void line_reader::set_input_history(input_history *i) +{ + history = i; +} + +void line_reader::set_keyproc(keyproc fn) +{ + keyfn = fn; +} + +void line_reader::cursorto(int ncx) +{ + int x = (start_x + ncx - 1) % wrapcol + 1; + int y = start_y + (start_x + ncx - 1) / wrapcol; + ::gotoxy(x, y); +} + +int line_reader::read_line(bool clear_previous) +{ + if (bufsz <= 0) return false; + + cursor_control coff(true); + + if (clear_previous) + *buffer = 0; + + start_x = wherex(); + start_y = wherey(); + + length = strlen(buffer); + + // Remember the previous cursor position, if valid. + if (pos < 0 || pos > length) + pos = length; + + cur = buffer + pos; + + if (length) + wrapcprintf(wrapcol, "%s", buffer); + + if (pos != length) + cursorto(pos); + + if (history) + history->go_end(); + + for ( ; ; ) + { + int ch = c_getch(); + + if (keyfn) + { + int whattodo = (*keyfn)(ch); + if (whattodo == 0) + { + buffer[length] = 0; + if (history && length) + history->new_input(buffer); + return (0); + } + else if (whattodo == -1) + { + buffer[length] = 0; + return (ch); + } + } + + int ret = process_key(ch); + if (ret != -1) + return (ret); + } +} + +void line_reader::backspace() +{ + if (pos) + { + --cur; + char *c = cur; + while (*c) + { + *c = c[1]; + c++; + } + --pos; + --length; + + cursorto(pos); + buffer[length] = 0; + wrapcprintf( wrapcol, "%s ", cur ); + cursorto(pos); + } +} + +bool line_reader::is_wordchar(int c) +{ + return isalnum(c) || c == '_' || c == '-'; +} + +void line_reader::killword() +{ + if (!pos || cur == buffer) + return; + + bool foundwc = false; + while (pos) + { + if (is_wordchar(cur[-1])) + foundwc = true; + else if (foundwc) + break; + + backspace(); + } +} + +int line_reader::process_key(int ch) +{ + switch (ch) + { + case CONTROL('G'): + case CK_ESCAPE: + return (CK_ESCAPE); + case CK_UP: + case CK_DOWN: + { + if (!history) + break; + + const std::string *text = + ch == CK_UP? history->prev() : history->next(); + + if (text) + { + int olen = length; + length = text->length(); + if (length >= (int) bufsz) + length = bufsz - 1; + memcpy(buffer, text->c_str(), length); + buffer[length] = 0; + cursorto(0); + + int clear = length < olen? olen - length : 0; + wrapcprintf(wrapcol, "%s%*s", buffer, clear, ""); + + pos = length; + cur = buffer + pos; + cursorto(pos); + } + break; + } + case CK_ENTER: + buffer[length] = 0; + if (history && length) + history->new_input(buffer); + return (0); + + case CONTROL('K'): + { + // Kill to end of line + int erase = length - pos; + if (erase) + { + length = pos; + buffer[length] = 0; + wrapcprintf( wrapcol, "%*s", erase, "" ); + cursorto(pos); + } + break; + } + case CK_DELETE: + if (pos < length) + { + char *c = cur; + while (c - buffer < length) + { + *c = c[1]; + c++; + } + --length; + + cursorto(pos); + buffer[length] = 0; + wrapcprintf( wrapcol, "%s ", cur ); + cursorto(pos); + } + break; + + case CK_BKSP: + backspace(); + break; + + case CONTROL('W'): + killword(); + break; + + case CK_LEFT: + if (pos) + { + --pos; + cur = buffer + pos; + cursorto(pos); + } + break; + case CK_RIGHT: + if (pos < length) + { + ++pos; + cur = buffer + pos; + cursorto(pos); + } + break; + case CK_HOME: + case CONTROL('A'): + pos = 0; + cur = buffer + pos; + cursorto(pos); + break; + case CK_END: + case CONTROL('E'): + pos = length; + cur = buffer + pos; + cursorto(pos); + break; + default: + if (isprint(ch) && length < (int) bufsz - 1) + { + if (pos < length) + { + char *c = buffer + length - 1; + while (c >= cur) + { + c[1] = *c; + c--; + } + } + *cur++ = (char) ch; + ++length; + ++pos; + putch(ch); + if (pos < length) + { + buffer[length] = 0; + wrapcprintf( wrapcol, "%s", cur ); + } + cursorto(pos); + } + break; + } + + return (-1); +} + +///////////////////////////////////////////////////////////////////////////// +// Of mice and other mice. + +static std::queue mouse_events; + +coord_def get_mouse_pos() +{ + // lib$(OS) has to maintain mousep. This function is just the messenger. + return (crawl_view.mousep); +} + +c_mouse_event get_mouse_event() +{ + if (mouse_events.empty()) + return c_mouse_event(); + + c_mouse_event ce = mouse_events.front(); + mouse_events.pop(); + return (ce); +} + +void new_mouse_event(const c_mouse_event &ce) +{ + mouse_events.push(ce); +} + +void flush_mouse_events() +{ + while (!mouse_events.empty()) + mouse_events.pop(); +} + +void c_input_reset(bool enable_mouse, bool flush) +{ + crawl_state.mouse_enabled = (enable_mouse && Options.mouse_input); + set_mouse_enabled(crawl_state.mouse_enabled); + + if (flush) + flush_mouse_events(); +} diff --git a/crawl-ref/source/cio.h b/crawl-ref/source/cio.h new file mode 100644 index 0000000000..552ea1b699 --- /dev/null +++ b/crawl-ref/source/cio.h @@ -0,0 +1,226 @@ +/* + * File: cio.h + * Summary: System independent console IO functions + * + * Modified for Crawl Reference by $Author: dshaligram $ on $Date: 2007-06-14T18:14:26.828542Z $ + */ + +#ifndef CIO_H +#define CIO_H + +#include "AppHdr.h" +#include "externs.h" +#include "defines.h" +#include +#include +#include + +void cursorxy(int x, int y); + +// Read one key, flag it as a mouse event if appropriate, but apply no +// other conversions. Defined in lib$OS.cc, not in cio.cc. +int m_getch(); + +// A getch() that flags mouse events and returns a consistent set of key codes +// for all platforms for a small subset of the keys Crawl is interested in. +int c_getch(); + +// Converts a key to a direction key, converting keypad and other sequences +// to vi key sequences (shifted/control key directions are also handled). Non +// direction keys (hopefully) pass through unmangled. +int unmangle_direction_keys(int keyin, int keymap = 0, + bool fake_ctrl = true, bool fake_shift = true); + +void get_input_line( char *const buff, int len ); + +// In view.cc, declared here for default argument to cancelable_get_line() +int get_number_of_cols(void); + +class input_history; +// Returns zero if user entered text and pressed Enter, otherwise returns the +// key pressed that caused the exit, usually Escape. +// +// If keyproc is provided, it must return 1 for normal processing, 0 to exit +// normally (pretend the user pressed Enter), or -1 to exit as if the user +// pressed Escape +int cancelable_get_line( char *buf, + int len, + int wrapcol = get_number_of_cols(), + input_history *mh = NULL, + int (*keyproc)(int &c) = NULL ); + +struct c_mouse_event +{ + coord_def pos; + int bstate; + + enum button_state_type + { + BUTTON1 = 0x1, + BUTTON1_DBL = 0x2, + BUTTON2 = 0x4, + BUTTON2_DBL = 0x8, + BUTTON3 = 0x10, + BUTTON3_DBL = 0x20, + BUTTON4 = 0x40, + BUTTON4_DBL = 0x80, + BUTTON_SCRL_UP = 0x100, + BUTTON_SCRL_DN = 0x200 + }; + + c_mouse_event() : pos(-1, -1), bstate(0) + { + } + + c_mouse_event(const coord_def &c, int state = 0) : pos(c), bstate(state) + { + } + + // Returns true for valid events. + operator bool () const + { + return (bstate); + } + + bool left_clicked() const + { + return (bstate & BUTTON1); + } + + bool right_clicked() const + { + return (bstate & BUTTON3); + } + + bool scroll_up() const + { + return (bstate & (BUTTON4 | BUTTON4_DBL | BUTTON_SCRL_UP)); + } + + bool scroll_down() const + { + return (bstate & (BUTTON2 | BUTTON2_DBL | BUTTON_SCRL_DN)); + } +}; + +coord_def get_mouse_pos(); +c_mouse_event get_mouse_event(); +void new_mouse_event(const c_mouse_event &ce); +void flush_mouse_events(); +void c_input_reset(bool enable_mouse, bool flush = false); + +// Keys that getch() must return for keys Crawl is interested in. +enum KEYS +{ + CK_ENTER = '\r', + CK_BKSP = 8, + CK_ESCAPE = ESCAPE, + + // 128 is off-limits because it's the code that's used when running + CK_DELETE = 129, + + // This sequence of enums should not be rearranged. + CK_UP, + CK_DOWN, + CK_LEFT, + CK_RIGHT, + + CK_INSERT, + + CK_HOME, + CK_END, + CK_CLEAR, + + CK_PGUP, + CK_PGDN, + + CK_SHIFT_UP, + CK_SHIFT_DOWN, + CK_SHIFT_LEFT, + CK_SHIFT_RIGHT, + + CK_SHIFT_INSERT, + + CK_SHIFT_HOME, + CK_SHIFT_END, + CK_SHIFT_CLEAR, + + CK_SHIFT_PGUP, + CK_SHIFT_PGDN, + + CK_CTRL_UP, + CK_CTRL_DOWN, + CK_CTRL_LEFT, + CK_CTRL_RIGHT, + + CK_CTRL_INSERT, + + CK_CTRL_HOME, + CK_CTRL_END, + CK_CTRL_CLEAR, + + CK_CTRL_PGUP, + CK_CTRL_PGDN, + + // Mouse codes. + CK_MOUSE_MOVE = 10001, + CK_MOUSE_CLICK +}; + +class cursor_control +{ +public: + cursor_control(bool cursor_enabled) + : cstate(is_cursor_enabled()), smartcstate(is_smart_cursor_enabled()) + { + enable_smart_cursor(false); + set_cursor_enabled(cursor_enabled); + } + ~cursor_control() { + set_cursor_enabled(cstate); + enable_smart_cursor(smartcstate); + } +private: + bool cstate; + bool smartcstate; +}; + +// Reads lines of text; used internally by cancelable_get_line. +class line_reader +{ +public: + line_reader(char *buffer, size_t bufsz, + int wrap_col = get_number_of_cols()); + + typedef int (*keyproc)(int &key); + + int read_line(bool clear_previous = true); + + std::string get_text() const; + + void set_input_history(input_history *ih); + void set_keyproc(keyproc fn); + +protected: + void cursorto(int newcpos); + int process_key(int ch); + void backspace(); + void killword(); + + bool is_wordchar(int c); + +private: + char *buffer; + size_t bufsz; + input_history *history; + int start_x, start_y; + keyproc keyfn; + int wrapcol; + + // These are subject to change during editing. + char *cur; + int length; + int pos; +}; + +#endif diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc index 9140cf5d2b..fb36672fe9 100644 --- a/crawl-ref/source/clua.cc +++ b/crawl-ref/source/clua.cc @@ -9,6 +9,7 @@ #include "abl-show.h" #include "command.h" #include "chardump.h" +#include "cio.h" #include "delay.h" #include "food.h" #include "invent.h" diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc index a40a3c4492..4f7badcd30 100644 --- a/crawl-ref/source/debug.cc +++ b/crawl-ref/source/debug.cc @@ -37,6 +37,7 @@ #include "externs.h" #include "branch.h" +#include "cio.h" #include "decks.h" #include "describe.h" #include "direct.h" diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 5b2ebf3f55..e6da1565ff 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -32,6 +32,7 @@ #include "externs.h" +#include "cio.h" #include "command.h" #include "debug.h" #include "describe.h" @@ -416,7 +417,7 @@ void direction(dist& moves, targeting_type restricts, const int old_tx = moves.tx + (skip_iter ? 500 : 0); // hmmm...hack const int old_ty = moves.ty; - int i, mid, oid; + int i, mid; switch ( key_command ) { @@ -628,32 +629,8 @@ void direction(dist& moves, targeting_type restricts, #endif case CMD_TARGET_DESCRIBE: - // Don't give out information for things outside LOS - if (!see_grid(moves.tx, moves.ty)) - break; - - mid = mgrd[moves.tx][moves.ty]; - oid = igrd[moves.tx][moves.ty]; - - if (mid != NON_MONSTER && player_monster_visible(&menv[mid])) - { - // First priority: monsters - describe_monsters(menv[mid]); - } - else if (oid != NON_ITEM) - { - // Second priority: objects - describe_item( mitm[oid] ); - } - else - { - // Third priority: features - describe_feature_wide(moves.tx, moves.ty); - } - + full_describe_square(moves.target()); force_redraw = true; - redraw_screen(); - mesclr(true); break; case CMD_TARGET_HELP: @@ -735,10 +712,7 @@ void direction(dist& moves, targeting_type restricts, if ( !skip_iter ) // don't clear before we get a chance to see mesclr(true); // maybe not completely necessary - if ( !in_vlos(grid2viewX(moves.tx), grid2viewY(moves.ty)) ) - describe_oos_square(moves.tx, moves.ty); - else if ( in_bounds(moves.tx, moves.ty) ) - describe_cell(moves.tx, moves.ty); + terse_describe_square(moves.target()); } if ( need_beam_redraw ) @@ -776,6 +750,43 @@ void direction(dist& moves, targeting_type restricts, extend_move_to_edge(moves); } +void terse_describe_square(const coord_def &c) +{ + if (!see_grid(c.x, c.y)) + describe_oos_square(c.x, c.y); + else if (in_bounds(c) ) + describe_cell(c.x, c.y); +} + +void full_describe_square(const coord_def &c) +{ + // Don't give out information for things outside LOS + if (!see_grid(c.x, c.y)) + return; + + const int mid = mgrd(c); + const int oid = igrd(c); + + if (mid != NON_MONSTER && player_monster_visible(&menv[mid])) + { + // First priority: monsters + describe_monsters(menv[mid]); + } + else if (oid != NON_ITEM) + { + // Second priority: objects + describe_item( mitm[oid] ); + } + else + { + // Third priority: features + describe_feature_wide(c.x, c.y); + } + + redraw_screen(); + mesclr(true); +} + static void extend_move_to_edge(dist &moves) { if (!moves.dx && !moves.dy) diff --git a/crawl-ref/source/direct.h b/crawl-ref/source/direct.h index 8f2c243955..54b7a4821d 100644 --- a/crawl-ref/source/direct.h +++ b/crawl-ref/source/direct.h @@ -33,6 +33,8 @@ bool in_los(int x, int y); bool in_vlos(int x, int y); bool in_vlos(const coord_def &pos); +void terse_describe_square(const coord_def &c); +void full_describe_square(const coord_def &c); void describe_floor(); int dos_direction_unmunge(int doskey); diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index a86a978218..e86dcc2a0e 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -661,6 +661,9 @@ enum command_type CMD_RESISTS_SCREEN, CMD_READ_MESSAGES, + + CMD_MOUSE_MOVE, + CMD_MOUSE_CLICK, /* overmap commands */ CMD_MAP_CLEAR_MAP, diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 9271c72dea..53165a8240 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -1185,6 +1185,8 @@ extern struct crawl_environment env; // Track various aspects of Crawl game state. struct game_state { + bool mouse_enabled; // True if mouse input is currently relevant. + bool waiting_for_command; // True when the game is waiting for a command. bool terminal_resized; // True if the term was resized and we need to // take action to handle it. @@ -1204,11 +1206,12 @@ struct game_state void (*terminal_resize_handler)(); void (*terminal_resize_check)(); - game_state() : waiting_for_command(false), terminal_resized(false), - io_inited(false), need_save(false), saving_game(false), - updating_scores(false), shopping(false), seen_hups(0), - unicode_ok(false), glyph2strfn(NULL), multibyte_strlen(NULL), - terminal_resize_handler(NULL), terminal_resize_check(NULL) + game_state() : mouse_enabled(false), waiting_for_command(false), + terminal_resized(false), io_inited(false), need_save(false), + saving_game(false), updating_scores(false), shopping(false), + seen_hups(0), unicode_ok(false), glyph2strfn(NULL), + multibyte_strlen(NULL), terminal_resize_handler(NULL), + terminal_resize_check(NULL) { } @@ -1289,6 +1292,8 @@ public: coord_def glos1, glos2; // LOS limit grid coords (inclusive) coord_def vlos1, vlos2; // LOS limit viewport coords (inclusive) + coord_def mousep; // Where the mouse is. + static const int message_min_lines = 7; static const int hud_min_width = 41; static const int hud_min_gutter = 3; @@ -1458,6 +1463,8 @@ public: bool messaging; // Check for messages. #endif + bool mouse_input; + int view_max_width; int view_max_height; diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 6fb3700514..3662b31a1a 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -559,6 +559,8 @@ void game_options::reset_options() messaging = true; #endif + mouse_input = false; + view_max_width = VIEW_BASE_WIDTH; view_max_height = VIEW_MIN_HEIGHT; @@ -1873,6 +1875,10 @@ void game_options::read_option_line(const std::string &str, bool runscript) messaging = read_bool(field, messaging); } #endif + else if (key == "mouse_input") + { + mouse_input = read_bool(field, mouse_input); + } else if (key == "view_max_width") { view_max_width = atoi(field.c_str()); diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc index 271852cd2d..0db383d21e 100644 --- a/crawl-ref/source/item_use.cc +++ b/crawl-ref/source/item_use.cc @@ -35,6 +35,7 @@ #include "externs.h" #include "beam.h" +#include "cio.h" #include "debug.h" #include "delay.h" #include "describe.h" diff --git a/crawl-ref/source/libdos.cc b/crawl-ref/source/libdos.cc index 8c197e1c8e..02e1b7f85c 100644 --- a/crawl-ref/source/libdos.cc +++ b/crawl-ref/source/libdos.cc @@ -93,4 +93,38 @@ int get_number_of_cols() return (80); } +int getch_ck() +{ + int c = getch(); + if (!c) + { + switch (c = getch()) + { + case 'O': return CK_END; + case 'P': return CK_DOWN; + case 'I': return CK_PGUP; + case 'H': return CK_UP; + case 'G': return CK_HOME; + case 'K': return CK_LEFT; + case 'Q': return CK_PGDN; + case 'M': return CK_RIGHT; + case 119: return CK_CTRL_HOME; + case 141: return CK_CTRL_UP; + case 132: return CK_CTRL_PGUP; + case 116: return CK_CTRL_RIGHT; + case 118: return CK_CTRL_PGDN; + case 145: return CK_CTRL_DOWN; + case 117: return CK_CTRL_END; + case 115: return CK_CTRL_LEFT; + case 'S': return CK_DELETE; + } + } + return c; +} + +int m_getch() +{ + return getch(); +} + #endif /* #if defined(DOS) */ diff --git a/crawl-ref/source/libdos.h b/crawl-ref/source/libdos.h index 6e2d3f16a6..fd6a0a0d92 100644 --- a/crawl-ref/source/libdos.h +++ b/crawl-ref/source/libdos.h @@ -11,6 +11,8 @@ inline bool is_smart_cursor_enabled() { return (false); } void set_cursor_enabled(bool enabled); bool is_cursor_enabled(); void clear_to_end_of_line(); +int getch_ck(); +void set_mouse_enabled(bool enabled) { } void message_out(int mline, int colour, const char *str, int firstcol = 0, bool newline = true); diff --git a/crawl-ref/source/libunix.cc b/crawl-ref/source/libunix.cc index 7af2b38f3e..84d0beaa80 100644 --- a/crawl-ref/source/libunix.cc +++ b/crawl-ref/source/libunix.cc @@ -43,6 +43,7 @@ #include "libunix.h" #include "defines.h" +#include "cio.h" #include "enum.h" #include "externs.h" #include "files.h" @@ -225,10 +226,83 @@ static void termio_init() crawl_state.terminal_resize_handler = unix_handle_terminal_resize; } +void set_mouse_enabled(bool enabled) +{ +#ifdef NCURSES_MOUSE_VERSION + const int mask = enabled? ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION : 0; + mousemask(mask, NULL); +#endif +} + +#ifdef NCURSES_MOUSE_VERSION +static int proc_mouse_event(int c, const MEVENT *me) +{ + crawl_view.mousep.x = me->x + 1; + crawl_view.mousep.y = me->y + 1; + + if (!crawl_state.mouse_enabled) + return (CK_MOUSE_MOVE); + + c_mouse_event cme(crawl_view.mousep); + if (me->bstate & BUTTON1_CLICKED) + cme.bstate |= c_mouse_event::BUTTON1; + else if (me->bstate & BUTTON1_DOUBLE_CLICKED) + cme.bstate |= c_mouse_event::BUTTON1_DBL; + else if (me->bstate & BUTTON2_CLICKED) + cme.bstate |= c_mouse_event::BUTTON2; + else if (me->bstate & BUTTON2_DOUBLE_CLICKED) + cme.bstate |= c_mouse_event::BUTTON2_DBL; + else if (me->bstate & BUTTON3_CLICKED) + cme.bstate |= c_mouse_event::BUTTON3; + else if (me->bstate & BUTTON3_DOUBLE_CLICKED) + cme.bstate |= c_mouse_event::BUTTON3_DBL; + else if (me->bstate & BUTTON4_CLICKED) + cme.bstate |= c_mouse_event::BUTTON4; + else if (me->bstate & BUTTON4_DOUBLE_CLICKED) + cme.bstate |= c_mouse_event::BUTTON4_DBL; + + if (cme) + { + new_mouse_event(cme); + return (CK_MOUSE_CLICK); + } + + return (CK_MOUSE_MOVE); +} +#endif + +static int raw_m_getch() +{ + const int c = getch(); + switch (c) + { +#ifdef NCURSES_MOUSE_VERSION + case KEY_MOUSE: + { + MEVENT me; + getmouse(&me); + return (proc_mouse_event(c, &me)); + } +#endif + default: + return (c); + } +} + +int m_getch() +{ + int c; + do + c = raw_m_getch(); + while ((c == CK_MOUSE_MOVE || c == CK_MOUSE_CLICK) + && !crawl_state.mouse_enabled); + + return (c); +} int getch_ck() { - int c = getch(); + int c = m_getch(); switch (c) { // [dshaligram] MacOS ncurses returns 127 for backspace. @@ -389,6 +463,8 @@ void unixcurses_startup( void ) crawl_view.init_geometry(); setup_message_window(); + + set_mouse_enabled(false); } void unixcurses_shutdown() diff --git a/crawl-ref/source/libunix.h b/crawl-ref/source/libunix.h index 42d9ba9449..03d63a8be4 100644 --- a/crawl-ref/source/libunix.h +++ b/crawl-ref/source/libunix.h @@ -51,6 +51,8 @@ bool is_cursor_enabled(); inline void enable_smart_cursor(bool) { } inline bool is_smart_cursor_enabled() { return (false); } +void set_mouse_enabled(bool enabled); + #ifndef _LIBUNIX_IMPLEMENTATION /* Some stuff from curses, to remove compiling warnings.. */ extern "C" diff --git a/crawl-ref/source/libutil.cc b/crawl-ref/source/libutil.cc index 27d28e6e7a..98dd7f598f 100644 --- a/crawl-ref/source/libutil.cc +++ b/crawl-ref/source/libutil.cc @@ -46,96 +46,6 @@ #include #endif -#ifdef UNIX -static keycode_type numpad2vi(keycode_type key) -{ - if (key >= '1' && key <= '9') - { - const char *vikeys = "bjnh.lyku"; - return keycode_type(vikeys[key - '1']); - } - return (key); -} -#endif - -int unmangle_direction_keys(int keyin, int km, bool fake_ctrl, bool fake_shift) -{ - const KeymapContext keymap = static_cast(km); -#ifdef UNIX - // Kludging running and opening as two character sequences - // for Unix systems. This is an easy way out... all the - // player has to do is find a termcap and numlock setting - // that will get curses the numbers from the keypad. This - // will hopefully be easy. - - /* can we say yuck? -- haranp */ - if (fake_ctrl && keyin == '*') - { - keyin = getchm(keymap); - // return control-key - keyin = CONTROL(toupper(numpad2vi(keyin))); - } - else if (fake_shift && keyin == '/') - { - keyin = getchm(keymap); - // return shift-key - keyin = toupper(numpad2vi(keyin)); - } -#else - // Old DOS keypad support - if (keyin == 0) - { - /* FIXME haranp - hackiness */ - const char DOSidiocy[10] = { "OPQKSMGHI" }; - const char DOSunidiocy[10] = { "bjnh.lyku" }; - const int DOScontrolidiocy[9] = - { - 117, 145, 118, 115, 76, 116, 119, 141, 132 - }; - keyin = getchm(keymap); - for (int j = 0; j < 9; ++j ) - { - if (keyin == DOSidiocy[j]) - { - keyin = DOSunidiocy[j]; - break; - } - if (keyin == DOScontrolidiocy[j]) - { - keyin = CONTROL(toupper(DOSunidiocy[j])); - break; - } - } - } -#endif - - // [dshaligram] More lovely keypad mangling. - switch (keyin) - { -#ifdef UNIX - case '1': return 'b'; - case '2': return 'j'; - case '3': return 'n'; - case '4': return 'h'; - case '6': return 'l'; - case '7': return 'y'; - case '8': return 'k'; - case '9': return 'u'; -#else - case '1': return 'B'; - case '2': return 'J'; - case '3': return 'N'; - case '4': return 'H'; - case '6': return 'L'; - case '7': return 'Y'; - case '8': return 'K'; - case '9': return 'U'; -#endif - } - - return (keyin); -} - // Should return true if the filename contains nothing that // the shell can do damage with. bool shell_safe(const char *file) @@ -321,146 +231,6 @@ int count_occurrences(const std::string &text, const std::string &s) return (nfound); } -void get_input_line( char *const buff, int len ) -{ - buff[0] = 0; // just in case - -#if defined(UNIX) - get_input_line_from_curses( buff, len ); // implemented in libunix.cc -#elif defined(WIN32CONSOLE) - getstr( buff, len ); -#else - - // [dshaligram] Turn on the cursor for DOS. -#ifdef DOS - _setcursortype(_NORMALCURSOR); -#endif - - fgets( buff, len, stdin ); // much safer than gets() -#endif - - buff[ len - 1 ] = 0; // just in case - - // Removing white space from the end in order to get rid of any - // newlines or carriage returns that any of the above might have - // left there (ie fgets especially). -- bwr - const int end = strlen( buff ); - int i; - - for (i = end - 1; i >= 0; i++) - { - if (isspace( buff[i] )) - buff[i] = 0; - else - break; - } -} - -#ifdef DOS -static int getch_ck() -{ - int c = getch(); - if (!c) - { - switch (c = getch()) - { - case 'O': return CK_END; - case 'P': return CK_DOWN; - case 'I': return CK_PGUP; - case 'H': return CK_UP; - case 'G': return CK_HOME; - case 'K': return CK_LEFT; - case 'Q': return CK_PGDN; - case 'M': return CK_RIGHT; - case 119: return CK_CTRL_HOME; - case 141: return CK_CTRL_UP; - case 132: return CK_CTRL_PGUP; - case 116: return CK_CTRL_RIGHT; - case 118: return CK_CTRL_PGDN; - case 145: return CK_CTRL_DOWN; - case 117: return CK_CTRL_END; - case 115: return CK_CTRL_LEFT; - case 'S': return CK_DELETE; - } - } - return c; -} -#endif - -// Hacky wrapper around getch() that returns CK_ codes for keys -// we want to use in cancelable_get_line() and menus. -int c_getch() -{ -#if defined(DOS) || defined(UNIX) || defined(WIN32CONSOLE) - return getch_ck(); -#else - return getch(); -#endif -} - -// Wrapper around gotoxy that can draw a fake cursor for Unix terms where -// cursoring over darkgray or black causes problems. -void cursorxy(int x, int y) -{ -#ifdef UNIX - if (Options.use_fake_cursor) - fakecursorxy(x, y); - else - gotoxy(x, y); -#else - gotoxy(x, y); -#endif -} - -// cprintf that knows how to wrap down lines (primitive, but what the heck) -int wrapcprintf( int wrapcol, const char *s, ... ) -{ - char buf[1000]; // Hard max - va_list args; - va_start(args, s); - - // XXX: If snprintf isn't available, vsnprintf probably isn't, either. - int len = vsnprintf(buf, sizeof buf, s, args); - int olen = len; - va_end(args); - - char *run = buf; - while (len > 0) - { - int x = wherex(), y = wherey(); - - if (x > wrapcol) // Somebody messed up! - return 0; - - int avail = wrapcol - x + 1; - int c = 0; - if (len > avail) - { - c = run[avail]; - run[avail] = 0; - } - cprintf("%s", run); - - if (len > avail) - run[avail] = c; - - if ((len -= avail) > 0) - gotoxy(1, y + 1); - run += avail; - } - return (olen); -} - -int cancelable_get_line( char *buf, int len, int maxcol, - input_history *mh, int (*keyproc)(int &ch) ) -{ - line_reader reader(buf, len, maxcol); - reader.set_input_history(mh); - reader.set_keyproc(keyproc); - - return reader.read_line(); -} - std::string trimmed_string( std::string s ) { trim_string(s); @@ -724,331 +494,3 @@ bool pattern_match(void *compiled_pattern, const char *text, int length) //////////////////////////////////////////////////////////////////// #endif - - -///////////////////////////////////////////////////////////// -// input_history -// - -input_history::input_history(size_t size) - : history(), pos(), maxsize(size) -{ - if (maxsize < 2) - maxsize = 2; - - pos = history.end(); -} - -void input_history::new_input(const std::string &s) -{ - history.remove(s); - - if (history.size() == maxsize) - history.pop_front(); - - history.push_back(s); - - // Force the iterator to the end (also revalidates it) - go_end(); -} - -const std::string *input_history::prev() -{ - if (history.empty()) - return NULL; - - if (pos == history.begin()) - pos = history.end(); - - return &*--pos; -} - -const std::string *input_history::next() -{ - if (history.empty()) - return NULL; - - if (pos == history.end() || ++pos == history.end()) - pos = history.begin(); - - return &*pos; -} - -void input_history::go_end() -{ - pos = history.end(); -} - -void input_history::clear() -{ - history.clear(); - go_end(); -} - -///////////////////////////////////////////////////////////////////////// -// line_reader - -line_reader::line_reader(char *buf, size_t sz, int wrap) - : buffer(buf), bufsz(sz), history(NULL), start_x(0), - start_y(0), keyfn(NULL), wrapcol(wrap), cur(NULL), - length(0), pos(-1) -{ -} - -std::string line_reader::get_text() const -{ - return (buffer); -} - -void line_reader::set_input_history(input_history *i) -{ - history = i; -} - -void line_reader::set_keyproc(keyproc fn) -{ - keyfn = fn; -} - -void line_reader::cursorto(int ncx) -{ - int x = (start_x + ncx - 1) % wrapcol + 1; - int y = start_y + (start_x + ncx - 1) / wrapcol; - ::gotoxy(x, y); -} - -int line_reader::read_line(bool clear_previous) -{ - if (bufsz <= 0) return false; - - cursor_control coff(true); - - if (clear_previous) - *buffer = 0; - - start_x = wherex(); - start_y = wherey(); - - length = strlen(buffer); - - // Remember the previous cursor position, if valid. - if (pos < 0 || pos > length) - pos = length; - - cur = buffer + pos; - - if (length) - wrapcprintf(wrapcol, "%s", buffer); - - if (pos != length) - cursorto(pos); - - if (history) - history->go_end(); - - for ( ; ; ) - { - int ch = c_getch(); - - if (keyfn) - { - int whattodo = (*keyfn)(ch); - if (whattodo == 0) - { - buffer[length] = 0; - if (history && length) - history->new_input(buffer); - return (0); - } - else if (whattodo == -1) - { - buffer[length] = 0; - return (ch); - } - } - - int ret = process_key(ch); - if (ret != -1) - return (ret); - } -} - -void line_reader::backspace() -{ - if (pos) - { - --cur; - char *c = cur; - while (*c) - { - *c = c[1]; - c++; - } - --pos; - --length; - - cursorto(pos); - buffer[length] = 0; - wrapcprintf( wrapcol, "%s ", cur ); - cursorto(pos); - } -} - -bool line_reader::is_wordchar(int c) -{ - return isalnum(c) || c == '_' || c == '-'; -} - -void line_reader::killword() -{ - if (!pos || cur == buffer) - return; - - bool foundwc = false; - while (pos) - { - if (is_wordchar(cur[-1])) - foundwc = true; - else if (foundwc) - break; - - backspace(); - } -} - -int line_reader::process_key(int ch) -{ - switch (ch) - { - case CONTROL('G'): - case CK_ESCAPE: - return (CK_ESCAPE); - case CK_UP: - case CK_DOWN: - { - if (!history) - break; - - const std::string *text = - ch == CK_UP? history->prev() : history->next(); - - if (text) - { - int olen = length; - length = text->length(); - if (length >= (int) bufsz) - length = bufsz - 1; - memcpy(buffer, text->c_str(), length); - buffer[length] = 0; - cursorto(0); - - int clear = length < olen? olen - length : 0; - wrapcprintf(wrapcol, "%s%*s", buffer, clear, ""); - - pos = length; - cur = buffer + pos; - cursorto(pos); - } - break; - } - case CK_ENTER: - buffer[length] = 0; - if (history && length) - history->new_input(buffer); - return (0); - - case CONTROL('K'): - { - // Kill to end of line - int erase = length - pos; - if (erase) - { - length = pos; - buffer[length] = 0; - wrapcprintf( wrapcol, "%*s", erase, "" ); - cursorto(pos); - } - break; - } - case CK_DELETE: - if (pos < length) - { - char *c = cur; - while (c - buffer < length) - { - *c = c[1]; - c++; - } - --length; - - cursorto(pos); - buffer[length] = 0; - wrapcprintf( wrapcol, "%s ", cur ); - cursorto(pos); - } - break; - - case CK_BKSP: - backspace(); - break; - - case CONTROL('W'): - killword(); - break; - - case CK_LEFT: - if (pos) - { - --pos; - cur = buffer + pos; - cursorto(pos); - } - break; - case CK_RIGHT: - if (pos < length) - { - ++pos; - cur = buffer + pos; - cursorto(pos); - } - break; - case CK_HOME: - case CONTROL('A'): - pos = 0; - cur = buffer + pos; - cursorto(pos); - break; - case CK_END: - case CONTROL('E'): - pos = length; - cur = buffer + pos; - cursorto(pos); - break; - default: - if (isprint(ch) && length < (int) bufsz - 1) - { - if (pos < length) - { - char *c = buffer + length - 1; - while (c >= cur) - { - c[1] = *c; - c--; - } - } - *cur++ = (char) ch; - ++length; - ++pos; - putch(ch); - if (pos < length) - { - buffer[length] = 0; - wrapcprintf( wrapcol, "%s", cur ); - } - cursorto(pos); - } - break; - } - - return (-1); -} diff --git a/crawl-ref/source/libutil.h b/crawl-ref/source/libutil.h index e9d6d987b8..4eed5ab7a7 100644 --- a/crawl-ref/source/libutil.h +++ b/crawl-ref/source/libutil.h @@ -1,6 +1,6 @@ /* * File: libutil.h - * Summary: System indepentant functions + * Summary: System independent functions * * Modified for Crawl Reference by $Author$ on $Date$ * @@ -19,14 +19,6 @@ #include #include -void cursorxy(int x, int y); - -// Converts a key to a direction key, converting keypad and other sequences -// to vi key sequences (shifted/control key directions are also handled). Non -// direction keys (hopefully) pass through unmangled. -int unmangle_direction_keys(int keyin, int keymap = 0, - bool fake_ctrl = true, bool fake_shift = true); - std::string lowercase_string(std::string s); std::string &lowercase(std::string &s); std::string &uppercase(std::string &s); @@ -54,9 +46,6 @@ std::string replace_all_of(std::string s, int count_occurrences(const std::string &text, const std::string &searchfor); -// getch() that returns a consistent set of values for all platforms. -int c_getch(); - void play_sound(const char *file); // Pattern matching @@ -64,25 +53,6 @@ void *compile_pattern(const char *pattern, bool ignore_case = false); void free_compiled_pattern(void *cp); bool pattern_match(void *compiled_pattern, const char *text, int length); -void get_input_line( char *const buff, int len ); - -class input_history; - -// In view.cc, declared here for default argument to cancelable_get_line() -int get_number_of_cols(void); - -// Returns zero if user entered text and pressed Enter, otherwise returns the -// key pressed that caused the exit, usually Escape. -// -// If keyproc is provided, it must return 1 for normal processing, 0 to exit -// normally (pretend the user pressed Enter), or -1 to exit as if the user -// pressed Escape -int cancelable_get_line( char *buf, - int len, - int wrapcol = get_number_of_cols(), - input_history *mh = NULL, - int (*keyproc)(int &c) = NULL ); - std::string & trim_string( std::string &str ); std::string trimmed_string( std::string s ); @@ -135,60 +105,6 @@ void usleep( unsigned long time ); int snprintf( char *str, size_t size, const char *format, ... ); #endif -// Keys that getch() must return for keys Crawl is interested in. -enum KEYS -{ - CK_ENTER = '\r', - CK_BKSP = 8, - CK_ESCAPE = ESCAPE, - - // 128 is off-limits because it's the code that's used when running - CK_DELETE = 129, - - // This sequence of enums should not be rearranged. - CK_UP, - CK_DOWN, - CK_LEFT, - CK_RIGHT, - - CK_INSERT, - - CK_HOME, - CK_END, - CK_CLEAR, - - CK_PGUP, - CK_PGDN, - - CK_SHIFT_UP, - CK_SHIFT_DOWN, - CK_SHIFT_LEFT, - CK_SHIFT_RIGHT, - - CK_SHIFT_INSERT, - - CK_SHIFT_HOME, - CK_SHIFT_END, - CK_SHIFT_CLEAR, - - CK_SHIFT_PGUP, - CK_SHIFT_PGDN, - - CK_CTRL_UP, - CK_CTRL_DOWN, - CK_CTRL_LEFT, - CK_CTRL_RIGHT, - - CK_CTRL_INSERT, - - CK_CTRL_HOME, - CK_CTRL_END, - CK_CTRL_CLEAR, - - CK_CTRL_PGUP, - CK_CTRL_PGDN -}; - // Sets a boolean to a new value in the scope of the object instance. class unwind_bool { @@ -206,62 +122,6 @@ private: bool oldval; }; -class cursor_control -{ -public: - cursor_control(bool cursor_enabled) - : cstate(is_cursor_enabled()), smartcstate(is_smart_cursor_enabled()) - { - enable_smart_cursor(false); - set_cursor_enabled(cursor_enabled); - } - ~cursor_control() { - set_cursor_enabled(cstate); - enable_smart_cursor(smartcstate); - } -private: - bool cstate; - bool smartcstate; -}; - -// Reads lines of text; used internally by cancelable_get_line. -class line_reader -{ -public: - line_reader(char *buffer, size_t bufsz, - int wrap_col = get_number_of_cols()); - - typedef int (*keyproc)(int &key); - - int read_line(bool clear_previous = true); - - std::string get_text() const; - - void set_input_history(input_history *ih); - void set_keyproc(keyproc fn); - -protected: - void cursorto(int newcpos); - int process_key(int ch); - void backspace(); - void killword(); - - bool is_wordchar(int c); - -private: - char *buffer; - size_t bufsz; - input_history *history; - int start_x, start_y; - keyproc keyfn; - int wrapcol; - - // These are subject to change during editing. - char *cur; - int length; - int pos; -}; - class base_pattern { public: diff --git a/crawl-ref/source/libw32c.cc b/crawl-ref/source/libw32c.cc index 015b2b7e34..42f730a08e 100644 --- a/crawl-ref/source/libw32c.cc +++ b/crawl-ref/source/libw32c.cc @@ -221,8 +221,21 @@ void bFlush(void) } } +void set_mouse_enabled(bool enabled) +{ + DWORD inmode; + if (::GetConsoleMode(inbuf, &inmode)) + { + if (enabled) + inmode |= ENABLE_MOUSE_INPUT; + else + inmode &= ~ENABLE_MOUSE_INPUT; + + ::SetConsoleMode(inbuf, inmode); + } +} -void setStringInput(bool value) +void set_string_input(bool value) { DWORD inmodes, outmodes; if (value == TRUE) @@ -352,7 +365,7 @@ void init_libw32c(void) init_colors(oldTitle); // by default, set string input to false: use char-input only - setStringInput( false ); + set_string_input( false ); // set up screen size set_w32_screen_size(); @@ -364,7 +377,7 @@ void init_libw32c(void) _setcursortype_internal(false); // buffering defaults to ON -- very important! - setBuffering(true); + set_buffering(true); crawl_state.terminal_resize_handler = w32_term_resizer; crawl_state.terminal_resize_check = w32_check_screen_resize; @@ -399,7 +412,7 @@ void deinit_libw32c(void) SetConsoleOutputCP(OutputCP); // restore console attributes for normal function - setStringInput(true); + set_string_input(true); // set cursor and normal textcolor _setcursortype_internal(true); @@ -613,7 +626,7 @@ static void cprintf_aux(const char *s) // turn buffering ON (temporarily) bool oldValue = buffering; - setBuffering(true); + set_buffering(true); // loop through string char *p = (char *)s; @@ -623,7 +636,7 @@ static void cprintf_aux(const char *s) } // reset buffering - setBuffering(oldValue); + set_buffering(oldValue); // flush string bFlush(); @@ -773,6 +786,11 @@ int vk_translate( WORD VirtCode, CHAR c, DWORD cKeys) return vk_tr[1][mkey]; } +int m_getch() +{ + return getch(); +} + int getch_ck(void) { INPUT_RECORD ir; @@ -845,7 +863,7 @@ int getche(void) { // turn buffering off temporarily const bool oldValue = buffering; - setBuffering(false); + set_buffering(false); int val = getch(); @@ -853,7 +871,7 @@ int getche(void) putch(val); // restore buffering value - setBuffering(oldValue); + set_buffering(oldValue); return val; } @@ -889,11 +907,11 @@ void textbackground(int c) UNUSED( c ); } -int getConsoleString(char *buf, int maxlen) +int get_console_string(char *buf, int maxlen) { DWORD nread; // set console input to line mode - setStringInput( true ); + set_string_input( true ); // force cursor const bool oldValue = cursor_is_enabled; @@ -920,7 +938,7 @@ int getConsoleString(char *buf, int maxlen) // reset console mode - also flushes if player has typed in // too long of a name so we don't get silly garbage on return. - setStringInput( false ); + set_string_input( false ); // restore old cursor if (w32_smart_cursor) @@ -935,7 +953,7 @@ void update_screen() bFlush(); } -bool setBuffering( bool value ) +bool set_buffering( bool value ) { bool oldValue = buffering; diff --git a/crawl-ref/source/libw32c.h b/crawl-ref/source/libw32c.h index 70c038c49e..6e424a43ca 100644 --- a/crawl-ref/source/libw32c.h +++ b/crawl-ref/source/libw32c.h @@ -28,9 +28,9 @@ void textcolor(int c); void textattr(int c); void cprintf( const char *format, ... ); // void cprintf(const char *s); -void setStringInput(bool value); -bool setBuffering(bool value); -int getConsoleString(char *buf, int maxlen); +void set_string_input(bool value); +bool set_buffering(bool value); +int get_console_string(char *buf, int maxlen); void print_timings(void); void window(int x, int y, int lx, int ly); @@ -49,6 +49,7 @@ void update_screen(); void enable_smart_cursor(bool cursor); bool is_smart_cursor_enabled(); +void set_mouse_enabled(bool enabled); #endif diff --git a/crawl-ref/source/macro.cc b/crawl-ref/source/macro.cc index 4f9e8cbf45..0deb31ae04 100644 --- a/crawl-ref/source/macro.cc +++ b/crawl-ref/source/macro.cc @@ -44,6 +44,7 @@ #include // for tolower #include +#include "cio.h" #include "externs.h" #include "stuff.h" @@ -577,7 +578,7 @@ static keyseq getch_mul( int (*rgetch)() = NULL ) int a; if (!rgetch) - rgetch = getch; + rgetch = m_getch; keys.push_back( a = rgetch() ); @@ -655,16 +656,14 @@ void flush_input_buffer( int reason ) void macro_add_query( void ) { - unsigned char input; + int input; bool keymap = false; KeymapContext keymc = KC_DEFAULT; mesclr(); - mpr( "(m)acro, keymap [(k) default, (x) level-map or (t)argeting], (s)ave?", MSGCH_PROMPT ); - input = getch(); - if (input == 0) - input = getch(); - + mpr("(m)acro, keymap [(k) default, (x) level-map or (t)argeting], (s)ave?", + MSGCH_PROMPT); + input = m_getch(); input = tolower( input ); if (input == 'k') { @@ -714,9 +713,7 @@ void macro_add_query( void ) mprf(MSGCH_WARN, "Current Action: %s", vtostr(mapref[key]).c_str()); mpr( "Do you wish to (r)edefine, (c)lear, or (a)bort?", MSGCH_PROMPT ); - input = getch(); - if (input == 0) - input = getch(); + input = m_getch(); input = tolower( input ); if (input == 'a' || input == ESCAPE) diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index 0316e1cb7f..20e016dc9b 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -7,6 +7,7 @@ acr.o \ beam.o \ branch.o \ chardump.o \ +cio.o \ cloud.o \ command.o \ database.o \ diff --git a/crawl-ref/source/menu.cc b/crawl-ref/source/menu.cc index 4d88c2160b..7b78c92b1e 100644 --- a/crawl-ref/source/menu.cc +++ b/crawl-ref/source/menu.cc @@ -7,6 +7,7 @@ */ #include #include "AppHdr.h" +#include "cio.h" #include "menu.h" #include "macro.h" #include "tutorial.h" diff --git a/crawl-ref/source/message.cc b/crawl-ref/source/message.cc index 8c947fb4d7..487fedb422 100644 --- a/crawl-ref/source/message.cc +++ b/crawl-ref/source/message.cc @@ -24,7 +24,7 @@ #endif #include "externs.h" - +#include "cio.h" #include "initfile.h" #include "libutil.h" #include "macro.h" diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc index 1f81f6329d..f09b3e6049 100644 --- a/crawl-ref/source/newgame.cc +++ b/crawl-ref/source/newgame.cc @@ -71,6 +71,7 @@ #include "abl-show.h" #include "branch.h" +#include "cio.h" #include "command.h" #include "files.h" #include "fight.h" diff --git a/crawl-ref/source/notes.cc b/crawl-ref/source/notes.cc index 3ea3d44edc..7b21af98e1 100644 --- a/crawl-ref/source/notes.cc +++ b/crawl-ref/source/notes.cc @@ -10,6 +10,7 @@ #include "notes.h" #include "branch.h" +#include "cio.h" #include "files.h" #include "Kills.h" #include "hiscores.h" diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 598aa55dc0..984dc715b8 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -2930,8 +2930,6 @@ int check_stealth(void) void ability_increase(void) { - unsigned char keyin; - mpr("Your experience leads to an increase in your attributes!", MSGCH_INTRINSIC_GAIN); @@ -2940,34 +2938,28 @@ void ability_increase(void) mpr("Increase (S)trength, (I)ntelligence, or (D)exterity? ", MSGCH_PROMPT); - get_key: - keyin = getch(); - if (keyin == 0) - { - getch(); - goto get_key; - } - - switch (keyin) + while (true) { - case 's': - case 'S': - modify_stat(STAT_STRENGTH, 1, false); - return; + const int keyin = getch(); - case 'i': - case 'I': - modify_stat(STAT_INTELLIGENCE, 1, false); - return; - - case 'd': - case 'D': - modify_stat(STAT_DEXTERITY, 1, false); - return; + switch (keyin) + { + case 's': + case 'S': + modify_stat(STAT_STRENGTH, 1, false); + return; + + case 'i': + case 'I': + modify_stat(STAT_INTELLIGENCE, 1, false); + return; + + case 'd': + case 'D': + modify_stat(STAT_DEXTERITY, 1, false); + return; + } } - - goto get_key; -/* this is an infinite loop because it is reasonable to assume that you're not going to want to leave it prematurely. */ } // end ability_increase() void display_char_status() diff --git a/crawl-ref/source/shopping.cc b/crawl-ref/source/shopping.cc index d98117f1b5..9f722b94bd 100644 --- a/crawl-ref/source/shopping.cc +++ b/crawl-ref/source/shopping.cc @@ -25,7 +25,7 @@ #endif #include "externs.h" - +#include "cio.h" #include "describe.h" #include "invent.h" #include "items.h" diff --git a/crawl-ref/source/skills2.cc b/crawl-ref/source/skills2.cc index 1e2d3dd43f..2c29dcea27 100644 --- a/crawl-ref/source/skills2.cc +++ b/crawl-ref/source/skills2.cc @@ -1818,20 +1818,11 @@ static const skill_type skill_display_order[] = static const int ndisplayed_skills = sizeof(skill_display_order) / sizeof(*skill_display_order); -void show_skills() +static void display_skill_table(bool show_aptitudes) { - int i; - int x; - menu_letter lcount; - bool show_aptitudes = false; - + menu_letter lcount = 'a'; const int num_lines = get_number_of_lines(); - clrscr(); - - reprint_stuff: - lcount = 'a'; - gotoxy(1, 1); textcolor(LIGHTGREY); @@ -1848,11 +1839,11 @@ void show_skills() #endif int scrln = 3, scrcol = 1; - + int x; // Don't want the help line to appear too far down a big window. const int bottom_line = ((num_lines > 30) ? 30 : num_lines); - for (i = 0; i < ndisplayed_skills; ++i) + for (int i = 0; i < ndisplayed_skills; ++i) { x = skill_display_order[i]; @@ -1939,76 +1930,80 @@ void show_skills() if (Options.tutorial_left) { - textcolor(MAGENTA); - gotoxy(1, bottom_line-5); - formatted_string::parse_block( - "This screen shows the skill set of your character. You can pick up new" EOL - "skills by performing the corresponding actions. The number next to the" EOL - "skill is your current level, the higher the better. The blue percent " EOL - "value shows your progress towards the next skill level. You can toggle" EOL - "which skills to train by pressing their slot letters. A greyish skill " EOL - "will increase at a decidedly slower rate and ease training of others. ", - false).display(); + textcolor(MAGENTA); + gotoxy(1, bottom_line-5); + formatted_string::parse_block( + "This screen shows the skill set of your character. You can pick up new" EOL + "skills by performing the corresponding actions. The number next to the" EOL + "skill is your current level, the higher the better. The blue percent " EOL + "value shows your progress towards the next skill level. You can toggle" EOL + "which skills to train by pressing their slot letters. A greyish skill " EOL + "will increase at a decidedly slower rate and ease training of others. ", + false).display(); } else { - // if any more skills added, must adapt letters to go into caps - gotoxy(1, bottom_line-1); - textcolor(LIGHTGREY); - cprintf("Press the letter of a skill to choose whether you want to practise it."); - if (!player_genus(GENPC_DRACONIAN) || you.max_level >= 7) - { - gotoxy(1, bottom_line); - formatted_string::parse_string("Press '!' to toggle between " - "progress and " - "aptitude " - "display.").display(); - } + // if any more skills added, must adapt letters to go into caps + gotoxy(1, bottom_line-1); + textcolor(LIGHTGREY); + cprintf("Press the letter of a skill to choose " + "whether you want to practise it."); + if (!player_genus(GENPC_DRACONIAN) || you.max_level >= 7) + { + gotoxy(1, bottom_line); + formatted_string::parse_string("Press '!' to toggle between " + "progress and " + "aptitude " + "display.").display(); + } } +} - int get_thing = getch(); - - if (get_thing == 0) - getch(); - else +void show_skills() +{ + bool show_aptitudes = false; + clrscr(); + while (true) { + display_skill_table(show_aptitudes); + + const int get_thing = getch(); if (get_thing == '!' && (!player_genus(GENPC_DRACONIAN) || - you.max_level >= 7)) + you.max_level >= 7)) { show_aptitudes = !show_aptitudes; - goto reprint_stuff; + continue; } + if ((get_thing >= 'a' && get_thing <= 'z') || (get_thing >= 'A' && get_thing <= 'Z')) { - lcount = 'a'; // toggle skill practise + menu_letter lcount = 'a'; // toggle skill practise - for (i = 0; i < ndisplayed_skills; i++) + int x; + for (int i = 0; i < ndisplayed_skills; i++) { x = skill_display_order[i]; if (x == SK_BLANK_LINE || x == SK_COLUMN_BREAK) continue; - + if (you.skills[x] == 0) continue; - + if (get_thing == lcount) { you.practise_skill[x] = !you.practise_skill[x]; break; } - + ++lcount; } - - goto reprint_stuff; + continue; } + break; } - - return; } - const char *skill_name(int which_skill) { return (skills[which_skill][0]); diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc index 02bb77e9af..bc3eee8912 100644 --- a/crawl-ref/source/spl-book.cc +++ b/crawl-ref/source/spl-book.cc @@ -25,7 +25,7 @@ #endif #include "externs.h" - +#include "cio.h" #include "debug.h" #include "delay.h" #include "food.h" @@ -685,8 +685,8 @@ spell_type which_spell_in_book(int sbook_type, int spl) // If fs is not NULL, updates will be to the formatted_string instead of // the display. -unsigned char spellbook_contents( item_def &book, int action, - formatted_string *fs ) +int spellbook_contents( item_def &book, int action, + formatted_string *fs ) { int spelcount = 0; int i, j; @@ -827,7 +827,7 @@ unsigned char spellbook_contents( item_def &book, int action, if (fs) *fs = out; - unsigned char keyn = 0; + int keyn = 0; if (update_screen) { cursor_control coff(false); @@ -835,9 +835,7 @@ unsigned char spellbook_contents( item_def &book, int action, out.display(); - keyn = getch(); - if (keyn == 0) - getch(); + keyn = c_getch(); } return (keyn); // try to figure out that for which this is used {dlb} diff --git a/crawl-ref/source/spl-book.h b/crawl-ref/source/spl-book.h index d06172cc8f..a118b0b370 100644 --- a/crawl-ref/source/spl-book.h +++ b/crawl-ref/source/spl-book.h @@ -48,8 +48,8 @@ int staff_spell( int zap_device_2 ); bool undead_cannot_memorise(spell_type spell, char being); -unsigned char spellbook_contents( item_def &book, int action, - formatted_string *fs = NULL ); +int spellbook_contents( item_def &book, int action, + formatted_string *fs = NULL ); int count_staff_spells(const item_def &item, bool need_id); int rod_shield_leakage(); diff --git a/crawl-ref/source/stash.cc b/crawl-ref/source/stash.cc index a1ed94ed47..7c58b55cde 100644 --- a/crawl-ref/source/stash.cc +++ b/crawl-ref/source/stash.cc @@ -8,6 +8,7 @@ #include "AppHdr.h" #include "chardump.h" +#include "cio.h" #include "clua.h" #include "describe.h" #include "direct.h" diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 20f6d49160..1db49cdff9 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -14,6 +14,7 @@ #include "FixAry.h" #include "branch.h" #include "command.h" +#include "cio.h" #include "clua.h" #include "delay.h" #include "describe.h" @@ -2552,6 +2553,15 @@ void start_travel(int x, int y) void start_explore(bool grab_items) { + if (Options.tut_explored) + Options.tut_explored = 0; + + if (you.level_type == LEVEL_LABYRINTH || you.level_type == LEVEL_ABYSS) + { + mpr("It would help if you knew where you were, first."); + return; + } + if (!i_feel_safe(true)) return; diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc index 390c7e56c0..522511002a 100644 --- a/crawl-ref/source/tutorial.cc +++ b/crawl-ref/source/tutorial.cc @@ -6,7 +6,7 @@ #include #include "tutorial.h" - +#include "cio.h" #include "command.h" #include "files.h" #include "initfile.h" diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index fe384a5809..a3fb63f251 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -37,6 +37,7 @@ #include "externs.h" #include "command.h" +#include "cio.h" #include "cloud.h" #include "clua.h" #include "debug.h" @@ -2518,7 +2519,7 @@ void show_map( FixedVector &spec_place, bool travel_mode ) char move_x = 0; char move_y = 0; - char getty = 0; + int getty = 0; // Vector to track all features we can travel to, in order of distance. std::vector features; @@ -2605,8 +2606,10 @@ void show_map( FixedVector &spec_place, bool travel_mode ) redraw_map = true; cursorxy(curs_x, curs_y + top - 1); + c_input_reset(true); getty = unmangle_direction_keys(getchm(KC_LEVELMAP), KC_LEVELMAP, false, false); + c_input_reset(false); switch (getty) { @@ -2641,7 +2644,7 @@ void show_map( FixedVector &spec_place, bool travel_mode ) move_x = move_y = 0; break; } - + case CONTROL('E'): case CONTROL('X'): { @@ -2805,6 +2808,46 @@ void show_map( FixedVector &spec_place, bool travel_mode ) search_found, &move_x, &move_y); break; } + + case CK_MOUSE_MOVE: + move_x = move_y = 0; + break; + + case CK_MOUSE_CLICK: + { + const c_mouse_event cme = get_mouse_event(); + const coord_def curp(start_x + curs_x - 1, start_y + curs_y - 1); + const coord_def grdp = + cme.pos + coord_def(start_x - 1, start_y - top); + + if (cme.left_clicked() && in_bounds(grdp)) + { + spec_place[0] = grdp.x; + spec_place[1] = grdp.y; + map_alive = false; + } + else if (cme.scroll_up()) + { + move_y = -block_step * ((curs_y - top + 1) / block_step + 1); + move_x = 0; + } + else if (cme.scroll_down()) + { + move_y = + block_step * + ((get_number_of_lines() - curs_y + top - 1) / block_step + + 1); + move_x = 0; + } + else if (cme.right_clicked()) + { + const coord_def delta = grdp - curp; + move_y = delta.y; + move_x = delta.x; + } + break; + } + case '.': case '\r': case 'S': -- cgit v1.2.3-54-g00ecf