Adds InputWindowElement.
This commit is contained in:
parent
11279acb02
commit
a07c61675e
@ -148,6 +148,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\Font.cc" />
|
<ClCompile Include="src\Font.cc" />
|
||||||
<ClCompile Include="src\Game.cc" />
|
<ClCompile Include="src\Game.cc" />
|
||||||
|
<ClCompile Include="src\HiraganaMatcher.cc" />
|
||||||
<ClCompile Include="src\Lua.cc" />
|
<ClCompile Include="src\Lua.cc" />
|
||||||
<ClCompile Include="src\main.cc" />
|
<ClCompile Include="src\main.cc" />
|
||||||
<ClCompile Include="src\PlayScene.cc" />
|
<ClCompile Include="src\PlayScene.cc" />
|
||||||
@ -155,6 +156,8 @@
|
|||||||
<ClCompile Include="src\Win32Console.cc" />
|
<ClCompile Include="src\Win32Console.cc" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="src\HiraganaMatcher.h" />
|
||||||
|
<ClInclude Include="src\iInputMatcher.h" />
|
||||||
<ClInclude Include="src\common.h" />
|
<ClInclude Include="src\common.h" />
|
||||||
<ClInclude Include="src\ElementStore.h" />
|
<ClInclude Include="src\ElementStore.h" />
|
||||||
<ClInclude Include="src\Font.h" />
|
<ClInclude Include="src\Font.h" />
|
||||||
@ -166,6 +169,7 @@
|
|||||||
<ClInclude Include="src\iElementFactory.h" />
|
<ClInclude Include="src\iElementFactory.h" />
|
||||||
<ClInclude Include="src\iLogger.h" />
|
<ClInclude Include="src\iLogger.h" />
|
||||||
<ClInclude Include="src\iClock.h" />
|
<ClInclude Include="src\iClock.h" />
|
||||||
|
<ClInclude Include="src\InputWindowElementFactory.h" />
|
||||||
<ClInclude Include="src\iScene.h" />
|
<ClInclude Include="src\iScene.h" />
|
||||||
<ClInclude Include="src\iWritable.h" />
|
<ClInclude Include="src\iWritable.h" />
|
||||||
<ClInclude Include="src\Logger.h" />
|
<ClInclude Include="src\Logger.h" />
|
||||||
@ -181,6 +185,7 @@
|
|||||||
<ClInclude Include="src\StackAllocator.h" />
|
<ClInclude Include="src\StackAllocator.h" />
|
||||||
<ClInclude Include="src\SystemClock.h" />
|
<ClInclude Include="src\SystemClock.h" />
|
||||||
<ClInclude Include="src\Text.h" />
|
<ClInclude Include="src\Text.h" />
|
||||||
|
<ClInclude Include="src\InputWindowElement.h" />
|
||||||
<ClInclude Include="src\Texture.h" />
|
<ClInclude Include="src\Texture.h" />
|
||||||
<ClInclude Include="src\TextureElement.h" />
|
<ClInclude Include="src\TextureElement.h" />
|
||||||
<ClInclude Include="src\TickingClock.h" />
|
<ClInclude Include="src\TickingClock.h" />
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
<ClCompile Include="src\PlayScene.cc">
|
<ClCompile Include="src\PlayScene.cc">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\HiraganaMatcher.cc">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\iConsole.h">
|
<ClInclude Include="src\iConsole.h">
|
||||||
@ -155,6 +158,18 @@
|
|||||||
<ClInclude Include="thirdparty\utf8.h">
|
<ClInclude Include="thirdparty\utf8.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\InputWindowElement.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\iInputMatcher.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\HiraganaMatcher.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\InputWindowElementFactory.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Library Include="thirdparty\lua5.1.lib" />
|
<Library Include="thirdparty\lua5.1.lib" />
|
||||||
|
@ -53,6 +53,7 @@ class ElementStore {
|
|||||||
for (auto& eptr : performing_) {
|
for (auto& eptr : performing_) {
|
||||||
iElement* e = eptr.get();
|
iElement* e = eptr.get();
|
||||||
if (e->period.end <= now) {
|
if (e->period.end <= now) {
|
||||||
|
e->Finalize();
|
||||||
eptr = nullptr;
|
eptr = nullptr;
|
||||||
} else {
|
} else {
|
||||||
e->Update(frame, e->period.Normalize(now));
|
e->Update(frame, e->period.Normalize(now));
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "iDrawable.h"
|
#include "iDrawable.h"
|
||||||
@ -46,6 +47,8 @@ class Frame : public iDrawable, public iWritable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string input;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<const iDrawable*> draw_;
|
std::vector<const iDrawable*> draw_;
|
||||||
std::vector<const iWritable*> write_;
|
std::vector<const iWritable*> write_;
|
||||||
|
@ -36,10 +36,12 @@ class Game : public iDrawable, public iWritable {
|
|||||||
|
|
||||||
Game(Param&& p);
|
Game(Param&& p);
|
||||||
|
|
||||||
void Update() {
|
void Update(const std::string& input) {
|
||||||
clock_.Tick();
|
clock_.Tick();
|
||||||
|
|
||||||
frame_.Clear();
|
frame_.Clear();
|
||||||
|
frame_.input = input;
|
||||||
|
|
||||||
UniqPtr<iScene> next = scene_->Update(frame_);
|
UniqPtr<iScene> next = scene_->Update(frame_);
|
||||||
if (next) {
|
if (next) {
|
||||||
scene_ = std::move(next);
|
scene_ = std::move(next);
|
||||||
|
@ -30,7 +30,7 @@ class GlyphElementFactory : public iElementFactory {
|
|||||||
const intmax_t size = std::get<double>(param.custom[2]);
|
const intmax_t size = std::get<double>(param.custom[2]);
|
||||||
|
|
||||||
auto& font = FindOrCreateFont(name);
|
auto& font = FindOrCreateFont(name);
|
||||||
auto tex = std::move(font.RenderGlyphs(ConvertUtf8ToUtf16(text), size)); /* TODO */
|
auto tex = std::move(font.RenderGlyphs(ConvertStrToWstr(text), size)); /* TODO */
|
||||||
|
|
||||||
return alloc_->MakeUniq<iElement, TextureElement>(
|
return alloc_->MakeUniq<iElement, TextureElement>(
|
||||||
param.period, std::move(tex), std::move(param.driver));
|
param.period, std::move(tex), std::move(param.driver));
|
||||||
|
99
src/HiraganaMatcher.cc
Normal file
99
src/HiraganaMatcher.cc
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include "HiraganaMatcher.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const std::vector<std::pair<std::wstring, std::wstring>> kPatterns = {
|
||||||
|
{ L"ka", L"か", },
|
||||||
|
{ L"ki", L"き", },
|
||||||
|
{ L"ku", L"く", },
|
||||||
|
{ L"ke", L"け", },
|
||||||
|
{ L"ko", L"こ", },
|
||||||
|
{ L"sa", L"さ", },
|
||||||
|
{ L"si", L"し", },
|
||||||
|
{ L"su", L"す", },
|
||||||
|
{ L"se", L"せ", },
|
||||||
|
{ L"so", L"そ", },
|
||||||
|
{ L"ta", L"た", },
|
||||||
|
{ L"ti", L"ち", },
|
||||||
|
{ L"tu", L"つ", },
|
||||||
|
{ L"te", L"て", },
|
||||||
|
{ L"to", L"と", },
|
||||||
|
{ L"na", L"な", },
|
||||||
|
{ L"ni", L"に", },
|
||||||
|
{ L"nu", L"ぬ", },
|
||||||
|
{ L"ne", L"ね", },
|
||||||
|
{ L"no", L"の", },
|
||||||
|
{ L"a", L"あ", },
|
||||||
|
{ L"i", L"い", },
|
||||||
|
{ L"u", L"う", },
|
||||||
|
{ L"e", L"え", },
|
||||||
|
{ L"o", L"お", },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool gj::HiraganaMatcher::Input(wchar_t c) {
|
||||||
|
assert(!done());
|
||||||
|
|
||||||
|
const std::wstring remain = state_.text.substr(state_.match);
|
||||||
|
const std::wstring newbuf = buffer_ + c;
|
||||||
|
|
||||||
|
const size_t n = newbuf.size();
|
||||||
|
|
||||||
|
size_t last_match = 0;
|
||||||
|
bool accept = false;
|
||||||
|
for (size_t i = 0; i < kPatterns.size(); ++i) {
|
||||||
|
const auto& pattern = kPatterns[i];
|
||||||
|
if (pattern.first.substr(0, n) == newbuf) {
|
||||||
|
const size_t pn = pattern.second.size();
|
||||||
|
if (remain.substr(0, pn) == pattern.second) {
|
||||||
|
accept = true;
|
||||||
|
last_match = i;
|
||||||
|
}
|
||||||
|
if (pattern.first.size() == n) {
|
||||||
|
if (!accept) return false;
|
||||||
|
state_.match += pn;
|
||||||
|
buffer_ = L"";
|
||||||
|
UpdateExpects(i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accept) {
|
||||||
|
buffer_ = newbuf;
|
||||||
|
UpdateExpects(last_match);
|
||||||
|
}
|
||||||
|
return accept;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gj::HiraganaMatcher::UpdateExpects(size_t last_match) {
|
||||||
|
std::wstring text = state_.text.substr(state_.match);
|
||||||
|
|
||||||
|
expects_ = L"";
|
||||||
|
if (text.empty()) return;
|
||||||
|
|
||||||
|
if (last_match < SIZE_MAX && buffer_.size()) {
|
||||||
|
expects_ = kPatterns[last_match].first.substr(buffer_.size());
|
||||||
|
text = text.substr(kPatterns[last_match].second.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (text.size()) {
|
||||||
|
bool match = false;
|
||||||
|
for (const auto& pattern : kPatterns) {
|
||||||
|
const size_t n = pattern.second.size();
|
||||||
|
if (text.size() < n) continue;
|
||||||
|
|
||||||
|
if (text.substr(0, n) == pattern.second) {
|
||||||
|
expects_ += pattern.first;
|
||||||
|
text = text.substr(n);
|
||||||
|
match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!match) Abort("hiragana janai");
|
||||||
|
}
|
||||||
|
}
|
44
src/HiraganaMatcher.h
Normal file
44
src/HiraganaMatcher.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "iInputMatcher.h"
|
||||||
|
|
||||||
|
namespace gj {
|
||||||
|
|
||||||
|
|
||||||
|
class HiraganaMatcher : public iInputMatcher {
|
||||||
|
public:
|
||||||
|
HiraganaMatcher(HiraganaMatcher&&) = default;
|
||||||
|
HiraganaMatcher(const HiraganaMatcher&) = default;
|
||||||
|
|
||||||
|
HiraganaMatcher& operator=(HiraganaMatcher&&) = default;
|
||||||
|
HiraganaMatcher& operator=(const HiraganaMatcher&) = default;
|
||||||
|
|
||||||
|
HiraganaMatcher(const std::wstring& text) : state_{text, 0} {
|
||||||
|
UpdateExpects();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Input(wchar_t c) override;
|
||||||
|
|
||||||
|
const std::wstring& expects() const override {
|
||||||
|
return expects_;
|
||||||
|
}
|
||||||
|
bool done() const override {
|
||||||
|
return state_.text.size() <= state_.match;
|
||||||
|
}
|
||||||
|
const State& state() const override {
|
||||||
|
return state_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::wstring buffer_;
|
||||||
|
std::wstring expects_;
|
||||||
|
|
||||||
|
State state_;
|
||||||
|
|
||||||
|
void UpdateExpects(size_t last_match = SIZE_MAX);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
73
src/InputWindowElement.h
Normal file
73
src/InputWindowElement.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "iElement.h"
|
||||||
|
#include "iElementDriver.h"
|
||||||
|
#include "iInputMatcher.h"
|
||||||
|
#include "Text.h"
|
||||||
|
|
||||||
|
namespace gj {
|
||||||
|
|
||||||
|
|
||||||
|
class InputWindowElement : public iElement {
|
||||||
|
public:
|
||||||
|
struct Param {
|
||||||
|
UniqPtr<iInputMatcher> matcher;
|
||||||
|
UniqPtr<iElementDriver> driver;
|
||||||
|
|
||||||
|
Period period;
|
||||||
|
|
||||||
|
std::wstring text;
|
||||||
|
};
|
||||||
|
|
||||||
|
InputWindowElement() = delete;
|
||||||
|
InputWindowElement(InputWindowElement&&) = delete;
|
||||||
|
InputWindowElement(const InputWindowElement&) = delete;
|
||||||
|
|
||||||
|
InputWindowElement& operator=(InputWindowElement&&) = delete;
|
||||||
|
InputWindowElement& operator=(const InputWindowElement&) = delete;
|
||||||
|
|
||||||
|
InputWindowElement(Param&& p) :
|
||||||
|
iElement(p.period),
|
||||||
|
matcher_(std::move(p.matcher)), drv_(std::move(p.driver)),
|
||||||
|
text_(p.text), guide_(matcher_->expects()) {
|
||||||
|
param_["posX"] = 0;
|
||||||
|
param_["posY"] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(Frame& frame, double t) override {
|
||||||
|
for (auto c : frame.input) {
|
||||||
|
if (matcher_->done()) break;
|
||||||
|
if (matcher_->Input(c)) {
|
||||||
|
guide_ = Text(matcher_->expects());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drv_->Update(param_, t);
|
||||||
|
|
||||||
|
const auto posX = std::get<intmax_t>(param_["posX"]);
|
||||||
|
const auto posY = std::get<intmax_t>(param_["posY"]);
|
||||||
|
|
||||||
|
text_.SetPosition(posX, posY);
|
||||||
|
guide_.SetPosition(posX, posY+1);
|
||||||
|
frame.Add(&text_);
|
||||||
|
frame.Add(&guide_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Finalize() override {
|
||||||
|
/* TODO score calculation */
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UniqPtr<iInputMatcher> matcher_;
|
||||||
|
UniqPtr<iElementDriver> drv_;
|
||||||
|
|
||||||
|
Text text_;
|
||||||
|
Text guide_;
|
||||||
|
|
||||||
|
iElementDriver::Param param_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
45
src/InputWindowElementFactory.h
Normal file
45
src/InputWindowElementFactory.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "HiraganaMatcher.h"
|
||||||
|
#include "iAllocator.h"
|
||||||
|
#include "iClock.h"
|
||||||
|
#include "iElementFactory.h"
|
||||||
|
#include "InputWindowElement.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace gj {
|
||||||
|
|
||||||
|
|
||||||
|
class InputWindowElementFactory : public iElementFactory {
|
||||||
|
public:
|
||||||
|
InputWindowElementFactory(InputWindowElementFactory&&) = delete;
|
||||||
|
InputWindowElementFactory(const InputWindowElementFactory&) = delete;
|
||||||
|
|
||||||
|
InputWindowElementFactory& operator=(InputWindowElementFactory&&) = delete;
|
||||||
|
InputWindowElementFactory& operator=(const InputWindowElementFactory&) = delete;
|
||||||
|
|
||||||
|
InputWindowElementFactory(iAllocator* alloc) : alloc_(alloc) {
|
||||||
|
}
|
||||||
|
|
||||||
|
UniqPtr<iElement> Create(Param&& param) override {
|
||||||
|
if (param.custom.size() != 2) return nullptr;
|
||||||
|
|
||||||
|
const std::string text = std::get<std::string>(param.custom[0]);
|
||||||
|
const std::string kana = std::get<std::string>(param.custom[1]);
|
||||||
|
|
||||||
|
InputWindowElement::Param p;
|
||||||
|
p.period = param.period;
|
||||||
|
p.driver = std::move(param.driver);
|
||||||
|
p.matcher = alloc_->MakeUniq<iInputMatcher, HiraganaMatcher>(ConvertStrToWstr(kana));
|
||||||
|
p.text = ConvertStrToWstr(text);
|
||||||
|
|
||||||
|
return alloc_->MakeUniq<iElement, InputWindowElement>(std::move(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
iAllocator* alloc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,15 +1,18 @@
|
|||||||
#include "PlayScene.h"
|
#include "PlayScene.h"
|
||||||
|
|
||||||
#include "GlyphElementFactory.h"
|
#include "GlyphElementFactory.h"
|
||||||
|
#include "InputWindowElementFactory.h"
|
||||||
|
|
||||||
|
|
||||||
gj::PlayScene::PlayScene(Param&& p) :
|
gj::PlayScene::PlayScene(Param&& p) :
|
||||||
alloc_(p.alloc), logger_(p.logger), w_(p.w), h_(p.h),
|
alloc_(p.alloc), logger_(p.logger), w_(p.w), h_(p.h),
|
||||||
clock_(p.clock), store_(&clock_, 256) {
|
clock_(p.clock), store_(&clock_, 256) {
|
||||||
GlyphElementFactory glyph(alloc_);
|
GlyphElementFactory glyph(alloc_);
|
||||||
|
InputWindowElementFactory inputWin(alloc_);
|
||||||
|
|
||||||
Lua::FactoryMap map;
|
Lua::FactoryMap map;
|
||||||
map["Glyph"] = &glyph;
|
map["Glyph"] = &glyph;
|
||||||
|
map["InputWin"] = &inputWin;
|
||||||
|
|
||||||
lua_ = alloc_->MakeUniq<Lua>(
|
lua_ = alloc_->MakeUniq<Lua>(
|
||||||
alloc_, &store_, map, "res/score/" + p.score + ".lua");
|
alloc_, &store_, map, "res/score/" + p.score + ".lua");
|
||||||
|
@ -44,6 +44,9 @@ public:
|
|||||||
frame.Add(&tex_);
|
frame.Add(&tex_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Finalize() override {
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Texture tex_;
|
Texture tex_;
|
||||||
UniqPtr<iElementDriver> drv_;
|
UniqPtr<iElementDriver> drv_;
|
||||||
|
@ -47,6 +47,35 @@ void gj::Win32Console::main() {
|
|||||||
constexpr CONSOLE_CURSOR_INFO cursor{ 1, FALSE };
|
constexpr CONSOLE_CURSOR_INFO cursor{ 1, FALSE };
|
||||||
SetConsoleCursorInfo(screen_, &cursor);
|
SetConsoleCursorInfo(screen_, &cursor);
|
||||||
|
|
||||||
|
/* read input */
|
||||||
|
{ /* critical section */
|
||||||
|
std::lock_guard<std::mutex> _(mtx_);
|
||||||
|
|
||||||
|
INPUT_RECORD input[256];
|
||||||
|
DWORD input_n;
|
||||||
|
PeekConsoleInput(buffer_, input, 256, &input_n);
|
||||||
|
if (input_n) {
|
||||||
|
/* Peek* can retrieve the input but doesn't remove it from the buffer
|
||||||
|
* so calls Read* to clear. */
|
||||||
|
ReadConsoleInput(buffer_, input, 256, &input_n);
|
||||||
|
}
|
||||||
|
for (DWORD i = 0; i < input_n; ++i) {
|
||||||
|
const auto& rec = input[i];
|
||||||
|
switch (rec.EventType) {
|
||||||
|
case KEY_EVENT:
|
||||||
|
if (rec.Event.KeyEvent.bKeyDown) {
|
||||||
|
input_ += rec.Event.KeyEvent.uChar.AsciiChar;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* write output */
|
||||||
CHAR_INFO* c = chars_.get();
|
CHAR_INFO* c = chars_.get();
|
||||||
{ /* critical section */
|
{ /* critical section */
|
||||||
std::lock_guard<std::mutex> _(mtx_);
|
std::lock_guard<std::mutex> _(mtx_);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -10,6 +11,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#undef NOMINMAX
|
#undef NOMINMAX
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
#include "iConsole.h"
|
#include "iConsole.h"
|
||||||
|
|
||||||
|
|
||||||
@ -32,10 +34,13 @@ class Win32Console : public iConsole {
|
|||||||
tb_main_(alloc, w, h), tb_sub_(alloc, w, h),
|
tb_main_(alloc, w, h), tb_sub_(alloc, w, h),
|
||||||
chars_(std::make_unique<CHAR_INFO[]>(static_cast<uint64_t>(w)*h)),
|
chars_(std::make_unique<CHAR_INFO[]>(static_cast<uint64_t>(w)*h)),
|
||||||
win_(GetConsoleWindow()) {
|
win_(GetConsoleWindow()) {
|
||||||
_ASSERT(win_);
|
if (!win_) gj::Abort("GetConsoleWindow returned nullptr");
|
||||||
|
|
||||||
screen_ = GetStdHandle(STD_OUTPUT_HANDLE);
|
screen_ = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
_ASSERT(screen_ != INVALID_HANDLE_VALUE);
|
buffer_ = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
if (screen_ == INVALID_HANDLE_VALUE || buffer_ == INVALID_HANDLE_VALUE) {
|
||||||
|
gj::Abort("GetStdHandle returned nullptr");
|
||||||
|
}
|
||||||
|
|
||||||
CONSOLE_SCREEN_BUFFER_INFOEX size;
|
CONSOLE_SCREEN_BUFFER_INFOEX size;
|
||||||
size.cbSize = sizeof(size);
|
size.cbSize = sizeof(size);
|
||||||
@ -83,6 +88,13 @@ class Win32Console : public iConsole {
|
|||||||
std::swap(tb_main_, tb_sub_);
|
std::swap(tb_main_, tb_sub_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TakeInput() override {
|
||||||
|
std::lock_guard<std::mutex> _(mtx_);
|
||||||
|
std::string ret = std::move(input_);
|
||||||
|
input_ = "";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t width() const override {
|
uint32_t width() const override {
|
||||||
return w_;
|
return w_;
|
||||||
}
|
}
|
||||||
@ -107,8 +119,11 @@ class Win32Console : public iConsole {
|
|||||||
std::unique_ptr<CHAR_INFO[]> chars_;
|
std::unique_ptr<CHAR_INFO[]> chars_;
|
||||||
|
|
||||||
HANDLE screen_ = INVALID_HANDLE_VALUE;
|
HANDLE screen_ = INVALID_HANDLE_VALUE;
|
||||||
|
HANDLE buffer_ = INVALID_HANDLE_VALUE;
|
||||||
HWND win_ = nullptr;
|
HWND win_ = nullptr;
|
||||||
|
|
||||||
|
std::string input_;
|
||||||
|
|
||||||
void main();
|
void main();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ using mat3 = ::linalg::mat<double, 3, 3>;
|
|||||||
using vec3 = ::linalg::vec<double, 3>;
|
using vec3 = ::linalg::vec<double, 3>;
|
||||||
|
|
||||||
|
|
||||||
static inline std::wstring ConvertUtf8ToUtf16(const std::string& str) {
|
static inline std::wstring ConvertStrToWstr(const std::string& str) {
|
||||||
std::wstring ret;
|
std::wstring ret;
|
||||||
|
|
||||||
const void* c = str.c_str();
|
const void* c = str.c_str();
|
||||||
@ -33,7 +33,7 @@ static inline std::wstring ConvertUtf8ToUtf16(const std::string& str) {
|
|||||||
|
|
||||||
[[noreturn]]
|
[[noreturn]]
|
||||||
static inline void Abort(const std::string& msg) {
|
static inline void Abort(const std::string& msg) {
|
||||||
MessageBox(NULL, ConvertUtf8ToUtf16(msg).c_str(), L"PROGRAM ABORTED", MB_OK);
|
MessageBox(NULL, ConvertStrToWstr(msg).c_str(), L"PROGRAM ABORTED", MB_OK);
|
||||||
std::exit(1);
|
std::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@ class iConsole {
|
|||||||
virtual Textbuffer& TakeTextbuffer() = 0;
|
virtual Textbuffer& TakeTextbuffer() = 0;
|
||||||
virtual void SwapTextbuffer() = 0;
|
virtual void SwapTextbuffer() = 0;
|
||||||
|
|
||||||
|
virtual std::string TakeInput() = 0;
|
||||||
|
|
||||||
virtual uint32_t width() const = 0;
|
virtual uint32_t width() const = 0;
|
||||||
virtual uint32_t height() const = 0;
|
virtual uint32_t height() const = 0;
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,8 @@ class iElement {
|
|||||||
|
|
||||||
virtual void Update(Frame& frame, double t) = 0;
|
virtual void Update(Frame& frame, double t) = 0;
|
||||||
|
|
||||||
|
virtual void Finalize() = 0;
|
||||||
|
|
||||||
/* Interfaces had better not have a variable but this is for optimization. */
|
/* Interfaces had better not have a variable but this is for optimization. */
|
||||||
const Period period;
|
const Period period;
|
||||||
};
|
};
|
||||||
|
35
src/iInputMatcher.h
Normal file
35
src/iInputMatcher.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
namespace gj {
|
||||||
|
|
||||||
|
|
||||||
|
class iInputMatcher {
|
||||||
|
public:
|
||||||
|
struct State {
|
||||||
|
std::wstring text;
|
||||||
|
size_t match;
|
||||||
|
};
|
||||||
|
|
||||||
|
iInputMatcher(iInputMatcher&&) = default;
|
||||||
|
iInputMatcher(const iInputMatcher&) = default;
|
||||||
|
|
||||||
|
iInputMatcher& operator=(iInputMatcher&&) = default;
|
||||||
|
iInputMatcher& operator=(const iInputMatcher&) = default;
|
||||||
|
|
||||||
|
iInputMatcher() = default;
|
||||||
|
virtual ~iInputMatcher() = default;
|
||||||
|
|
||||||
|
virtual bool Input(wchar_t c) = 0;
|
||||||
|
|
||||||
|
virtual const std::wstring& expects() const = 0;
|
||||||
|
|
||||||
|
virtual bool done() const = 0;
|
||||||
|
|
||||||
|
virtual const State& state() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -32,7 +32,7 @@ int main() {
|
|||||||
param.h = kHeight;
|
param.h = kHeight;
|
||||||
gj::Game game(std::move(param));
|
gj::Game game(std::move(param));
|
||||||
while (true) {
|
while (true) {
|
||||||
game.Update();
|
game.Update(console.TakeInput());
|
||||||
{
|
{
|
||||||
auto& fb = console.TakeColorbuffer();
|
auto& fb = console.TakeColorbuffer();
|
||||||
fb.Clear();
|
fb.Clear();
|
||||||
|
Reference in New Issue
Block a user