mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-06-11 18:04:40 +08:00
Compare commits
5 Commits
v1.3.6
...
file-transfer
| Author | SHA1 | Date | |
|---|---|---|---|
| fea238722d | |||
| 178d958c08 | |||
| f9633f366b | |||
| 7a81f3e767 | |||
| bbbbbf7927 |
@@ -1,11 +1,36 @@
|
|||||||
#include "mouse_controller.h"
|
#include "mouse_controller.h"
|
||||||
|
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
#include "rd_log.h"
|
#include "rd_log.h"
|
||||||
|
|
||||||
namespace crossdesk {
|
namespace crossdesk {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr auto kDoubleClickInterval = std::chrono::milliseconds(500);
|
||||||
|
constexpr int kDoubleClickMaxDistance = 8;
|
||||||
|
constexpr int kMaxClickState = 3;
|
||||||
|
|
||||||
|
bool IsWithinClickDistance(int x1, int y1, int x2, int y2) {
|
||||||
|
return std::abs(x1 - x2) <= kDoubleClickMaxDistance &&
|
||||||
|
std::abs(y1 - y2) <= kDoubleClickMaxDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetClickState(CGEventRef event, int click_state) {
|
||||||
|
if (!event) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGEventSetIntegerValueField(
|
||||||
|
event, kCGMouseEventClickState,
|
||||||
|
std::max(1, std::min(click_state, kMaxClickState)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
MouseController::MouseController() {}
|
MouseController::MouseController() {}
|
||||||
|
|
||||||
@@ -19,6 +44,36 @@ int MouseController::Init(std::vector<DisplayInfo> display_info_list) {
|
|||||||
|
|
||||||
int MouseController::Destroy() { return 0; }
|
int MouseController::Destroy() { return 0; }
|
||||||
|
|
||||||
|
int MouseController::BeginClick(ClickTracker& tracker, int x, int y) {
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
const bool continues_previous_click =
|
||||||
|
tracker.has_last_down &&
|
||||||
|
now - tracker.last_down_time <= kDoubleClickInterval &&
|
||||||
|
IsWithinClickDistance(tracker.last_down_x, tracker.last_down_y, x, y);
|
||||||
|
|
||||||
|
tracker.click_state = continues_previous_click
|
||||||
|
? std::min(tracker.click_state + 1, kMaxClickState)
|
||||||
|
: 1;
|
||||||
|
tracker.active_click_state = tracker.click_state;
|
||||||
|
tracker.has_last_down = true;
|
||||||
|
tracker.last_down_time = now;
|
||||||
|
tracker.last_down_x = x;
|
||||||
|
tracker.last_down_y = y;
|
||||||
|
|
||||||
|
return tracker.active_click_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MouseController::EndClick(ClickTracker& tracker, int x, int y) {
|
||||||
|
const int click_state = tracker.active_click_state;
|
||||||
|
if (!IsWithinClickDistance(tracker.last_down_x, tracker.last_down_y, x, y)) {
|
||||||
|
tracker.has_last_down = false;
|
||||||
|
tracker.click_state = 0;
|
||||||
|
tracker.active_click_state = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return click_state;
|
||||||
|
}
|
||||||
|
|
||||||
int MouseController::SendMouseCommand(RemoteAction remote_action,
|
int MouseController::SendMouseCommand(RemoteAction remote_action,
|
||||||
int display_index) {
|
int display_index) {
|
||||||
if (remote_action.type != ControlType::mouse) {
|
if (remote_action.type != ControlType::mouse) {
|
||||||
@@ -41,58 +96,69 @@ int MouseController::SendMouseCommand(RemoteAction remote_action,
|
|||||||
|
|
||||||
const float normalized_x = std::clamp(remote_action.m.x, 0.0f, 1.0f);
|
const float normalized_x = std::clamp(remote_action.m.x, 0.0f, 1.0f);
|
||||||
const float normalized_y = std::clamp(remote_action.m.y, 0.0f, 1.0f);
|
const float normalized_y = std::clamp(remote_action.m.y, 0.0f, 1.0f);
|
||||||
int mouse_pos_x =
|
int mouse_pos_x = normalized_x * display_info.width + display_info.left;
|
||||||
normalized_x * display_info.width + display_info.left;
|
int mouse_pos_y = normalized_y * display_info.height + display_info.top;
|
||||||
int mouse_pos_y =
|
|
||||||
normalized_y * display_info.height + display_info.top;
|
|
||||||
|
|
||||||
CGEventRef mouse_event = nullptr;
|
CGEventRef mouse_event = nullptr;
|
||||||
CGEventType mouse_type;
|
CGEventType mouse_type;
|
||||||
CGMouseButton mouse_button;
|
CGMouseButton mouse_button;
|
||||||
CGPoint mouse_point = CGPointMake(mouse_pos_x, mouse_pos_y);
|
CGPoint mouse_point = CGPointMake(mouse_pos_x, mouse_pos_y);
|
||||||
|
int click_state = 1;
|
||||||
|
|
||||||
switch (remote_action.m.flag) {
|
switch (remote_action.m.flag) {
|
||||||
case MouseFlag::left_down:
|
case MouseFlag::left_down:
|
||||||
mouse_type = kCGEventLeftMouseDown;
|
mouse_type = kCGEventLeftMouseDown;
|
||||||
left_dragging_ = true;
|
left_dragging_ = true;
|
||||||
|
click_state = BeginClick(left_click_tracker_, mouse_pos_x, mouse_pos_y);
|
||||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
||||||
kCGMouseButtonLeft);
|
kCGMouseButtonLeft);
|
||||||
|
SetClickState(mouse_event, click_state);
|
||||||
break;
|
break;
|
||||||
case MouseFlag::left_up:
|
case MouseFlag::left_up:
|
||||||
mouse_type = kCGEventLeftMouseUp;
|
mouse_type = kCGEventLeftMouseUp;
|
||||||
left_dragging_ = false;
|
left_dragging_ = false;
|
||||||
|
click_state = EndClick(left_click_tracker_, mouse_pos_x, mouse_pos_y);
|
||||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
||||||
kCGMouseButtonLeft);
|
kCGMouseButtonLeft);
|
||||||
|
SetClickState(mouse_event, click_state);
|
||||||
break;
|
break;
|
||||||
case MouseFlag::right_down:
|
case MouseFlag::right_down:
|
||||||
mouse_type = kCGEventRightMouseDown;
|
mouse_type = kCGEventRightMouseDown;
|
||||||
right_dragging_ = true;
|
right_dragging_ = true;
|
||||||
|
click_state = BeginClick(right_click_tracker_, mouse_pos_x, mouse_pos_y);
|
||||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
||||||
kCGMouseButtonRight);
|
kCGMouseButtonRight);
|
||||||
|
SetClickState(mouse_event, click_state);
|
||||||
break;
|
break;
|
||||||
case MouseFlag::right_up:
|
case MouseFlag::right_up:
|
||||||
mouse_type = kCGEventRightMouseUp;
|
mouse_type = kCGEventRightMouseUp;
|
||||||
right_dragging_ = false;
|
right_dragging_ = false;
|
||||||
|
click_state = EndClick(right_click_tracker_, mouse_pos_x, mouse_pos_y);
|
||||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
||||||
kCGMouseButtonRight);
|
kCGMouseButtonRight);
|
||||||
|
SetClickState(mouse_event, click_state);
|
||||||
break;
|
break;
|
||||||
case MouseFlag::middle_down:
|
case MouseFlag::middle_down:
|
||||||
mouse_type = kCGEventOtherMouseDown;
|
mouse_type = kCGEventOtherMouseDown;
|
||||||
|
click_state = BeginClick(middle_click_tracker_, mouse_pos_x, mouse_pos_y);
|
||||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
||||||
kCGMouseButtonCenter);
|
kCGMouseButtonCenter);
|
||||||
|
SetClickState(mouse_event, click_state);
|
||||||
break;
|
break;
|
||||||
case MouseFlag::middle_up:
|
case MouseFlag::middle_up:
|
||||||
mouse_type = kCGEventOtherMouseUp;
|
mouse_type = kCGEventOtherMouseUp;
|
||||||
|
click_state = EndClick(middle_click_tracker_, mouse_pos_x, mouse_pos_y);
|
||||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
||||||
kCGMouseButtonCenter);
|
kCGMouseButtonCenter);
|
||||||
|
SetClickState(mouse_event, click_state);
|
||||||
break;
|
break;
|
||||||
case MouseFlag::wheel_vertical:
|
case MouseFlag::wheel_vertical:
|
||||||
mouse_event = CGEventCreateScrollWheelEvent(
|
mouse_event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitLine,
|
||||||
NULL, kCGScrollEventUnitLine, 2, remote_action.m.s, 0);
|
2, remote_action.m.s, 0);
|
||||||
break;
|
break;
|
||||||
case MouseFlag::wheel_horizontal:
|
case MouseFlag::wheel_horizontal:
|
||||||
mouse_event = CGEventCreateScrollWheelEvent(
|
mouse_event = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitLine,
|
||||||
NULL, kCGScrollEventUnitLine, 2, 0, remote_action.m.s);
|
2, 0, remote_action.m.s);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (left_dragging_) {
|
if (left_dragging_) {
|
||||||
@@ -106,8 +172,8 @@ int MouseController::SendMouseCommand(RemoteAction remote_action,
|
|||||||
mouse_button = kCGMouseButtonLeft;
|
mouse_button = kCGMouseButtonLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
mouse_event = CGEventCreateMouseEvent(NULL, mouse_type, mouse_point,
|
mouse_event =
|
||||||
mouse_button);
|
CGEventCreateMouseEvent(NULL, mouse_type, mouse_point, mouse_button);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#ifndef _MOUSE_CONTROLLER_H_
|
#ifndef _MOUSE_CONTROLLER_H_
|
||||||
#define _MOUSE_CONTROLLER_H_
|
#define _MOUSE_CONTROLLER_H_
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "device_controller.h"
|
#include "device_controller.h"
|
||||||
@@ -24,9 +25,24 @@ class MouseController : public DeviceController {
|
|||||||
virtual int SendMouseCommand(RemoteAction remote_action, int display_index);
|
virtual int SendMouseCommand(RemoteAction remote_action, int display_index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct ClickTracker {
|
||||||
|
bool has_last_down = false;
|
||||||
|
std::chrono::steady_clock::time_point last_down_time{};
|
||||||
|
int last_down_x = 0;
|
||||||
|
int last_down_y = 0;
|
||||||
|
int click_state = 0;
|
||||||
|
int active_click_state = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
int BeginClick(ClickTracker& tracker, int x, int y);
|
||||||
|
int EndClick(ClickTracker& tracker, int x, int y);
|
||||||
|
|
||||||
std::vector<DisplayInfo> display_info_list_;
|
std::vector<DisplayInfo> display_info_list_;
|
||||||
bool left_dragging_ = false;
|
bool left_dragging_ = false;
|
||||||
bool right_dragging_ = false;
|
bool right_dragging_ = false;
|
||||||
|
ClickTracker left_click_tracker_;
|
||||||
|
ClickTracker right_click_tracker_;
|
||||||
|
ClickTracker middle_click_tracker_;
|
||||||
};
|
};
|
||||||
} // namespace crossdesk
|
} // namespace crossdesk
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -158,6 +158,9 @@ struct TranslationRow {
|
|||||||
X(signal_connected, u8"已连接服务器", "Connected", u8"Подключено к серверу") \
|
X(signal_connected, u8"已连接服务器", "Connected", u8"Подключено к серверу") \
|
||||||
X(signal_disconnected, u8"未连接服务器", "Disconnected", \
|
X(signal_disconnected, u8"未连接服务器", "Disconnected", \
|
||||||
u8"Нет подключения к серверу") \
|
u8"Нет подключения к серверу") \
|
||||||
|
X(signal_tls_cert_error, u8"证书验证失败,请重新安装自托管根证书", \
|
||||||
|
"Certificate verification failed. Reinstall the self-hosted root certificate.", \
|
||||||
|
u8"Ошибка проверки сертификата. Переустановите корневой сертификат.") \
|
||||||
X(p2p_connected, u8"对等连接已建立", "P2P Connected", u8"P2P подключено") \
|
X(p2p_connected, u8"对等连接已建立", "P2P Connected", u8"P2P подключено") \
|
||||||
X(p2p_disconnected, u8"对等连接已断开", "P2P Disconnected", \
|
X(p2p_disconnected, u8"对等连接已断开", "P2P Disconnected", \
|
||||||
u8"P2P отключено") \
|
u8"P2P отключено") \
|
||||||
|
|||||||
@@ -1231,6 +1231,8 @@ void Render::OnSignalStatusCb(SignalStatus status, const char* user_id,
|
|||||||
render->signal_connected_ = false;
|
render->signal_connected_ = false;
|
||||||
} else if (SignalStatus::SignalServerClosed == status) {
|
} else if (SignalStatus::SignalServerClosed == status) {
|
||||||
render->signal_connected_ = false;
|
render->signal_connected_ = false;
|
||||||
|
} else if (SignalStatus::SignalTlsCertError == status) {
|
||||||
|
render->signal_connected_ = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (client_id.rfind("C-", 0) != 0) {
|
if (client_id.rfind("C-", 0) != 0) {
|
||||||
@@ -1258,6 +1260,8 @@ void Render::OnSignalStatusCb(SignalStatus status, const char* user_id,
|
|||||||
props->signal_connected_ = false;
|
props->signal_connected_ = false;
|
||||||
} else if (SignalStatus::SignalServerClosed == status) {
|
} else if (SignalStatus::SignalServerClosed == status) {
|
||||||
props->signal_connected_ = false;
|
props->signal_connected_ = false;
|
||||||
|
} else if (SignalStatus::SignalTlsCertError == status) {
|
||||||
|
props->signal_connected_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,20 +26,31 @@ int Render::StatusBar() {
|
|||||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||||
draw_list->AddCircleFilled(dot_pos, status_bar_height * 0.25f,
|
draw_list->AddCircleFilled(dot_pos, status_bar_height * 0.25f,
|
||||||
ImColor(1.0f, 1.0f, 1.0f), 100);
|
ImColor(1.0f, 1.0f, 1.0f), 100);
|
||||||
|
bool tls_cert_error =
|
||||||
|
signal_status_ == SignalStatus::SignalTlsCertError;
|
||||||
draw_list->AddCircleFilled(dot_pos, status_bar_height * 0.2f,
|
draw_list->AddCircleFilled(dot_pos, status_bar_height * 0.2f,
|
||||||
ImColor(signal_connected_ ? 0.0f : 1.0f,
|
tls_cert_error
|
||||||
signal_connected_ ? 1.0f : 0.0f, 0.0f),
|
? ImColor(1.0f, 0.65f, 0.0f)
|
||||||
|
: ImColor(signal_connected_ ? 0.0f : 1.0f,
|
||||||
|
signal_connected_ ? 1.0f : 0.0f,
|
||||||
|
0.0f),
|
||||||
100);
|
100);
|
||||||
|
|
||||||
ImGui::SetWindowFontScale(0.6f);
|
ImGui::SetWindowFontScale(0.6f);
|
||||||
|
const char* signal_status_text =
|
||||||
|
tls_cert_error
|
||||||
|
? localization::signal_tls_cert_error[localization_language_index_]
|
||||||
|
.c_str()
|
||||||
|
: (signal_connected_
|
||||||
|
? localization::signal_connected[localization_language_index_]
|
||||||
|
.c_str()
|
||||||
|
: localization::signal_disconnected
|
||||||
|
[localization_language_index_]
|
||||||
|
.c_str());
|
||||||
draw_list->AddText(
|
draw_list->AddText(
|
||||||
ImVec2(status_bar_width * 0.045f,
|
ImVec2(status_bar_width * 0.045f,
|
||||||
io.DisplaySize.y * (1 - STATUS_BAR_HEIGHT * 0.9f)),
|
io.DisplaySize.y * (1 - STATUS_BAR_HEIGHT * 0.9f)),
|
||||||
ImColor(0.0f, 0.0f, 0.0f),
|
ImColor(0.0f, 0.0f, 0.0f), signal_status_text);
|
||||||
signal_connected_
|
|
||||||
? localization::signal_connected[localization_language_index_].c_str()
|
|
||||||
: localization::signal_disconnected[localization_language_index_]
|
|
||||||
.c_str());
|
|
||||||
ImGui::SetWindowFontScale(1.0f);
|
ImGui::SetWindowFontScale(1.0f);
|
||||||
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|||||||
+1
-1
Submodule submodules/minirtc updated: bb0fae0617...0d9a9d6a32
Reference in New Issue
Block a user