Add /input command in http server

This commit is contained in:
offtkp 2023-07-10 00:57:59 +03:00
parent 0949a16e6f
commit 77ea84373f
2 changed files with 87 additions and 5 deletions

View file

@ -17,7 +17,7 @@
enum class ROMType { None, ELF, NCSD, CXI }; enum class ROMType { None, ELF, NCSD, CXI };
enum class HttpAction { None, Screenshot }; enum class HttpAction { None, Screenshot, PressKey, ReleaseKey };
class Emulator { class Emulator {
CPU cpu; CPU cpu;
@ -52,6 +52,7 @@ class Emulator {
std::atomic_bool pendingAction = false; std::atomic_bool pendingAction = false;
HttpAction action = HttpAction::None; HttpAction action = HttpAction::None;
std::mutex actionMutex = {}; std::mutex actionMutex = {};
u32 pendingKey = 0;
#endif #endif
// Keep the handle for the ROM here to reload when necessary and to prevent deleting it // Keep the handle for the ROM here to reload when necessary and to prevent deleting it

View file

@ -118,6 +118,11 @@ void Emulator::run() {
startHttpServer(); startHttpServer();
#endif #endif
while (running) { while (running) {
runFrame(); // Run 1 frame of instructions
gpu.display(); // Display graphics
ServiceManager& srv = kernel.getServiceManager();
#ifdef PANDA3DS_ENABLE_HTTP_SERVER #ifdef PANDA3DS_ENABLE_HTTP_SERVER
{ {
std::scoped_lock lock(actionMutex); std::scoped_lock lock(actionMutex);
@ -127,19 +132,30 @@ void Emulator::run() {
screenshot(httpServerScreenshotPath); screenshot(httpServerScreenshotPath);
break; break;
} }
case HttpAction::PressKey: {
if (pendingKey != 0) {
srv.pressKey(pendingKey);
pendingKey = 0;
}
break;
}
case HttpAction::ReleaseKey: {
if (pendingKey != 0) {
srv.releaseKey(pendingKey);
pendingKey = 0;
}
break;
}
case HttpAction::None: { case HttpAction::None: {
break; break;
} }
} }
action = HttpAction::None;
pendingAction = false; pendingAction = false;
pendingAction.notify_all(); pendingAction.notify_all();
} }
} }
#endif #endif
runFrame(); // Run 1 frame of instructions
gpu.display(); // Display graphics
ServiceManager& srv = kernel.getServiceManager();
// Send VBlank interrupts // Send VBlank interrupts
srv.sendGPUInterrupt(GPUInterrupt::VBlank0); srv.sendGPUInterrupt(GPUInterrupt::VBlank0);
@ -443,12 +459,42 @@ void Emulator::initGraphicsContext() {
} }
#ifdef PANDA3DS_ENABLE_HTTP_SERVER #ifdef PANDA3DS_ENABLE_HTTP_SERVER
u32 stringToKey(const std::string& key_name) {
namespace Keys = HID::Keys;
static std::map<std::string, u32> keyMap = {
{"A", Keys::A},
{"B", Keys::B},
{"Select", Keys::Select},
{"Start", Keys::Start},
{"Right", Keys::Right},
{"Left", Keys::Left},
{"Up", Keys::Up},
{"Down", Keys::Down},
{"R", Keys::R},
{"L", Keys::L},
{"X", Keys::X},
{"Y", Keys::Y},
{"CirclePadRight", Keys::CirclePadRight},
{"CirclePadLeft", Keys::CirclePadLeft},
{"CirclePadUp", Keys::CirclePadUp},
{"CirclePadDown", Keys::CirclePadDown},
};
if (keyMap.find(key_name) != keyMap.end()) {
return keyMap[key_name];
}
return 0;
}
void Emulator::startHttpServer() { void Emulator::startHttpServer() {
std::thread http_thread([this]() { std::thread http_thread([this]() {
httplib::Server server; httplib::Server server;
server.Get("/ping", [](const httplib::Request&, httplib::Response& response) { server.Get("/ping", [](const httplib::Request&, httplib::Response& response) {
response.set_content("pong", "text/plain"); response.set_content("pong", "text/plain");
}); });
server.Get("/screen", [this](const httplib::Request&, httplib::Response& response) { server.Get("/screen", [this](const httplib::Request&, httplib::Response& response) {
{ {
std::scoped_lock lock(actionMutex); std::scoped_lock lock(actionMutex);
@ -461,6 +507,41 @@ void Emulator::startHttpServer() {
std::vector<char> buffer(std::istreambuf_iterator<char>(image), {}); std::vector<char> buffer(std::istreambuf_iterator<char>(image), {});
response.set_content(buffer.data(), buffer.size(), "image/png"); response.set_content(buffer.data(), buffer.size(), "image/png");
}); });
server.Get("/input", [this](const httplib::Request& request, httplib::Response& response) {
bool ok = false;
for (auto& [keyStr, value]: request.params) {
auto key = stringToKey(keyStr);
printf("Param: %s\n", keyStr.c_str());
if (key != 0) {
std::scoped_lock lock(actionMutex);
pendingAction = true;
pendingKey = key;
ok = true;
if (value == "1") {
action = HttpAction::PressKey;
} else if (value == "0") {
action = HttpAction::ReleaseKey;
} else {
// Should not happen but just in case
pendingAction = false;
ok = false;
}
// Not supporting multiple keys at once for now (ever?)
break;
}
}
if (ok) {
response.set_content("ok", "text/plain");
}
});
server.Get("/step", [this](const httplib::Request&, httplib::Response& response) {
// TODO: implement /step
response.set_content("ok", "text/plain");
});
// TODO: ability to specify host and port // TODO: ability to specify host and port
printf("Starting HTTP server on port 1234\n"); printf("Starting HTTP server on port 1234\n");
server.listen("localhost", 1234); server.listen("localhost", 1234);