// console.cpp --- 仮想コンソール
#include "DxLib.h"
#include <string> // for std::string
#include <cassert> // for assert
#define CHAR_HEIGHT 32 // 文字の高さ
#define CHAR_WIDTH (CHAR_HEIGHT / 2) // 半角文字の幅
#define COLUMNS 40 // 列の個数
#define ROWS 15 // 行の個数
#define CONSOLE_WIDTH (COLUMNS * CHAR_WIDTH) // コンソールの幅
#define CONSOLE_HEIGHT (ROWS * CHAR_HEIGHT) // コンソールの高さ
#define BLINK_RATE 200 // 点滅間隔(ミリ秒)
#define PROMPT "C:\\> " // プロンプト
char gp_buf[ROWS][COLUMNS]; // 仮想コンソール
int gp_cx = 0, gp_cy = 0; // キャレット位置(文字単位)
int gp_px = 0, gp_py = 0; // ???
int gp_font; // フォントハンドル
bool gp_blink = false; // キャレットの点滅用
std::string gp_output;
// 仮想コンソールを描画する。
void gp_DrawConsole(void)
{
char str[2];
str[1] = 0;
for (int y = 0; y < ROWS; ++y)
{
for (int x = 0; x < COLUMNS; ++x)
{
str[0] = gp_buf[y][x];
DrawStringToHandle(x * CHAR_WIDTH, y * CHAR_HEIGHT,
str, 0xFFFFFF, gp_font);
if (gp_cx == x && gp_cy == y && gp_blink)
{
str[0] = '_';
DrawStringToHandle(x * CHAR_WIDTH, y * CHAR_HEIGHT,
str, 0xFFFF00, gp_font);
}
}
}
}
// スクロールする。
void gp_Scroll(void)
{
memmove(gp_buf[0], gp_buf[1], COLUMNS * (ROWS - 1));
memset(gp_buf[ROWS - 1], ' ', COLUMNS);
}
// 一文字右に移動。
void gp_MoveRight(void)
{
++gp_cx;
if (gp_cx < COLUMNS)
return;
gp_cx = 0;
++gp_cy;
if (gp_cy < ROWS)
return;
--gp_cy;
gp_Scroll();
}
// 改行。
void gp_NewLine(void)
{
gp_cx = 0;
++gp_cy;
if (gp_cy >= ROWS)
{
--gp_cy;
gp_Scroll();
}
}
// 一文字出力する。
void gp_PutChar(char ch)
{
gp_buf[gp_cy][gp_cx] = (char)ch;
gp_MoveRight();
}
// 入力を受け取る。
void gp_ReadInput(void)
{
char ch = GetInputChar(TRUE);
if (ch == 0)
return;
if (ch == '\r')
{
gp_NewLine();
gp_output = PROMPT;
return;
}
gp_PutChar(ch);
}
// 初期化を行う。
void gp_Init(void)
{
#if 0
TCHAR gp_buf[32];
wsprintf(gp_buf, TEXT("%d, %d"), CONSOLE_WIDTH, CONSOLE_HEIGHT);
MessageBox(NULL, gp_buf, NULL, 0);
#endif
assert(CONSOLE_WIDTH == 640);
assert(CONSOLE_HEIGHT == 480);
//assert(CONSOLE_WIDTH == 800);
//assert(CONSOLE_HEIGHT == 600);
SetDrawScreen(DX_SCREEN_BACK);
memset(gp_buf, ' ', sizeof(gp_buf));
gp_font = CreateFontToHandle("MS ゴシック", CHAR_HEIGHT, 0,
DX_FONTTYPE_ANTIALIASING);
gp_output = PROMPT;
}
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
{
SetGraphMode(CONSOLE_WIDTH, CONSOLE_HEIGHT, 32);
ChangeWindowMode(TRUE);
if (DxLib_Init() == -1)
{
return -1;
}
gp_Init();
// 点滅用のカウンタ。
int counter = GetNowCount();
while (!ScreenFlip() && !ProcessMessage() && !ClearDrawScreen())
{
gp_DrawConsole();
gp_ReadInput();
// 出力中か?
if (gp_output.empty())
{
// 点滅のため、一定時間ごとにフラグを切り替える。
if (GetNowCount() - counter >= BLINK_RATE)
{
gp_blink = !gp_blink;
counter = GetNowCount();
}
}
else
{
// 一文字出力する。
gp_PutChar(gp_output[0]);
gp_output.erase(gp_output.begin());
gp_px = gp_cx;
gp_py = gp_cy;
gp_blink = false;
}
}
DxLib_End();
return 0;
}
Ly8gY29uc29sZS5jcHAgLS0tIOS7ruaDs+OCs+ODs+OCveODvOODqwojaW5jbHVkZSAiRHhMaWIuaCIKI2luY2x1ZGUgPHN0cmluZz4gICAgICAgLy8gZm9yIHN0ZDo6c3RyaW5nCiNpbmNsdWRlIDxjYXNzZXJ0PiAgICAgIC8vIGZvciBhc3NlcnQKCiNkZWZpbmUgQ0hBUl9IRUlHSFQgICAgIDMyICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDmloflrZfjga7pq5jjgZUKI2RlZmluZSBDSEFSX1dJRFRIICAgICAgKENIQVJfSEVJR0hUIC8gMikgICAgICAgICAgIC8vIOWNiuinkuaWh+Wtl+OBruW5hQojZGVmaW5lIENPTFVNTlMgICAgICAgICA0MCAgICAgICAgICAgICAgICAgICAgICAgICAgLy8g5YiX44Gu5YCL5pWwCiNkZWZpbmUgUk9XUyAgICAgICAgICAgIDE1ICAgICAgICAgICAgICAgICAgICAgICAgICAvLyDooYzjga7lgIvmlbAKI2RlZmluZSBDT05TT0xFX1dJRFRIICAgKENPTFVNTlMgKiBDSEFSX1dJRFRIKSAgICAgIC8vIOOCs+ODs+OCveODvOODq+OBruW5hQojZGVmaW5lIENPTlNPTEVfSEVJR0hUICAoUk9XUyAqIENIQVJfSEVJR0hUKSAgICAgICAgLy8g44Kz44Oz44K944O844Or44Gu6auY44GVCiNkZWZpbmUgQkxJTktfUkFURSAgICAgIDIwMCAgICAgICAgICAgICAgICAgICAgICAgICAvLyDngrnmu4XplpPpmpTvvIjjg5/jg6rnp5LvvIkKI2RlZmluZSBQUk9NUFQgICAgICAgICAgIkM6XFw+ICIgICAgICAgICAgICAgICAgICAgIC8vIOODl+ODreODs+ODl+ODiAoKY2hhciAgICBncF9idWZbUk9XU11bQ09MVU1OU107ICAgICAgLy8g5Luu5oOz44Kz44Oz44K944O844OrCmludCAgICAgZ3BfY3ggPSAwLCBncF9jeSA9IDA7ICAgICAgIC8vIOOCreODo+ODrOODg+ODiOS9jee9ru+8iOaWh+Wtl+WNmOS9je+8iQppbnQgICAgIGdwX3B4ID0gMCwgZ3BfcHkgPSAwOyAgICAgICAvLyDvvJ/vvJ/vvJ8KaW50ICAgICBncF9mb250OyAgICAgICAgICAgICAgICAgICAgLy8g44OV44Kp44Oz44OI44OP44Oz44OJ44OrCmJvb2wgICAgZ3BfYmxpbmsgPSBmYWxzZTsgICAgICAgICAgIC8vIOOCreODo+ODrOODg+ODiOOBrueCuea7heeUqApzdGQ6OnN0cmluZyAgICAgZ3Bfb3V0cHV0OwoKLy8g5Luu5oOz44Kz44Oz44K944O844Or44KS5o+P55S744GZ44KL44CCCnZvaWQgZ3BfRHJhd0NvbnNvbGUodm9pZCkKewogICAgY2hhciBzdHJbMl07CiAgICBzdHJbMV0gPSAwOwogICAgZm9yIChpbnQgeSA9IDA7IHkgPCBST1dTOyArK3kpCiAgICB7CiAgICAgICAgZm9yIChpbnQgeCA9IDA7IHggPCBDT0xVTU5TOyArK3gpCiAgICAgICAgewogICAgICAgICAgICBzdHJbMF0gPSBncF9idWZbeV1beF07CiAgICAgICAgICAgIERyYXdTdHJpbmdUb0hhbmRsZSh4ICogQ0hBUl9XSURUSCwgeSAqIENIQVJfSEVJR0hULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyLCAweEZGRkZGRiwgZ3BfZm9udCk7CiAgICAgICAgICAgIGlmIChncF9jeCA9PSB4ICYmIGdwX2N5ID09IHkgJiYgZ3BfYmxpbmspCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHN0clswXSA9ICdfJzsKICAgICAgICAgICAgICAgIERyYXdTdHJpbmdUb0hhbmRsZSh4ICogQ0hBUl9XSURUSCwgeSAqIENIQVJfSEVJR0hULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ciwgMHhGRkZGMDAsIGdwX2ZvbnQpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQp9CgovLyDjgrnjgq/jg63jg7zjg6vjgZnjgovjgIIKdm9pZCBncF9TY3JvbGwodm9pZCkKewogICAgbWVtbW92ZShncF9idWZbMF0sIGdwX2J1ZlsxXSwgQ09MVU1OUyAqIChST1dTIC0gMSkpOwogICAgbWVtc2V0KGdwX2J1ZltST1dTIC0gMV0sICcgJywgQ09MVU1OUyk7Cn0KCi8vIOS4gOaWh+Wtl+WPs+OBq+enu+WLleOAggp2b2lkIGdwX01vdmVSaWdodCh2b2lkKQp7CiAgICArK2dwX2N4OwogICAgaWYgKGdwX2N4IDwgQ09MVU1OUykKICAgICAgICByZXR1cm47CgogICAgZ3BfY3ggPSAwOwogICAgKytncF9jeTsKICAgIGlmIChncF9jeSA8IFJPV1MpCiAgICAgICAgcmV0dXJuOwoKICAgIC0tZ3BfY3k7CiAgICBncF9TY3JvbGwoKTsKfQoKLy8g5pS56KGM44CCCnZvaWQgZ3BfTmV3TGluZSh2b2lkKQp7CiAgICBncF9jeCA9IDA7CiAgICArK2dwX2N5OwogICAgaWYgKGdwX2N5ID49IFJPV1MpCiAgICB7CiAgICAgICAgLS1ncF9jeTsKICAgICAgICBncF9TY3JvbGwoKTsKICAgIH0KfQoKLy8g5LiA5paH5a2X5Ye65Yqb44GZ44KL44CCCnZvaWQgZ3BfUHV0Q2hhcihjaGFyIGNoKQp7CiAgICBncF9idWZbZ3BfY3ldW2dwX2N4XSA9IChjaGFyKWNoOwogICAgZ3BfTW92ZVJpZ2h0KCk7Cn0KCi8vIOWFpeWKm+OCkuWPl+OBkeWPluOCi+OAggp2b2lkIGdwX1JlYWRJbnB1dCh2b2lkKQp7CiAgICBjaGFyIGNoID0gR2V0SW5wdXRDaGFyKFRSVUUpOwogICAgaWYgKGNoID09IDApCiAgICAgICAgcmV0dXJuOwoKICAgIGlmIChjaCA9PSAnXHInKQogICAgewogICAgICAgIGdwX05ld0xpbmUoKTsKICAgICAgICBncF9vdXRwdXQgPSBQUk9NUFQ7CiAgICAgICAgcmV0dXJuOwogICAgfQoKICAgIGdwX1B1dENoYXIoY2gpOwp9CgovLyDliJ3mnJ/ljJbjgpLooYzjgYbjgIIKdm9pZCBncF9Jbml0KHZvaWQpCnsKI2lmIDAKICAgIFRDSEFSIGdwX2J1ZlszMl07CiAgICB3c3ByaW50ZihncF9idWYsIFRFWFQoIiVkLCAlZCIpLCBDT05TT0xFX1dJRFRILCBDT05TT0xFX0hFSUdIVCk7CiAgICBNZXNzYWdlQm94KE5VTEwsIGdwX2J1ZiwgTlVMTCwgMCk7CiNlbmRpZgogICAgYXNzZXJ0KENPTlNPTEVfV0lEVEggPT0gNjQwKTsKICAgIGFzc2VydChDT05TT0xFX0hFSUdIVCA9PSA0ODApOwogICAgLy9hc3NlcnQoQ09OU09MRV9XSURUSCA9PSA4MDApOwogICAgLy9hc3NlcnQoQ09OU09MRV9IRUlHSFQgPT0gNjAwKTsKCiAgICBTZXREcmF3U2NyZWVuKERYX1NDUkVFTl9CQUNLKTsKICAgIG1lbXNldChncF9idWYsICcgJywgc2l6ZW9mKGdwX2J1ZikpOwogICAgZ3BfZm9udCA9IENyZWF0ZUZvbnRUb0hhbmRsZSgi77yt77yzIOOCtOOCt+ODg+OCryIsIENIQVJfSEVJR0hULCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEWF9GT05UVFlQRV9BTlRJQUxJQVNJTkcpOwoKICAgIGdwX291dHB1dCA9IFBST01QVDsKfQoKSU5UIFdJTkFQSSBXaW5NYWluKEhJTlNUQU5DRSwgSElOU1RBTkNFLCBMUFNUUiwgSU5UKQp7CiAgICBTZXRHcmFwaE1vZGUoQ09OU09MRV9XSURUSCwgQ09OU09MRV9IRUlHSFQsIDMyKTsKICAgIENoYW5nZVdpbmRvd01vZGUoVFJVRSk7CiAgICBpZiAoRHhMaWJfSW5pdCgpID09IC0xKQogICAgewogICAgICAgIHJldHVybiAtMTsKICAgIH0KCiAgICBncF9Jbml0KCk7CgogICAgLy8g54K55ruF55So44Gu44Kr44Km44Oz44K/44CCCiAgICBpbnQgY291bnRlciA9IEdldE5vd0NvdW50KCk7CgogICAgd2hpbGUgKCFTY3JlZW5GbGlwKCkgJiYgIVByb2Nlc3NNZXNzYWdlKCkgJiYgIUNsZWFyRHJhd1NjcmVlbigpKQogICAgewogICAgICAgIGdwX0RyYXdDb25zb2xlKCk7CiAgICAgICAgZ3BfUmVhZElucHV0KCk7CgogICAgICAgIC8vIOWHuuWKm+S4reOBi++8nwogICAgICAgIGlmIChncF9vdXRwdXQuZW1wdHkoKSkKICAgICAgICB7CiAgICAgICAgICAgIC8vIOeCuea7heOBruOBn+OCgeOAgeS4gOWumuaZgumWk+OBlOOBqOOBq+ODleODqeOCsOOCkuWIh+OCiuabv+OBiOOCi+OAggogICAgICAgICAgICBpZiAoR2V0Tm93Q291bnQoKSAtIGNvdW50ZXIgPj0gQkxJTktfUkFURSkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgZ3BfYmxpbmsgPSAhZ3BfYmxpbms7CiAgICAgICAgICAgICAgICBjb3VudGVyID0gR2V0Tm93Q291bnQoKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBlbHNlCiAgICAgICAgewogICAgICAgICAgICAvLyDkuIDmloflrZflh7rlipvjgZnjgovjgIIKICAgICAgICAgICAgZ3BfUHV0Q2hhcihncF9vdXRwdXRbMF0pOwogICAgICAgICAgICBncF9vdXRwdXQuZXJhc2UoZ3Bfb3V0cHV0LmJlZ2luKCkpOwoKICAgICAgICAgICAgZ3BfcHggPSBncF9jeDsKICAgICAgICAgICAgZ3BfcHkgPSBncF9jeTsKICAgICAgICAgICAgZ3BfYmxpbmsgPSBmYWxzZTsKICAgICAgICB9CiAgICB9CiAgICBEeExpYl9FbmQoKTsKICAgIHJldHVybiAwOwp9Cg==