stupid ideas of when the terminal is actually resized).
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1604 c06c8d41-db1a-0410-9941-cceddc491573
NEECVIIAOBP72T6O44DWAA6HFSDY3KSWYCFMKAEMDMVOI7XASD7QC
YCXLDUFP5QPEX7YHXWAOETMZ2FWUMFI2GYFFS3NJAJYMEYUD5CUQC
UB73UGG2GEG6AL4T76UILFLTELH4Z5WN54UROLJD6RDR3JG77CXAC
W6IY6LF3MREPXC23AAKA2BJNUCJYCSOWY55DIWJWFLUEE2Y3LGNQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
UXBKTJSK6DEFSCQ4HB36YM6KVFGWYVCEORXIMOKQ3JZL4NNEOKGQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
TOKBONNNPTP2CIEHMMR4QAJZTXYETS55OGGDA6FY6NIMNDYMWJDAC
CTTZKXEF5P64ZO2UNJZIAKKZH7ZWZ54C5E27ATXKGZJFRJJC6FJAC
EOMCPVNQLX3IMLC46EAO67DPBH5KEG2FQTPBLGU62HIRWA3UQ7XQC
RCU52DRCPWJVQ6HME4QR6V6EVQWTBKZTPWDI47UGUDAUBPOO5YNAC
PL6I2CMSTHY5ZHWVMIQE5YTM5S5VPKBNZM6QJVHZSSKOJGIJ5W4AC
GCIZIUXO5TYROKDUYB3HAY7H7MRDTJNM7HR7DGSH7KXDIZC2LCDAC
YRY2TC3VHOYE47M23UJGUWDGF7H7WGU7WLWI4SUNM4EDNTGUPHGAC
CVC5FFFLGVRR3KPYDNB6RF4FNACV3LI3HPSR4MCUNZ4C3FSQYBDAC
// TIMING info
static int ncalls[6] = { 0,0,0,0,0,0 };
static double runavg[6] = { 0.0,0.0,0.0,0.0,0.0,0.0 };
static int oob[6] = { 0,0,0,0,0,0 };
static int dlen[6] = { 0,0,0,0,0,0 };
static LARGE_INTEGER t1, t2;
static void addcall(int i, LARGE_INTEGER &tm1, LARGE_INTEGER &tm2)
void writeChar(char c)
if (d > 1.4*runavg[i])
oob[i] ++;
}
}
#define CLOCKIN {QueryPerformanceCounter(&t1);}
#define CLOCKOUT(x) {QueryPerformanceCounter(&t2); \
addcall((x), t1, t2);}
static char *descrip[] =
{
"bflush:WriteConsoleOutput",
"_setCursorType:SetConsoleCursorInfo",
"gotoxy:SetConsoleCursorPosition",
"textcolor:SetConsoleTextAttribute",
"cprintf:WriteConsole",
"getch:ReadConsoleInput"
};
void print_timings(void)
{
int i;
char s[100];
// must flush current buffer
bFlush();
sprintf(s, "Avg (#/oob), CpS = %.1lf", cps.QuadPart);
mpr(s);
for(i=0; i<3; i++)
{
int dl = 0;
if (ncalls[i] > 0)
dl = dlen[i] / ncalls[i];
sprintf(s, "%-40s %.1f us (%d/%d), avg dlen = %d", descrip[i],
(1000000.0 * runavg[i]) / cps.QuadPart, ncalls[i], oob[i], dl);
mpr(s);
return;
void writeChar(char c)
{
bool noop = true;
PCHAR_INFO pci;
// check for CR: noop
if (c == 0x0D)
return;
// check for newline
if (c == 0x0A)
{
// must flush current buffer
bFlush();
// reposition
gotoxy(1, cy+2);
return;
}
int tc = WIN32COLOR(current_color);
pci = &screen[SCREENINDEX(cx,cy)];
// is this a no-op?
if (pci->Char.AsciiChar != c)
noop = false;
else if (pci->Attributes != tc)
noop = false;
if (!noop)
{
// write the info and update the dirty area
pci->Char.AsciiChar = c;
pci->Attributes = tc;
if (!noop)
{
// write the info and update the dirty area
pci->Char.AsciiChar = c;
pci->Attributes = tc;
// if cursor is not NOCURSOR, update screen
if (cursor_is_enabled)
{
COORD xy;
xy.X = cx;
xy.Y = cy;
CLOCKIN
SetConsoleCursorPosition(outbuf, xy);
CLOCKOUT(2)
}
// if cursor is not NOCURSOR, update screen
if (cursor_is_enabled)
{
COORD xy;
xy.X = cx;
xy.Y = cy;
SetConsoleCursorPosition(outbuf, xy);
}
DWORD inmodes, outmodes;
if (value == TRUE)
{
inmodes = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT;
outmodes = ENABLE_PROCESSED_OUTPUT;
}
else
{
inmodes = 0;
outmodes = 0;
}
DWORD inmodes, outmodes;
if (value == TRUE)
{
inmodes = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
| ENABLE_PROCESSED_INPUT
| ENABLE_MOUSE_INPUT
| ENABLE_WINDOW_INPUT;
outmodes = ENABLE_PROCESSED_OUTPUT;
}
else
{
inmodes = ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT;
outmodes = 0;
}
if ( SetConsoleMode( inbuf, inmodes ) == 0)
{
fputs("Error initialising console input mode.", stderr);
exit(0);
}
if ( SetConsoleMode( inbuf, inmodes ) == 0)
{
fputs("Error initialising console input mode.", stderr);
exit(0);
}
if ( SetConsoleMode( outbuf, outmodes ) == 0)
{
fputs("Error initialising console output mode.", stderr);
exit(0);
}
if ( SetConsoleMode( outbuf, outmodes ) == 0)
{
fputs("Error initialising console output mode.", stderr);
exit(0);
}
static void set_w32_screen_size()
{
CONSOLE_SCREEN_BUFFER_INFO cinf;
if (::GetConsoleScreenBufferInfo(outbuf, &cinf))
{
screensize.X = cinf.srWindow.Right - cinf.srWindow.Left + 1;
screensize.Y = cinf.srWindow.Bottom - cinf.srWindow.Top + 1;
}
else
{
screensize.X = 80;
screensize.Y = 25;
}
if (screen)
{
delete [] screen;
screen = NULL;
}
screen = new CHAR_INFO[screensize.X * screensize.Y];
COORD topleft;
SMALL_RECT used;
topleft.X = topleft.Y = 0;
::ReadConsoleOutput(outbuf, screen, screensize, topleft, &used);
}
static void w32_handle_resize_event()
{
if (crawl_state.waiting_for_command)
handle_terminal_resize(true);
else
crawl_state.terminal_resized = true;
}
static void w32_check_screen_resize()
{
CONSOLE_SCREEN_BUFFER_INFO cinf;
if (::GetConsoleScreenBufferInfo(outbuf, &cinf))
{
if (screensize.X != cinf.srWindow.Right - cinf.srWindow.Left + 1
|| screensize.Y != cinf.srWindow.Bottom - cinf.srWindow.Top + 1)
{
w32_handle_resize_event();
}
}
}
if (inbuf == INVALID_HANDLE_VALUE || outbuf == INVALID_HANDLE_VALUE)
{
fputs("Could not initialise libw32c console support.", stderr);
exit(0);
}
if (inbuf == INVALID_HANDLE_VALUE || outbuf == INVALID_HANDLE_VALUE)
{
fputs("Could not initialise libw32c console support.", stderr);
exit(0);
}
init_colors(oldTitle);
// by default, set string input to false: use char-input only
setStringInput( false );
if (SetConsoleMode( outbuf, 0 ) == 0)
{
fputs("Error initialising console output mode.", stderr);
exit(0);
}
CONSOLE_SCREEN_BUFFER_INFO cinf;
if (::GetConsoleScreenBufferInfo(outbuf, &cinf))
{
screensize.X = cinf.srWindow.Right - cinf.srWindow.Left + 1;
screensize.Y = cinf.srWindow.Bottom - cinf.srWindow.Top + 1;
}
else
{
screensize.X = 80;
screensize.Y = 25;
}
// by default, set string input to false: use char-input only
setStringInput( false );
//DEBUG
//foo = fopen("debug.txt", "w");
crawl_state.terminal_resize_handler = w32_term_resizer;
crawl_state.terminal_resize_check = w32_check_screen_resize;
// JWM, 06/12/2004: Code page setting, as XP does not use ANSI 437 by
// default.
InputCP = GetConsoleCP();
OutputCP = GetConsoleOutputCP();
// JWM, 06/12/2004: Code page setting, as XP does not use ANSI 437 by
// default.
InputCP = GetConsoleCP();
OutputCP = GetConsoleOutputCP();
// DS: Don't kill Crawl if we can't set the codepage. Windows 95/98/ME don't
// have support for setting the input and output codepage. I'm also not
// convinced we need to set the input codepage at all.
if (InputCP != PREFERRED_CODEPAGE)
SetConsoleCP(PREFERRED_CODEPAGE);
// Don't kill Crawl if we can't set the codepage. Windows 95/98/ME
// don't have support for setting the input and output codepage.
// I'm also not convinced we need to set the input codepage at all.
if (InputCP != PREFERRED_CODEPAGE)
SetConsoleCP(PREFERRED_CODEPAGE);
// JWM, 06/12/2004: Code page stuff. If it was the preferred code page, it
// doesn't need restoring. Shouldn't be an error and too bad if there is.
if (InputCP && InputCP != PREFERRED_CODEPAGE)
SetConsoleCP(InputCP);
// JWM, 06/12/2004: Code page stuff. If it was the preferred code page, it
// doesn't need restoring. Shouldn't be an error and too bad if there is.
if (InputCP && InputCP != PREFERRED_CODEPAGE)
SetConsoleCP(InputCP);
if (OutputCP && OutputCP != PREFERRED_CODEPAGE)
SetConsoleOutputCP(OutputCP);
// restore console attributes for normal function
setStringInput(true);
if (OutputCP && OutputCP != PREFERRED_CODEPAGE)
SetConsoleOutputCP(OutputCP);
// restore console attributes for normal function
setStringInput(true);
// set cursor and normal textcolor
_setcursortype_internal(true);
textcolor(DARKGREY);
// set cursor and normal textcolor
_setcursortype_internal(true);
textcolor(DARKGREY);
cci.dwSize = 5;
cci.bVisible = curstype? TRUE : FALSE;
cursor_is_enabled = curstype;
CLOCKIN
SetConsoleCursorInfo( outbuf, &cci );
CLOCKOUT(1)
cci.dwSize = 5;
cci.bVisible = curstype? TRUE : FALSE;
cursor_is_enabled = curstype;
SetConsoleCursorInfo( outbuf, &cci );
// now, if we just changed from NOCURSOR to CURSOR,
// actually move screen cursor
if (cursor_is_enabled)
gotoxy(cx+1, cy+1);
// now, if we just changed from NOCURSOR to CURSOR,
// actually move screen cursor
if (cursor_is_enabled)
gotoxy(cx+1, cy+1);
for(x = 0; x < screensize.X; x++)
{
for(y = 0; y < screensize.Y; y++)
{
pci->Char.AsciiChar = ' ';
pci->Attributes = 0;
pci++;
}
}
for(x = 0; x < screensize.X; x++)
{
for(y = 0; y < screensize.Y; y++)
{
pci->Char.AsciiChar = ' ';
pci->Attributes = 0;
pci++;
}
}
source.X = 0;
source.Y = 0;
target.Left = 0;
target.Top = 0;
target.Right = screensize.X - 1;
target.Bottom = screensize.Y - 1;
source.X = 0;
source.Y = 0;
target.Left = 0;
target.Top = 0;
target.Right = screensize.X - 1;
target.Bottom = screensize.Y - 1;
// bounds check
if (x < 1)
x = 1;
if (x > screensize.X)
x = screensize.X;
if (y < 1)
y = 1;
if (y > screensize.Y)
y = screensize.Y;
// bounds check
if (x < 1)
x = 1;
if (x > screensize.X)
x = screensize.X;
if (y < 1)
y = 1;
if (y > screensize.Y)
y = screensize.Y;
// if cursor is not NOCURSOR, update screen
if (cursor_is_enabled)
{
COORD xy;
xy.X = cx;
xy.Y = cy;
CLOCKIN
if (SetConsoleCursorPosition(outbuf, xy) == 0)
fputs("SetConsoleCursorPosition() failed!", stderr);
CLOCKOUT(2)
}
// if cursor is not NOCURSOR, update screen
if (cursor_is_enabled)
{
COORD xy;
xy.X = cx;
xy.Y = cy;
if (SetConsoleCursorPosition(outbuf, xy) == 0)
fputs("SetConsoleCursorPosition() failed!", stderr);
}
PCHAR_INFO pci = screen + SCREENINDEX(crawl_view.msgp.x - 1,
crawl_view.msgp.y - 1);
for (int x = 0; x < screensize.X; x++)
{
for (int y = 0; y < crawl_view.msgsz.y; y++)
{
pci->Char.AsciiChar = ' ';
pci->Attributes = 0;
pci++;
}
}
PCHAR_INFO pci = screen + SCREENINDEX(crawl_view.msgp.x - 1,
crawl_view.msgp.y - 1);
for (int x = 0; x < screensize.X; x++)
{
for (int y = 0; y < crawl_view.msgsz.y; y++)
{
pci->Char.AsciiChar = ' ';
pci->Attributes = 0;
pci++;
}
}
source.X = crawl_view.msgp.x - 1;
source.Y = crawl_view.msgp.y - 1;
target.Left = crawl_view.msgp.x - 1;
target.Top = crawl_view.msgp.y - 1;
target.Right = screensize.X - 1;
target.Bottom = screensize.Y - 1;
source.X = crawl_view.msgp.x - 1;
source.Y = crawl_view.msgp.y - 1;
target.Left = crawl_view.msgp.x - 1;
target.Top = crawl_view.msgp.y - 1;
target.Right = screensize.X - 1;
target.Bottom = screensize.Y - 1;
// loop through string
char *p = (char *)s;
while(*p)
{
writeChar(*p++);
}
// loop through string
char *p = (char *)s;
while(*p)
{
writeChar(*p++);
}
bool shftDown = false;
bool ctrlDown = false;
bool altDown = !!(cKeys & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED));
// DEBUG
//fprintf(foo, "Received code %d (%c) with modifiers: %d\n", VirtCode, c, cKeys);
bool shftDown = false;
bool ctrlDown = false;
bool altDown = !!(cKeys & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED));
// step 1 - we don't care about shift or control
if (VirtCode == VK_SHIFT || VirtCode == VK_CONTROL ||
VirtCode == VK_MENU || VirtCode == VK_CAPITAL ||
VirtCode == VK_NUMLOCK)
return 0;
// step 1 - we don't care about shift or control
if (VirtCode == VK_SHIFT || VirtCode == VK_CONTROL ||
VirtCode == VK_MENU || VirtCode == VK_CAPITAL ||
VirtCode == VK_NUMLOCK)
return 0;
// step 3 - translate shifted or controlled numeric keypad keys
if (cKeys & SHIFT_PRESSED)
shftDown = true;
if (cKeys & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
ctrlDown = true; // control takes precedence over shift
// step 3 - translate shifted or controlled numeric keypad keys
if (cKeys & SHIFT_PRESSED)
shftDown = true;
if (cKeys & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
ctrlDown = true; // control takes precedence over shift
// hack - translate ^P and ^Q since 16 and 17 are taken by CTRL and SHIFT
if ((VirtCode == 80 || VirtCode == 81) && ctrlDown)
return VirtCode & 0x003f; // shift back down
// hack - translate ^P and ^Q since 16 and 17 are taken by CTRL and SHIFT
if ((VirtCode == 80 || VirtCode == 81) && ctrlDown)
return VirtCode & 0x003f; // shift back down
// see if we're a vkey
int mkey;
for(mkey = 0; mkey<VKEY_MAPPINGS; mkey++)
if (VirtCode == vk_tr[0][mkey]) break;
// see if we're a vkey
int mkey;
for(mkey = 0; mkey<VKEY_MAPPINGS; mkey++)
if (VirtCode == vk_tr[0][mkey]) break;
// step 4 - just return the damn key.
if (mkey == VKEY_MAPPINGS)
{
if (c)
return c;
// step 4 - just return the damn key.
if (mkey == VKEY_MAPPINGS)
{
if (c)
return c;
// ds -- Icky hacks to allow keymaps with funky keys.
if (ctrlDown)
VirtCode |= 512;
if (shftDown)
VirtCode |= 1024;
if (altDown)
VirtCode |= 2048;
// ds -- Icky hacks to allow keymaps with funky keys.
if (ctrlDown)
VirtCode |= 512;
if (shftDown)
VirtCode |= 1024;
if (altDown)
VirtCode |= 2048;
// ds -- Cheat and returns 256 + VK if the char is zero. This allows us
// to use the VK for macros and is on par for evil with the rest of
// this function anyway.
return VirtCode | 256;
}
// ds -- Cheat and returns 256 + VK if the char is zero. This allows us
// to use the VK for macros and is on par for evil with the rest of
// this function anyway.
return VirtCode | 256;
}
CLOCKIN
if (ReadConsoleInput( inbuf, &ir, 1, &nread) == 0)
fputs("Error in ReadConsoleInput()!", stderr);
CLOCKOUT(5)
if (nread > 0)
{
// ignore if it isn't a keyboard event.
if (ir.EventType == KEY_EVENT)
{
kr = &(ir.Event.KeyEvent);
// ignore if it is a 'key up' - we only want 'key down'
if (kr->bKeyDown == true)
{
key = vk_translate( kr->wVirtualKeyCode, kr->uChar.AsciiChar, kr->dwControlKeyState );
if (key > 0)
if (ReadConsoleInput( inbuf, &ir, 1, &nread) == 0)
fputs("Error in ReadConsoleInput()!", stderr);
if (nread > 0)
{
// ignore if it isn't a keyboard event.
switch (ir.EventType)
{
case KEY_EVENT:
kr = &(ir.Event.KeyEvent);
// ignore if it is a 'key up' - we only want 'key down'
if (kr->bKeyDown == true)
repeat_count = kr->wRepeatCount - 1;
repeat_key = key;
break;
key = vk_translate( kr->wVirtualKeyCode,
kr->uChar.AsciiChar,
kr->dwControlKeyState );
if (key > 0)
{
repeat_count = kr->wRepeatCount - 1;
repeat_key = key;
waiting_for_event = false;
break;
}
// turn buffering off temporarily
const bool oldValue = buffering;
setBuffering(false);
// turn buffering off temporarily
const bool oldValue = buffering;
setBuffering(false);
// terminate string, then strip CRLF, replace with \0
buf[maxlen-1] = 0;
for (unsigned i=(nread<3 ? 0 : nread-3); i<nread; i++)
{
if (buf[i] == 0x0A || buf[i] == 0x0D)
{
buf[i] = '\0';
break;
}
// terminate string, then strip CRLF, replace with \0
buf[maxlen-1] = 0;
for (unsigned i=(nread<3 ? 0 : nread-3); i<nread; i++)
{
if (buf[i] == 0x0A || buf[i] == 0x0D)
{
buf[i] = '\0';
break;
}
// 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 );
// 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 );