feat: Improved usability of the TCP Client/Server tool (#2175)

### Problem description
Messages in the TCP tool were only visible as a text string in the
messages list and unable to be opened in the hex view.
There was also no way to send data other than as a typed in text string
in the input field.

### Implementation description
* Added the ability to double-click on a message in the messages list to
open it in a provider tab.
* Added a new button to the client tab to send the current provider to
the connected server.
* Updated the list look to show the message index in a column

### Screenshots



https://github.com/user-attachments/assets/198d78c7-7c94-4f48-ac8c-3581e2ac12e4

---------

Co-authored-by: Nik <werwolv98@gmail.com>
This commit is contained in:
Goomii
2025-08-09 21:07:58 +01:00
committed by GitHub
parent 6b4fef806c
commit d81f0668a1
2 changed files with 64 additions and 2 deletions

View File

@@ -690,6 +690,8 @@
"hex.builtin.tools.tcp_client_server.server": "Server",
"hex.builtin.tools.tcp_client_server.messages": "Messages",
"hex.builtin.tools.tcp_client_server.settings": "Connection Settings",
"hex.builtin.tools.tcp_client_server.tcp_message": "TCP Message {}",
"hex.builtin.tools.tcp_client_server.send_current_provider": "Send from open data source",
"hex.builtin.tools.value": "Value",
"hex.builtin.tools.wiki_explain": "Wikipedia term definitions",
"hex.builtin.tools.wiki_explain.control": "Control",

View File

@@ -5,7 +5,10 @@
#include <fonts/vscode_icons.hpp>
#include <imgui.h>
#include <imgui_internal.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/api/imhex_api.hpp>
#include <hex/providers/memory_provider.hpp>
#include <jthread.hpp>
#include <string>
@@ -71,19 +74,62 @@ namespace hex::plugin::builtin {
}
ImGui::PopItemWidth();
ImGui::SameLine();
ImGui::BeginDisabled(!client.isConnected() || !ImHexApi::Provider::isValid());
{
if (ImGuiExt::IconButton(ICON_VS_SEND, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
auto provider = ImHexApi::Provider::get();
if (provider != nullptr) {
std::vector<u8> data;
data.resize(provider->getSize());
provider->readRaw(0, data.data(), provider->getSize());
client.writeBytes(data);
}
}
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
if (ImHexApi::Provider::isValid()) {
ImGui::SetTooltip("%s", fmt::format("{} ({})", "hex.builtin.tools.tcp_client_server.send_current_provider"_lang, ImHexApi::Provider::get()->getName()).c_str());
}
else {
ImGui::SetTooltip("%s", "hex.builtin.tools.tcp_client_server.send_current_provider"_lang.get());
}
}
}
ImGui::EndDisabled();
if (port < 1)
port = 1;
else if (port > 65535)
port = 65535;
ImGuiExt::Header("hex.builtin.tools.tcp_client_server.messages"_lang);
if (ImGui::BeginTable("##response", 1, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders, ImVec2(0, 200_scaled))) {
if (ImGui::BeginTable("##response", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders, ImVec2(0, 200_scaled))) {
ImGui::TableSetupColumn("##ID", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("##Value");
{
std::scoped_lock lock(receiverMutex);
u32 index = 0;
for (const auto &message : messages) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushID(index);
ImGuiExt::TextFormatted("{}", index);
ImGui::TableNextColumn();
ImGuiExt::TextFormattedSelectable("{}", message.c_str());
if (ImGui::TableGetHoveredRow() == (int)index) {
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::GetColorU32(ImGuiCol_Header));
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
std::vector<uint8_t> data(message.begin(), message.end());
ImHexApi::Provider::add<prv::MemoryProvider>(data, fmt::format("hex.builtin.tools.tcp_client_server.tcp_message"_lang, index));
}
}
ImGui::PopID();
index += 1;
}
}
@@ -166,15 +212,29 @@ namespace hex::plugin::builtin {
ImGuiExt::Header("hex.builtin.tools.tcp_client_server.messages"_lang);
if (ImGui::BeginTable("##response", 1, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders, ImVec2(0, 200_scaled))) {
if (ImGui::BeginTable("##response", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders, ImVec2(0, 200_scaled))) {
ImGui::TableSetupColumn("##ID", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("##Value");
{
std::scoped_lock lock(receiverMutex);
u32 index = 0;
for (const auto &message : messages) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushID(index);
ImGuiExt::TextFormatted("{}", index);
ImGui::TableNextColumn();
ImGuiExt::TextFormattedSelectable("{}", message.c_str());
if (ImGui::TableGetHoveredRow() == (int)index) {
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::GetColorU32(ImGuiCol_Header));
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
std::vector<uint8_t> data(message.begin(), message.end());
ImHexApi::Provider::add<prv::MemoryProvider>(data, fmt::format("hex.builtin.tools.tcp_client_server.tcp_message"_lang, index));
}
}
ImGui::PopID();
index += 1;