Files
Renderive/web_server/Web_Event_Adapter.cpp
T
2026-08-11 14:55:46 +08:00

224 lines
8.1 KiB
C++

#include "Web_Event_Adapter.h"
#include <json/json.h>
#include <algorithm>
#include <cmath>
#include <memory>
#include <string>
namespace renderive::web {
namespace {
std::optional<Json::Value> parse_json(std::string_view message) {
Json::CharReaderBuilder builder;
builder["collectComments"] = false;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value root;
std::string errors;
if (!reader->parse(message.data(), message.data() + message.size(), &root, &errors) ||
!root.isObject()) {
return std::nullopt;
}
return root;
}
std::optional<double> finite_number(const Json::Value& root, const char* name) {
const auto& value = root[name];
if (!value.isNumeric())
return std::nullopt;
const double result = value.asDouble();
return std::isfinite(result) ? std::optional<double>(result) : std::nullopt;
}
std::optional<bool> boolean(const Json::Value& root, const char* name) {
const auto& value = root[name];
return value.isBool() ? std::optional<bool>(value.asBool()) : std::nullopt;
}
Keyboard_Modifier modifiers(const Json::Value& root) {
const int value = root["modifiers"].isInt() ? root["modifiers"].asInt() : 0;
return static_cast<Keyboard_Modifier>(std::clamp(value, 0, 15));
}
Mouse_Button mouse_button(const Json::Value& root) {
const std::string value = root["button"].isString() ? root["button"].asString() : "none";
if (value == "left")
return Mouse_Button::Left;
if (value == "right")
return Mouse_Button::Right;
if (value == "middle")
return Mouse_Button::Middle;
return Mouse_Button::None;
}
Key key(const Json::Value& root) {
const std::string value = root["key"].isString() ? root["key"].asString() : "";
if (value == "Escape")
return Key::Escape;
if (value == "Enter")
return Key::Enter;
if (value == "Space")
return Key::Space;
if (value == "Delete")
return Key::Delete;
if (value == "Backspace")
return Key::Backspace;
if (value == "ArrowLeft")
return Key::Left;
if (value == "ArrowRight")
return Key::Right;
if (value == "ArrowUp")
return Key::Up;
if (value == "ArrowDown")
return Key::Down;
return Key::Unknown;
}
std::optional<Web_Event> pointer_event(const Json::Value& root, Event_Type type) {
const auto x = finite_number(root, "x");
const auto y = finite_number(root, "y");
if (!x || !y)
return std::nullopt;
Pointer_Event event(type);
event.position = {*x, *y};
event.global_position = event.position;
event.button = mouse_button(root);
const int buttons = root["buttons"].isInt() ? root["buttons"].asInt() : 0;
event.buttons = static_cast<Mouse_Button_Mask>(std::clamp(buttons, 0, 7));
event.modifiers = modifiers(root);
return event;
}
std::optional<Web_Event> wheel_event(const Json::Value& root) {
const auto x = finite_number(root, "x");
const auto y = finite_number(root, "y");
const auto pixel_x = finite_number(root, "pixelDeltaX");
const auto pixel_y = finite_number(root, "pixelDeltaY");
const auto angle_x = finite_number(root, "angleDeltaX");
const auto angle_y = finite_number(root, "angleDeltaY");
if (!x || !y || !pixel_x || !pixel_y || !angle_x || !angle_y)
return std::nullopt;
Wheel_Event event;
event.position = {*x, *y};
event.global_position = event.position;
event.pixel_delta_x = *pixel_x;
event.pixel_delta_y = *pixel_y;
event.angle_delta_x = *angle_x;
event.angle_delta_y = *angle_y;
event.modifiers = modifiers(root);
const int buttons = root["buttons"].isInt() ? root["buttons"].asInt() : 0;
event.buttons = static_cast<Mouse_Button_Mask>(std::clamp(buttons, 0, 7));
return event;
}
std::optional<Web_Event> key_event(const Json::Value& root, Event_Type type) {
Key_Event event(type);
event.key = key(root);
event.native_key = root["nativeKey"].isUInt() ? root["nativeKey"].asUInt() : 0;
event.modifiers = modifiers(root);
event.auto_repeat = root["repeat"].isBool() && root["repeat"].asBool();
return event;
}
std::optional<Web_Event> control_event(const Json::Value& root) {
if (!root["control"].isString())
return std::nullopt;
const std::string control = root["control"].asString();
if (control == "mode" && root["value"].isString()) {
const std::string value = root["value"].asString();
if (value == "AM")
return Set_Demo_Mode{Demo_Mode::Am};
if (value == "FM")
return Set_Demo_Mode{Demo_Mode::Fm};
if (value == "USB")
return Set_Demo_Mode{Demo_Mode::Usb};
if (value == "LSB")
return Set_Demo_Mode{Demo_Mode::Lsb};
return std::nullopt;
}
if (control == "center_frequency_mhz") {
const auto value = finite_number(root, "value");
return value && *value >= 1.0 && *value <= 6000.0
? std::optional<Web_Event>(Set_Center_Frequency{*value})
: std::nullopt;
}
if (control == "bandwidth_khz") {
const auto value = finite_number(root, "value");
return value && *value >= 10.0 && *value <= 50000.0
? std::optional<Web_Event>(Set_Bandwidth{*value})
: std::nullopt;
}
if (control == "gain_db") {
const auto value = finite_number(root, "value");
return value && *value >= -30.0 && *value <= 80.0
? std::optional<Web_Event>(Set_Gain{*value})
: std::nullopt;
}
if (control == "max_hold") {
const auto value = boolean(root, "value");
return value ? std::optional<Web_Event>(Set_Max_Hold{*value}) : std::nullopt;
}
if (control == "smoothing") {
const auto value = boolean(root, "value");
return value ? std::optional<Web_Event>(Set_Smoothing{*value}) : std::nullopt;
}
if (control == "clear_selection")
return Clear_Selection{};
return std::nullopt;
}
} // namespace
std::optional<Web_Event> Web_Event_Adapter::decode(std::string_view message) {
const auto parsed = parse_json(message);
if (!parsed || (*parsed)["category"].asString() != "event" || !(*parsed)["type"].isString())
return std::nullopt;
const Json::Value& root = *parsed;
const std::string type = root["type"].asString();
if (type == "frame")
return Frame_Request{};
if (type == "resize") {
const auto width = finite_number(root, "width");
const auto height = finite_number(root, "height");
if (!width || !height)
return std::nullopt;
return Viewport_Resize{{static_cast<int>(std::clamp(*width, 240.0, 1920.0)),
static_cast<int>(std::clamp(*height, 180.0, 1200.0))}};
}
if (type == "show")
return Event(Event_Type::Show);
if (type == "hide")
return Event(Event_Type::Hide);
if (type == "leave")
return Event(Event_Type::Leave);
if (type == "pointer_move")
return pointer_event(root, Event_Type::Pointer_Move);
if (type == "pointer_press")
return pointer_event(root, Event_Type::Pointer_Press);
if (type == "pointer_release")
return pointer_event(root, Event_Type::Pointer_Release);
if (type == "wheel")
return wheel_event(root);
if (type == "key_press")
return key_event(root, Event_Type::Key_Press);
if (type == "key_release")
return key_event(root, Event_Type::Key_Release);
if (type == "control")
return control_event(root);
if (type == "gallery_catalog")
return Gallery_Request{Gallery_Request_Kind::Catalog, std::string(message)};
if (type == "gallery_open")
return Gallery_Request{Gallery_Request_Kind::Open, std::string(message)};
if (type == "gallery_refresh")
return Gallery_Request{Gallery_Request_Kind::Refresh, std::string(message)};
if (type == "gallery_patch")
return Gallery_Request{Gallery_Request_Kind::Patch, std::string(message)};
if (type == "gallery_action")
return Gallery_Request{Gallery_Request_Kind::Action, std::string(message)};
return std::nullopt;
}
} // namespace renderive::web