Project X88000において開発・配布されているPC-8801エミュレータ。 ソースコードはPDSとして公開されており自由に改変できる。
Linux対応版とWindows版とがあり、Linux版は音声のサポートがない。
HAL研PCG-8800にPCGおよび音源まで含めて対応している。
高性能な反面、設定可能な項目は少なく、As Isで利用する場合は問題ないが、キーバインドを変更したい、あるいは、イメージファイルの拡張子の対応を増やしたいといったような場合には、ソースに手を入れて再構築する必要がある。
開発が止まって久しいので、Linux版はさておき、Windows版はある程度手を入れないとビルドすらままならない。
Windows版はDirectX7をターゲットに作成されており、Visual Studio 2019 Communityなどではコンパイルすらできない。 とはいえ、いくつかのポイントを修正すればビルド可能であり、現在でも手を入れたバージョンで遊ぶことが可能である。
よくわからないが、Debugフラグで構築したところ、Windows DefencerにTrojan.Script/Wacatac.B!ml
と判定され、駆除された。
Releaseフラグで構築すると特に何も言われないので、誤検出ではないかと思うが、不安な方は使わないほうがいいだろう。
typedef
を無効化する。LPDWORD
に変換できない)を起こすuint32_t
宣言の変数をすべてDWORD
宣言に変更する。dinput.lib
およびdinput.dll
はそれぞれdinput8.lib
およびdinput8.dll
に置き換える。X88irectX.cpp
内376行目付近から – 下記)#if 0 typedef HRESULT WINAPI DirectInputCreateProc( HINSTANCE, DWORD, IDirectInput**, IUnknown*); DirectInputCreateProc* pprocDirectInputCreate = (DirectInputCreateProc*) GetProcAddress(,_hlibDInput, "DirectInputCreateA"); if (pprocDirectInputCreate == NULL) { return false; } HRESULT hResult; // Direct Input hResult = pprocDirectInputCreate( (HINSTANCE)GetModuleHandle(NULL), DIRECTINPUT_VERSION, &m_pDI, NULL); #else typedef HRESULT WINAPI DirectInput8CreateProc(HINSTANCE,DWORD,REFIID,LPVOID*,LPUNKNOWN); DirectInput8CreateProc *pprocDirectInput8Create = (DirectInput8CreateProc*) GetProcAddress(m_hlibDInput, "DirectInput8Create"); if (pprocDirectInput8Create == NULL) { return false; } HRESULT hResult = pprocDirectInput8Create((HINSTANCE)GetModuleHandleW(NULL), DIRECTINPUT8_VERSION, IID_IDrectInput8W, (LPVOID*)&m_pDI, NULL); #endif if (hResult != DI_OK) { return false; }
(StdHeader.h
160行目付近の #define DIRECTINPUT_VERSION 0x0300
の下に、#define DIRECTINPUT8_VERSION 0x0800
を追加しておく。)
以上を修正するとバイナリを得ることができる。
X88000はエミュレータとしての完成度が高いものの、キーバインドを含め、設定可能な項目が非常に少ない。 ノートPCで遊ぶ場合など、テンキーがない環境では、カーソルキーにテンキーの2,4,6,8あるいは1,2,3,5などを割り当てて、快適にゲームを楽しみたいのだが、これができない。
なので、キー入力処理に手を入れて、カーソルキーの処理を変更する。 なお、ゲームによって、2,4,6,8または1,2,3,5で上下左右の割り当てになっているので、メニューから切り替えられるようにしておく。
リソースエディターで、メニューを追加する。
IDR_MAINMENU
(日本語)およびIDR_MAINMENU_E
(英語)の二つがあるので、両方に追加する。
それぞれのIDシンボルは以下のようにする。
キー処理はX88Frame
の中で行われているので、フラグを、X88Frame.cpp
およびX88Frame.h
に追加していく。
X88Frame.h
の93行目からフラグの宣言を追加。
91: // keyboard state table 92: static uint8_t m_abtKeyboardState[256]; 93:#if 1 94: // cursor key mapping 95: static uint8_t m_cursorMode; 96:#endif
X88Frame.cpp
の122行目からフラグのインスタンスを定義する。
118:// keyboard state table 119: 120:uint8_t CX88Frame::m_abtKeyboardState[256]; 121: 122:#if 1 123:// cursor keys 124:uint8_t CX88Frame::m_cursorMode = 0; 125:#endif
X88Frame.cpp
内CX88Frame::WndProc()
処理内に追加(汚い)
case IDM_VERSION: OnHelpMenuCommand(LOWORD(wParam)); break; #if 1 case IDM_CURSORKEYS_CURSOR: m_cursorMode = 0; CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_CURSOR, MFS_CHECKED); CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_2468, MFS_UNCHECKED); CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_1235, MFS_UNCHECKED); break; case IDM_CURSORKEYS_2468: m_cursorMode = 1; CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_CURSOR, MFS_UNCHECKED); CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_2468, MFS_CHECKED); CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_1235, MFS_UNCHECKED); break; case IDM_CURSORKEYS_1235: m_cursorMode = 2; CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_CURSOR, MFS_UNCHECKED); CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_2468, MFS_UNCHECKED); CheckMenuItem(GetMenu(hwnd), IDM_CURSORKEYS_1235, MFS_CHECKED); break; #endif } break;
本来は、ラジオボタンにするべきだろうが、今時のメニューはどうするべきなのかちゃんとわかってないので、汚い処理になっている。
X8Frame.cpp
内 CX88Frame::UpdateAllKeyMatrics()
処理内に以下の変更。
} else { bShift = IsKeyPressed(VK_SHIFT); } #if 0 bool bUpArrow = IsKeyPressed(VK_UP), bRightArrow = IsKeyPressed(VK_RIGHT); if (X88k().PC88().Z80Main().GetBasicMode() == CPC88Z80Main::BASICMODE_N80V1) { if (IsKeyPressed(VK_DOWN)) { bShift = bUpArrow = true; } if (IsKeyPressed(VK_LEFT)) { bShift = bRightArrow = true; } } #else bool bUpArrow = false, bRightArrow = false; if (m_cursorMode == 0||IsKeyPressed(VK_CONTROL)) { bUpArrow = IsKeyPressed(VK_UP); bRightArrow = IsKeyPressed(VK_RIGHT); if (X88k().PC88().Z80Main().GetBasicMode() == CPC88Z80Main::BASICMODE_N80V1) { if (IsKeyPressed(VK_DOWN)) { bShift = bUpArrow = true; } if (IsKeyPressed(VK_LEFT)) { bShift = bRightArrow = true; } } } else { if (IsKeyPressed(VK_DOWN) || IsKeyPressed(VK_LEFT) || IsKeyPressed(VK_RIGHT) || IsKeyPressed(VK_UP)) { if (m_cursorMode == 1) { X88k().SetKeyMatrics(0x00, 2, IsKeyPressed(VK_DOWN)); X88k().SetKeyMatrics(0x00, 4, IsKeyPressed(VK_LEFT)); X88k().SetKeyMatrics(0x00, 6, IsKeyPressed(VK_RIGHT)); X88k().SetKeyMatrics(0x01, 0, IsKeyPressed(VK_UP)); } else { X88k().SetKeyMatrics(0x00, 2, IsKeyPressed(VK_DOWN)); X88k().SetKeyMatrics(0x00, 1, IsKeyPressed(VK_LEFT)); X88k().SetKeyMatrics(0x00, 3, IsKeyPressed(VK_RIGHT)); X88k().SetKeyMatrics(0x00, 5, IsKeyPressed(VK_UP)); } return; } } #endif X88k().SetKeyMatrics(0x00, 0, IsKeyPressed(VK_NUMPAD0)); X88k().SetKeyMatrics(0x00, 1, IsKeyPressed(VK_NUMPAD1)); ... } else { bShift = IsKeyPressed(DIK_LSHIFT, DIK_RSHIFT); } #if 0 bool bUpArrow = IsKeyPressed(DIK_UP), bRightArrow = IsKeyPressed(DIK_RIGHT); if (X88k().PC88().Z80Main().GetBasicMode() == CPC88Z80Main::BASICMODE_N80V1) { if (IsKeyPressed(DIK_DOWN)) { bShift = bUpArrow = true; } if (IsKeyPressed(DIK_LEFT)) { bShift = bRightArrow = true; } } #else bool bUpArrow = false, bRightArrow = false; if (m_cursorMode == 0||IsKeyPressed(DIK_LCONTROL, DIK_RCONTROL)) { bUpArrow = IsKeyPressed(DIK_UP); bRightArrow = IsKeyPressed(DIK_RIGHT); if (X88k().PC88().Z80Main().GetBasicMode() == CPC88Z80Main::BASICMODE_N80V1) { if (IsKeyPressed(DIK_DOWN)) { bShift = bUpArrow = true; } if (IsKeyPressed(DIK_LEFT)) { bShift = bRightArrow = true; } } } else { if (IsKeyPressed(DIK_DOWN) || IsKeyPressed(DIK_LEFT) || IsKeyPressed(DIK_RIGHT) || IsKeyPressed(DIK_UP)) { if (m_cursorMode == 1) { X88k().SetKeyMatrics(0x00, 2, IsKeyPressed(DIK_DOWN)); X88k().SetKeyMatrics(0x00, 4, IsKeyPressed(DIK_LEFT)); X88k().SetKeyMatrics(0x00, 6, IsKeyPressed(DIK_RIGHT)); X88k().SetKeyMatrics(0x01, 0, IsKeyPressed(DIK_UP)); } else { X88k().SetKeyMatrics(0x00, 2, IsKeyPressed(DIK_DOWN)); X88k().SetKeyMatrics(0x00, 1, IsKeyPressed(DIK_LEFT)); X88k().SetKeyMatrics(0x00, 3, IsKeyPressed(DIK_RIGHT)); X88k().SetKeyMatrics(0x00, 5, IsKeyPressed(DIK_UP)); } return; } } #endif X88k().SetKeyMatric(0x00, 0, IsKeyPressed(DIK_NUMPAD0));
#if 0
で無効化しているのがもともとのカーソルキー処理。
PC-8001などは、カーソルキーが縮退1)しているので、その処理をしている。
ここで、m_cursorMode
が0かコントロールキーが押されていたら、カーソルキーとして処理し、そうでなければ、テンキーの振りをするだけである。