59 Commits

Author SHA1 Message Date
dijunkun
418ab7a1d2 [fix] fix net traffic stats display 2024-12-02 11:03:55 +08:00
dijunkun
6a2c9af316 [feat] loss rate display supported 2024-12-01 17:00:59 +08:00
dijunkun
eaabf478cc [feat] update net statistics module 2024-11-29 17:54:15 +08:00
dijunkun
ffe3ca76af [feat] switch rtc module into new branch 'qos' 2024-11-28 18:27:34 +08:00
dijunkun
c5a6302220 [fix] update rtc module 2024-11-28 15:16:48 +08:00
dijunkun
9b2f81690f [fix] fix stream window scale error 2024-11-27 20:28:42 +08:00
dijunkun
9621e6b570 [fix] fix right shift key mapping on MacOSX 2024-11-27 17:33:54 +08:00
dijunkun
ce3ae03bef [fix] prevent cursor relocation when stream window resized 2024-11-27 17:24:45 +08:00
dijunkun
e0457213ea [fix] fix display errors when stream window resized 2024-11-27 16:14:14 +08:00
dijunkun
10cdc440a0 [fix] fix key press/release event 2024-11-27 14:34:54 +08:00
dijunkun
ddc62c90bb [fix] fix all unused variables and type conversions on Windows 2024-11-27 11:17:43 +08:00
dijunkun
9e70d0e8fc [fix] fix all unused variables and type conversions on MacOSX 2024-11-27 10:57:09 +08:00
dijunkun
4533d53ba8 [fix] fix all unused variables and type conversions 2024-11-26 23:31:06 +08:00
dijunkun
0caa243006 [fix] fix unused variables and type conversions 2024-11-26 17:31:37 +08:00
dijunkun
1e58abdfdd [feat] rewrite log module 2024-11-26 16:05:28 +08:00
dijunkun
370ac08d09 [fix] use new rtc api 2024-11-26 15:06:55 +08:00
dijunkun
31b6b2736c [fix] fix control and shift keys convertion from Win to MacOSX 2024-11-25 17:29:49 +08:00
dijunkun
abd22ab7f1 [fix] fix Win/MacOSX keycodes convertion 2024-11-25 17:15:22 +08:00
dijunkun
5ab68988aa [fix] fix stream window grabbing cannot be released after connection closed 2024-11-22 18:12:36 +08:00
dijunkun
ba3edcc02a [feat] keyboard control supported on MacOSX 2024-11-22 18:05:13 +08:00
dijunkun
8414a57a5b [feat] keyboard control supported on Windows 2024-11-22 17:17:33 +08:00
dijunkun
3f777e4662 [fix] fix compile error 2024-11-22 16:45:14 +08:00
dijunkun
52828183a1 [feat] keyboard capture supported on Windows 2024-11-22 16:39:01 +08:00
dijunkun
df7489f8e2 [fix] update imgui to v1.91.5-docking to fix: inputText cannot input text after add a space in remote id 2024-11-21 18:40:42 +08:00
dijunkun
4fea7d86e1 [feat] cursor will move into remote id input box automaticlly if the last input remote id does not exist 2024-11-21 16:20:25 +08:00
dijunkun
cb17b7c8db [fix] fix setting item [enable turn] 2024-11-21 16:05:10 +08:00
dijunkun
cf7ef89bf2 [fix] fix cursor position when stream window initialization 2024-11-21 10:34:04 +08:00
dijunkun
2d2a578800 [fix] fix control window position when stream window size changed 2024-11-20 19:17:33 +08:00
dijunkun
0ba12f3ccf [fix] only display client side net status if connected to itself 2024-11-19 22:33:59 +08:00
dijunkun
5ac603977d [fix] fix net traffic stats display 2024-11-19 17:31:31 +08:00
dijunkun
25d5a80bee [fix] reset net traffic stats after connection closed 2024-11-19 17:26:01 +08:00
dijunkun
c9d452a025 [feat] disable settings modification during streaming 2024-11-19 17:21:27 +08:00
dijunkun
8132d62c02 [feat] show net traffic stats in control bar 2024-11-19 16:56:30 +08:00
dijunkun
ca32ebeefe [feat] net traffic stats supported 2024-11-18 17:33:09 +08:00
dijunkun
5bf5e9ee25 [feat] change UI layouts 2024-11-18 16:08:54 +08:00
dijunkun
bf097008e7 [feat] use SDL_WINDOW_HIDDEN to delay showing the main window to avoid black window during initialization 2024-11-18 15:10:02 +08:00
dijunkun
59b1208321 [feat] load different size fonts in initialization 2024-11-15 18:19:54 +08:00
dijunkun
84194188f8 [fix] fix redundant recent connection cache file due to remember_password_ flag not being set correctly 2024-11-14 17:26:08 +08:00
dijunkun
a067441fb9 [feat] change recent connections layout 2024-11-14 17:13:38 +08:00
dijunkun
6eac8380b6 [feat] generate random AES128 key and iv during initialization, save them in cache file and load when program starts 2024-11-14 00:49:30 +08:00
dijunkun
5aed8317ca [feat] quick connecting supported 2024-11-13 23:27:06 +08:00
dijunkun
9aed7a19cf [fix] fix AES encrypt and decrypt 2024-11-13 17:58:59 +08:00
dijunkun
c0154be1aa [fix] use APIs in evp.h to encrypt and decrypt 2024-11-13 00:47:54 +08:00
dijunkun
f9d024e971 [feat] use AES to encrypt image names 2024-11-12 17:30:28 +08:00
dijunkun
526eb4bb31 [feat] add trash and connect buttons on recent connection images 2024-11-11 17:05:47 +08:00
dijunkun
f9347cbd49 [feat] use confirm window to confirm recent connections deletion 2024-11-11 10:49:07 +08:00
dijunkun
b6671bdbe7 [feat] delete recent connection supported 2024-11-08 17:52:19 +08:00
dijunkun
edcf5d408c [feat] use horizontal scroll bar to show all recent connections 2024-11-08 14:51:58 +08:00
dijunkun
8c8731909e [feat] remote host names will be shown below thumbnails 2024-11-07 17:30:55 +08:00
dijunkun
de721ac6e3 [feat] use a list to show thumbnails of recent connections 2024-11-07 16:58:25 +08:00
dijunkun
963f1da1d8 [fix] fix redefinition error on MacOSX 2024-11-07 16:32:35 +08:00
dijunkun
4c6159e4d4 [feat] write and load thumbnails supported 2024-11-07 16:29:02 +08:00
dijunkun
e3c2e9ec6d [fix] fix png images write and read 2024-11-07 02:38:35 +08:00
dijunkun
02022bdcdf [feat] add recent connections window 2024-11-06 17:28:11 +08:00
dijunkun
19ea426efc [feat] change UI layouts 2024-11-05 17:29:39 +08:00
dijunkun
863070a8a7 [feat] enable window grab when mouse control enabled 2024-11-04 17:29:26 +08:00
dijunkun
44f9e6a8c9 [fix] fix crash due to multi-context fonts release 2024-11-04 16:13:20 +08:00
dijunkun
087d5d7e52 [feat] use an additional window to show video streams 2024-11-01 20:30:06 +08:00
dijunkun
26fa53f867 [fix] fix imgui layout error 2024-11-01 15:57:15 +08:00
42 changed files with 55319 additions and 42445 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,12 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-11-11
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _FA_REGULAR_400_H_
#define _FA_REGULAR_400_H_
unsigned char fa_regular_400_ttf[] = {
0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x80, 0x00, 0x03, 0x00, 0x20,
0x4f, 0x53, 0x2f, 0x32, 0x5f, 0x6e, 0x5e, 0x5e, 0x00, 0x00, 0x01, 0x28,
@@ -5653,6 +5662,7 @@ unsigned char fa_regular_400_ttf[] = {
0x62, 0x65, 0x61, 0x6d, 0x10, 0x73, 0x74, 0x61, 0x72, 0x2d, 0x68, 0x61,
0x6c, 0x66, 0x2d, 0x73, 0x74, 0x72, 0x6f, 0x6b, 0x65, 0x0d, 0x66, 0x61,
0x63, 0x65, 0x2d, 0x73, 0x75, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x0a,
0x66, 0x61, 0x63, 0x65, 0x2d, 0x74, 0x69, 0x72, 0x65, 0x64, 0x00, 0x00
};
0x66, 0x61, 0x63, 0x65, 0x2d, 0x74, 0x69, 0x72, 0x65, 0x64, 0x00, 0x00};
unsigned int fa_regular_400_ttf_len = 67860;
#endif

View File

@@ -1,3 +1,12 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-11-11
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _FA_SOLID_900_H_
#define _FA_SOLID_900_H_
unsigned char fa_solid_900_ttf[] = {
0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x80, 0x00, 0x03, 0x00, 0x20,
0x4f, 0x53, 0x2f, 0x32, 0x61, 0x6b, 0x62, 0x53, 0x00, 0x00, 0x01, 0x28,
@@ -35026,6 +35035,7 @@ unsigned char fa_solid_900_ttf[] = {
0x73, 0x65, 0x05, 0x72, 0x61, 0x64, 0x69, 0x6f, 0x0c, 0x72, 0x65, 0x63,
0x6f, 0x72, 0x64, 0x2d, 0x76, 0x69, 0x6e, 0x79, 0x6c, 0x0d, 0x77, 0x61,
0x6c, 0x6b, 0x69, 0x65, 0x2d, 0x74, 0x61, 0x6c, 0x6b, 0x69, 0x65, 0x07,
0x63, 0x61, 0x72, 0x61, 0x76, 0x61, 0x6e, 0x00
};
0x63, 0x61, 0x72, 0x61, 0x76, 0x61, 0x6e, 0x00};
unsigned int fa_solid_900_ttf_len = 420332;
#endif

View File

@@ -25,13 +25,13 @@ std::string GetMac() {
#ifdef _WIN32
IP_ADAPTER_INFO adapterInfo[16];
DWORD bufferSize = sizeof(adapterInfo);
DWORD result = GetAdaptersInfo(adapterInfo, &bufferSize);
if (result == ERROR_SUCCESS) {
PIP_ADAPTER_INFO adapter = adapterInfo;
while (adapter) {
for (UINT i = 0; i < adapter->AddressLength; i++) {
len += sprintf(mac_addr + len, "%.2X", adapter->Address[i]);
len += sprintf_s(mac_addr + len, sizeof(mac_addr) - len, "%.2X",
adapter->Address[i]);
}
break;
}
@@ -100,3 +100,26 @@ std::string GetMac() {
#endif
return mac_addr;
}
std::string GetHostName() {
char hostname[256];
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed." << std::endl;
return "";
}
if (gethostname(hostname, sizeof(hostname)) == SOCKET_ERROR) {
LOG_ERROR("gethostname failed: {}", WSAGetLastError());
WSACleanup();
return "";
}
WSACleanup();
#else
if (gethostname(hostname, sizeof(hostname)) == -1) {
LOG_ERROR("gethostname failed");
return "";
}
#endif
return hostname;
}

View File

@@ -10,5 +10,6 @@
#include <iostream>
std::string GetMac();
std::string GetHostName();
#endif

View File

@@ -9,7 +9,12 @@
#include <stdio.h>
typedef enum { mouse = 0, keyboard, audio_capture } ControlType;
typedef enum {
mouse = 0,
keyboard,
audio_capture,
host_infomation
} ControlType;
typedef enum { move = 0, left_down, left_up, right_down, right_up } MouseFlag;
typedef enum { key_down = 0, key_up } KeyFlag;
typedef struct {
@@ -23,23 +28,35 @@ typedef struct {
KeyFlag flag;
} Key;
typedef struct {
char host_name[64];
size_t host_name_size;
} HostInfo;
typedef struct {
ControlType type;
union {
Mouse m;
Key k;
HostInfo i;
bool a;
};
} RemoteAction;
// int key_code, bool is_down
typedef void (*OnKeyAction)(int, bool, void*);
class DeviceController {
public:
virtual ~DeviceController() {}
public:
virtual int Init(int screen_width, int screen_height) = 0;
virtual int Destroy() = 0;
virtual int SendCommand(RemoteAction remote_action) = 0;
// virtual int Init(int screen_width, int screen_height);
// virtual int Destroy();
// virtual int SendCommand(RemoteAction remote_action);
// virtual int Hook();
// virtual int Unhook();
};
#endif

View File

@@ -8,6 +8,7 @@
#define _DEVICE_CONTROLLER_FACTORY_H_
#include "device_controller.h"
#include "keyboard_capturer.h"
#include "mouse_controller.h"
class DeviceControllerFactory {
@@ -23,7 +24,7 @@ class DeviceControllerFactory {
case Mouse:
return new MouseController();
case Keyboard:
return nullptr;
return new KeyboardCapturer();
default:
return nullptr;
}

View File

@@ -0,0 +1,15 @@
#include "keyboard_capturer.h"
KeyboardCapturer::KeyboardCapturer() {}
KeyboardCapturer::~KeyboardCapturer() {}
int KeyboardCapturer::Hook(OnKeyAction on_key_action, void *user_ptr) {
return 0;
}
int KeyboardCapturer::Unhook() { return 0; }
int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down) {
return 0;
}

View File

@@ -0,0 +1,25 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-11-22
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _KEYBOARD_CAPTURER_H_
#define _KEYBOARD_CAPTURER_H_
#include "device_controller.h"
class KeyboardCapturer : public DeviceController {
public:
KeyboardCapturer();
virtual ~KeyboardCapturer();
public:
virtual int Hook(OnKeyAction on_key_action, void *user_ptr);
virtual int Unhook();
virtual int SendKeyboardCommand(int key_code, bool is_down);
private:
};
#endif

View File

@@ -0,0 +1,135 @@
#include "keyboard_capturer.h"
#include "keyboard_converter.h"
#include "rd_log.h"
static OnKeyAction g_on_key_action = nullptr;
static void *g_user_ptr = nullptr;
CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type,
CGEventRef event, void *userInfo) {
KeyboardCapturer *keyboard_capturer = (KeyboardCapturer *)userInfo;
if (!keyboard_capturer) {
LOG_ERROR("keyboard_capturer is nullptr");
return event;
}
int vk_code = 0;
if (type == kCGEventKeyDown || type == kCGEventKeyUp) {
CGKeyCode key_code = static_cast<CGKeyCode>(
CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
if (CGKeyCodeToVkCode.find(key_code) != CGKeyCodeToVkCode.end()) {
g_on_key_action(CGKeyCodeToVkCode[key_code], type == kCGEventKeyDown,
g_user_ptr);
}
} else if (type == kCGEventFlagsChanged) {
CGEventFlags current_flags = CGEventGetFlags(event);
CGKeyCode key_code = static_cast<CGKeyCode>(
CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
// caps lock
bool caps_lock_state = (current_flags & kCGEventFlagMaskAlphaShift) != 0;
if (caps_lock_state != keyboard_capturer->caps_lock_flag_) {
keyboard_capturer->caps_lock_flag_ = caps_lock_state;
if (keyboard_capturer->caps_lock_flag_) {
g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr);
} else {
g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr);
}
}
// shift
bool shift_state = (current_flags & kCGEventFlagMaskShift) != 0;
if (shift_state != keyboard_capturer->shift_flag_) {
keyboard_capturer->shift_flag_ = shift_state;
if (keyboard_capturer->shift_flag_) {
g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr);
} else {
g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr);
}
}
// control
bool control_state = (current_flags & kCGEventFlagMaskControl) != 0;
if (control_state != keyboard_capturer->control_flag_) {
keyboard_capturer->control_flag_ = control_state;
if (keyboard_capturer->control_flag_) {
g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr);
} else {
g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr);
}
}
// option
bool option_state = (current_flags & kCGEventFlagMaskAlternate) != 0;
if (option_state != keyboard_capturer->option_flag_) {
keyboard_capturer->option_flag_ = option_state;
if (keyboard_capturer->option_flag_) {
g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr);
} else {
g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr);
}
}
// command
bool command_state = (current_flags & kCGEventFlagMaskCommand) != 0;
if (command_state != keyboard_capturer->command_flag_) {
keyboard_capturer->command_flag_ = command_state;
if (keyboard_capturer->command_flag_) {
g_on_key_action(CGKeyCodeToVkCode[key_code], true, g_user_ptr);
} else {
g_on_key_action(CGKeyCodeToVkCode[key_code], false, g_user_ptr);
}
}
}
return nullptr;
}
KeyboardCapturer::KeyboardCapturer() {}
KeyboardCapturer::~KeyboardCapturer() {}
int KeyboardCapturer::Hook(OnKeyAction on_key_action, void *user_ptr) {
g_on_key_action = on_key_action;
g_user_ptr = user_ptr;
CGEventMask eventMask = (1 << kCGEventKeyDown) | (1 << kCGEventKeyUp) |
(1 << kCGEventFlagsChanged);
event_tap_ = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap,
kCGEventTapOptionDefault, eventMask,
eventCallback, this);
if (!event_tap_) {
LOG_ERROR("CGEventTapCreate failed");
return -1;
}
run_loop_source_ =
CFMachPortCreateRunLoopSource(kCFAllocatorDefault, event_tap_, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), run_loop_source_,
kCFRunLoopCommonModes);
CGEventTapEnable(event_tap_, true);
return 0;
}
int KeyboardCapturer::Unhook() {
CFRelease(run_loop_source_);
CFRelease(event_tap_);
return 0;
}
int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down) {
if (vkCodeToCGKeyCode.find(key_code) != vkCodeToCGKeyCode.end()) {
CGKeyCode cg_key_code = vkCodeToCGKeyCode[key_code];
CGEventRef event = CGEventCreateKeyboardEvent(NULL, cg_key_code, is_down);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
return 0;
}

View File

@@ -0,0 +1,36 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-11-22
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _KEYBOARD_CAPTURER_H_
#define _KEYBOARD_CAPTURER_H_
#include <ApplicationServices/ApplicationServices.h>
#include "device_controller.h"
class KeyboardCapturer : public DeviceController {
public:
KeyboardCapturer();
virtual ~KeyboardCapturer();
public:
virtual int Hook(OnKeyAction on_key_action, void *user_ptr);
virtual int Unhook();
virtual int SendKeyboardCommand(int key_code, bool is_down);
private:
CFMachPortRef event_tap_;
CFRunLoopSourceRef run_loop_source_;
public:
bool caps_lock_flag_ = false;
bool shift_flag_ = false;
bool control_flag_ = false;
bool option_flag_ = false;
bool command_flag_ = false;
};
#endif

View File

@@ -0,0 +1,248 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-11-25
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _KEYBOARD_CONVERTER_H_
#define _KEYBOARD_CONVERTER_H_
#include <map>
// Windows vkCode to macOS CGKeyCode (104 keys)
std::map<int, int> vkCodeToCGKeyCode = {
// A-Z
{0x41, 0x00}, // A
{0x42, 0x0B}, // B
{0x43, 0x08}, // C
{0x44, 0x02}, // D
{0x45, 0x0E}, // E
{0x46, 0x03}, // F
{0x47, 0x05}, // G
{0x48, 0x04}, // H
{0x49, 0x22}, // I
{0x4A, 0x26}, // J
{0x4B, 0x28}, // K
{0x4C, 0x25}, // L
{0x4D, 0x2E}, // M
{0x4E, 0x2D}, // N
{0x4F, 0x1F}, // O
{0x50, 0x23}, // P
{0x51, 0x0C}, // Q
{0x52, 0x0F}, // R
{0x53, 0x01}, // S
{0x54, 0x11}, // T
{0x55, 0x20}, // U
{0x56, 0x09}, // V
{0x57, 0x0D}, // W
{0x58, 0x07}, // X
{0x59, 0x10}, // Y
{0x5A, 0x06}, // Z
// 0-9
{0x30, 0x1D}, // 0
{0x31, 0x12}, // 1
{0x32, 0x13}, // 2
{0x33, 0x14}, // 3
{0x34, 0x15}, // 4
{0x35, 0x17}, // 5
{0x36, 0x16}, // 6
{0x37, 0x1A}, // 7
{0x38, 0x1C}, // 8
{0x39, 0x19}, // 9
// F1-F12
{0x70, 0x7A}, // F1
{0x71, 0x78}, // F2
{0x72, 0x63}, // F3
{0x73, 0x76}, // F4
{0x74, 0x60}, // F5
{0x75, 0x61}, // F6
{0x76, 0x62}, // F7
{0x77, 0x64}, // F8
{0x78, 0x65}, // F9
{0x79, 0x6D}, // F10
{0x7A, 0x67}, // F11
{0x7B, 0x6F}, // F12
// control keys
{0x1B, 0x35}, // Escape
{0x0D, 0x24}, // Enter
{0x20, 0x31}, // Space
{0x08, 0x33}, // Backspace
{0x09, 0x30}, // Tab
{0x2C, 0x74}, // Print Screen
{0x2D, 0x72}, // Insert
{0x2E, 0x75}, // Delete
{0x24, 0x73}, // Home
{0x23, 0x77}, // End
{0x21, 0x79}, // Page Up
{0x22, 0x7A}, // Page Down
// arrow keys
{0x25, 0x7B}, // Left Arrow
{0x27, 0x7C}, // Right Arrow
{0x26, 0x7E}, // Up Arrow
{0x28, 0x7D}, // Down Arrow
// numpad
{0x60, 0x52}, // Numpad 0
{0x61, 0x53}, // Numpad 1
{0x62, 0x54}, // Numpad 2
{0x63, 0x55}, // Numpad 3
{0x64, 0x56}, // Numpad 4
{0x65, 0x57}, // Numpad 5
{0x66, 0x58}, // Numpad 6
{0x67, 0x59}, // Numpad 7
{0x68, 0x5B}, // Numpad 8
{0x69, 0x5C}, // Numpad 9
{0x6E, 0x41}, // Numpad .
{0x6F, 0x4B}, // Numpad /
{0x6A, 0x43}, // Numpad *
{0x6D, 0x4E}, // Numpad -
{0x6B, 0x45}, // Numpad +
// symbol keys
{0xBA, 0x29}, // ; (Semicolon)
{0xDE, 0x27}, // ' (Quote)
{0xC0, 0x32}, // ` (Backtick)
{0xBC, 0x2B}, // , (Comma)
{0xBE, 0x2F}, // . (Period)
{0xBF, 0x2C}, // / (Slash)
{0xDC, 0x2A}, // \ (Backslash)
{0xDB, 0x21}, // [ (Left Bracket)
{0xDD, 0x1E}, // ] (Right Bracket)
{0xBD, 0x1B}, // - (Minus)
{0xBB, 0x18}, // = (Equals)
// modifier keys
{0x14, 0x39}, // Caps Lock
{0xA0, 0x38}, // Shift (Left)
{0xA1, 0x3C}, // Shift (Right)
{0xA2, 0x3B}, // Ctrl (Left)
{0xA3, 0x3E}, // Ctrl (Right)
{0xA4, 0x3A}, // Alt (Left)
{0xA5, 0x3D}, // Alt (Right)
{0x5B, 0x37}, // Left Command (Windows key)
{0x5C, 0x36}, // Right Command
};
// macOS CGKeyCode to Windows vkCode
std::map<int, int> CGKeyCodeToVkCode = {
// A-Z
{0x00, 0x41}, // A
{0x0B, 0x42}, // B
{0x08, 0x43}, // C
{0x02, 0x44}, // D
{0x0E, 0x45}, // E
{0x03, 0x46}, // F
{0x05, 0x47}, // G
{0x04, 0x48}, // H
{0x22, 0x49}, // I
{0x26, 0x4A}, // J
{0x28, 0x4B}, // K
{0x25, 0x4C}, // L
{0x2E, 0x4D}, // M
{0x2D, 0x4E}, // N
{0x1F, 0x4F}, // O
{0x23, 0x50}, // P
{0x0C, 0x51}, // Q
{0x0F, 0x52}, // R
{0x01, 0x53}, // S
{0x11, 0x54}, // T
{0x20, 0x55}, // U
{0x09, 0x56}, // V
{0x0D, 0x57}, // W
{0x07, 0x58}, // X
{0x10, 0x59}, // Y
{0x06, 0x5A}, // Z
// 0-9
{0x1D, 0x30}, // 0
{0x12, 0x31}, // 1
{0x13, 0x32}, // 2
{0x14, 0x33}, // 3
{0x15, 0x34}, // 4
{0x17, 0x35}, // 5
{0x16, 0x36}, // 6
{0x1A, 0x37}, // 7
{0x1C, 0x38}, // 8
{0x19, 0x39}, // 9
// F1-F12
{0x7A, 0x70}, // F1
{0x78, 0x71}, // F2
{0x63, 0x72}, // F3
{0x76, 0x73}, // F4
{0x60, 0x74}, // F5
{0x61, 0x75}, // F6
{0x62, 0x76}, // F7
{0x64, 0x77}, // F8
{0x65, 0x78}, // F9
{0x6D, 0x79}, // F10
{0x67, 0x7A}, // F11
{0x6F, 0x7B}, // F12
// control keys
{0x35, 0x1B}, // Escape
{0x24, 0x0D}, // Enter
{0x31, 0x20}, // Space
{0x33, 0x08}, // Backspace
{0x30, 0x09}, // Tab
{0x74, 0x2C}, // Print Screen
{0x72, 0x2D}, // Insert
{0x75, 0x2E}, // Delete
{0x73, 0x24}, // Home
{0x77, 0x23}, // End
{0x79, 0x21}, // Page Up
{0x7A, 0x22}, // Page Down
// arrow keys
{0x7B, 0x25}, // Left Arrow
{0x7C, 0x27}, // Right Arrow
{0x7E, 0x26}, // Up Arrow
{0x7D, 0x28}, // Down Arrow
// numpad
{0x52, 0x60}, // Numpad 0
{0x53, 0x61}, // Numpad 1
{0x54, 0x62}, // Numpad 2
{0x55, 0x63}, // Numpad 3
{0x56, 0x64}, // Numpad 4
{0x57, 0x65}, // Numpad 5
{0x58, 0x66}, // Numpad 6
{0x59, 0x67}, // Numpad 7
{0x5B, 0x68}, // Numpad 8
{0x5C, 0x69}, // Numpad 9
{0x41, 0x6E}, // Numpad .
{0x4B, 0x6F}, // Numpad /
{0x43, 0x6A}, // Numpad *
{0x4E, 0x6D}, // Numpad -
{0x45, 0x6B}, // Numpad +
// symbol keys
{0x29, 0xBA}, // ; (Semicolon)
{0x27, 0xDE}, // ' (Quote)
{0x32, 0xC0}, // ` (Backtick)
{0x2B, 0xBC}, // , (Comma)
{0x2F, 0xBE}, // . (Period)
{0x2C, 0xBF}, // / (Slash)
{0x2A, 0xDC}, // \ (Backslash)
{0x21, 0xDB}, // [ (Left Bracket)
{0x1E, 0xDD}, // ] (Right Bracket)
{0x1B, 0xBD}, // - (Minus)
{0x18, 0xBB}, // = (Equals)
// modifier keys
{0x39, 0x14}, // Caps Lock
{0x38, 0xA0}, // Shift (Left)
{0x3C, 0xA1}, // Shift (Right)
{0x3B, 0xA2}, // Control (Left)
{0x3E, 0xA3}, // Control (Right)
{0x3A, 0xA4}, // Alt (Left)
{0x3D, 0xA5}, // Alt (Right)
{0x37, 0x5B}, // Left Command (Windows key)
{0x36, 0x5C}, // Right Command
};
#endif

View File

@@ -0,0 +1,56 @@
#include "keyboard_capturer.h"
#include "rd_log.h"
static OnKeyAction g_on_key_action = nullptr;
static void* g_user_ptr = nullptr;
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION && g_on_key_action) {
KBDLLHOOKSTRUCT* kbData = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
g_on_key_action(kbData->vkCode, true, g_user_ptr);
} else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
g_on_key_action(kbData->vkCode, false, g_user_ptr);
}
return 1;
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
KeyboardCapturer::KeyboardCapturer() {}
KeyboardCapturer::~KeyboardCapturer() {}
int KeyboardCapturer::Hook(OnKeyAction on_key_action, void* user_ptr) {
g_on_key_action = on_key_action;
g_user_ptr = user_ptr;
keyboard_hook_ = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, NULL, 0);
if (!keyboard_hook_) {
LOG_ERROR("Failed to install keyboard hook!")
return -1;
}
return 0;
}
int KeyboardCapturer::Unhook() {
UnhookWindowsHookEx(keyboard_hook_);
return 0;
}
// apply remote keyboard commands to the local machine
int KeyboardCapturer::SendKeyboardCommand(int key_code, bool is_down) {
INPUT input = {0};
input.type = INPUT_KEYBOARD;
input.ki.wVk = (WORD)key_code;
if (!is_down) {
input.ki.dwFlags = KEYEVENTF_KEYUP;
}
SendInput(1, &input, sizeof(INPUT));
return 0;
}

View File

@@ -0,0 +1,28 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-11-22
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _KEYBOARD_CAPTURER_H_
#define _KEYBOARD_CAPTURER_H_
#include <Windows.h>
#include "device_controller.h"
class KeyboardCapturer : public DeviceController {
public:
KeyboardCapturer();
virtual ~KeyboardCapturer();
public:
virtual int Hook(OnKeyAction on_key_action, void *user_ptr);
virtual int Unhook();
virtual int SendKeyboardCommand(int key_code, bool is_down);
private:
HHOOK keyboard_hook_ = nullptr;
};
#endif

View File

@@ -20,8 +20,8 @@ int MouseController::SendCommand(RemoteAction remote_action) {
if (remote_action.type == ControlType::mouse) {
ip.type = INPUT_MOUSE;
ip.mi.dx = remote_action.m.x;
ip.mi.dy = remote_action.m.y;
ip.mi.dx = (LONG)remote_action.m.x;
ip.mi.dy = (LONG)remote_action.m.y;
if (remote_action.m.flag == MouseFlag::left_down) {
ip.mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE;
} else if (remote_action.m.flag == MouseFlag::left_up) {

View File

@@ -9,7 +9,7 @@
#include "rd_log.h"
#include "render.h"
int main(int argc, char *argv[]) {
int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[]) {
LOG_INFO("Remote desk");
Render render;

View File

@@ -22,13 +22,26 @@ static std::vector<std::string> remote_desktop = {u8"控制远程桌面",
"Control Remote Desktop"};
static std::vector<std::string> remote_id = {u8"对端ID", "Remote ID"};
static std::vector<std::string> connect = {u8"连接", "Connect"};
static std::vector<std::string> recent_connections = {u8"近期连接",
"Recent Connections"};
static std::vector<std::string> disconnect = {u8"断开连接", "Disconnect"};
static std::vector<std::string> fullscreen = {u8" 全屏", " Fullscreen"};
static std::vector<std::string> exit_fullscreen = {u8" 退出全屏",
" Exit fullscreen"};
static std::vector<std::string> control_mouse = {u8" 控制", " Control"};
static std::vector<std::string> release_mouse = {u8" 释放", " Release"};
static std::vector<std::string> audio_capture = {u8" 声音", " Audio"};
static std::vector<std::string> fullscreen = {u8"全屏", " Fullscreen"};
static std::vector<std::string> show_net_traffic_stats = {
u8"显示流量统计", "Show Net Traffic Stats"};
static std::vector<std::string> hide_net_traffic_stats = {
u8"隐藏流量统计", "Hide Net Traffic Stats"};
static std::vector<std::string> video = {u8"视频", "Video"};
static std::vector<std::string> audio = {u8"音频", "Audio"};
static std::vector<std::string> data = {u8"数据", "Data"};
static std::vector<std::string> total = {u8"总计", "Total"};
static std::vector<std::string> in = {u8"输入", "In"};
static std::vector<std::string> out = {u8"输出", "Out"};
static std::vector<std::string> loss_rate = {u8"丢包率", "Loss Rate"};
static std::vector<std::string> exit_fullscreen = {u8"退出全屏",
"Exit fullscreen"};
static std::vector<std::string> control_mouse = {u8"控制", "Control"};
static std::vector<std::string> release_mouse = {u8"释放", "Release"};
static std::vector<std::string> audio_capture = {u8"声音", "Audio"};
static std::vector<std::string> mute = {u8" 静音", " Mute"};
static std::vector<std::string> settings = {u8"设置", "Settings"};
static std::vector<std::string> language = {u8"语言:", "Language:"};
@@ -61,6 +74,9 @@ static std::vector<std::string> validate_password = {u8"验证密码中...",
static std::vector<std::string> reinput_password = {
u8"请重新输入密码", "Please input password again"};
static std::vector<std::string> remember_password = {u8"记住密码",
"Remember password"};
static std::vector<std::string> signal_connected = {u8"已连接服务器",
"Connected"};
static std::vector<std::string> signal_disconnected = {u8"未连接服务器",
@@ -80,6 +96,8 @@ static std::vector<std::string> no_such_id = {u8"无此ID", "No such ID"};
static std::vector<std::string> about = {u8"关于", "About"};
static std::vector<std::string> version = {u8"版本", "Version"};
static std::vector<std::string> confirm_delete_connection = {
u8"确认删除此连接", "Confirm to delete this connection"};
} // namespace localization
#endif

37
src/log/rd_log.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include "rd_log.h"
std::shared_ptr<spdlog::logger> get_logger() {
if (auto logger = spdlog::get(LOGGER_NAME)) {
return logger;
}
auto now = std::chrono::system_clock::now() + std::chrono::hours(8);
auto now_time = std::chrono::system_clock::to_time_t(now);
std::tm tm_info;
#ifdef _WIN32
gmtime_s(&tm_info, &now_time);
#else
gmtime_r(&now_time, &tm_info);
#endif
std::stringstream ss;
std::string filename;
ss << LOGGER_NAME;
ss << std::put_time(&tm_info, "-%Y%m%d-%H%M%S.log");
ss >> filename;
std::string path = "logs/" + filename;
std::vector<spdlog::sink_ptr> sinks;
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>());
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
path, 1048576 * 5, 3));
auto combined_logger =
std::make_shared<spdlog::logger>(LOGGER_NAME, begin(sinks), end(sinks));
combined_logger->flush_on(spdlog::level::info);
spdlog::register_logger(combined_logger);
return combined_logger;
}

View File

@@ -1,6 +1,6 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-07-17
* @Date: 2024-11-26
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
@@ -26,97 +26,14 @@ using namespace std::chrono;
constexpr auto LOGGER_NAME = "rd";
#define LOG_INFO(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
combined_logger->flush_on(spdlog::level::info); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_INFO(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_INFO(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
std::shared_ptr<spdlog::logger> get_logger();
#define LOG_WARN(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_WARN(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_WARN(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_INFO(...) SPDLOG_LOGGER_INFO(get_logger(), __VA_ARGS__);
#define LOG_ERROR(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_ERROR(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_ERROR(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_WARN(...) SPDLOG_LOGGER_WARN(get_logger(), __VA_ARGS__);
#define LOG_FATAL(...) \
if (nullptr == spdlog::get(LOGGER_NAME)) { \
auto now = std::chrono::system_clock::now() + std::chrono::hours(8); \
auto timet = std::chrono::system_clock::to_time_t(now); \
auto localTime = *std::gmtime(&timet); \
std::stringstream ss; \
std::string filename; \
ss << LOGGER_NAME; \
ss << std::put_time(&localTime, "-%Y%m%d-%H%M%S.log"); \
ss >> filename; \
std::string path = "logs/" + filename; \
std::vector<spdlog::sink_ptr> sinks; \
sinks.push_back(std::make_shared<spdlog::sinks::stdout_color_sink_mt>()); \
sinks.push_back(std::make_shared<spdlog::sinks::rotating_file_sink_mt>( \
path, 1048576 * 5, 3)); \
auto combined_logger = std::make_shared<spdlog::logger>( \
LOGGER_NAME, begin(sinks), end(sinks)); \
spdlog::register_logger(combined_logger); \
SPDLOG_LOGGER_CRITICAL(combined_logger, __VA_ARGS__); \
} else { \
SPDLOG_LOGGER_CRITICAL(spdlog::get(LOGGER_NAME), __VA_ARGS__); \
}
#define LOG_ERROR(...) SPDLOG_LOGGER_ERROR(get_logger(), __VA_ARGS__);
#define LOG_FATAL(...) SPDLOG_LOGGER_CRITICAL(get_logger(), __VA_ARGS__);
#endif

View File

@@ -9,8 +9,8 @@
#include "libyuv.h"
BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, HDC hdc, LPRECT lprc,
LPARAM data) {
BOOL WINAPI EnumMonitorProc(HMONITOR hmonitor, [[maybe_unused]] HDC hdc,
[[maybe_unused]] LPRECT lprc, LPARAM data) {
MONITORINFOEX info_ex;
info_ex.cbSize = sizeof(MONITORINFOEX);

View File

@@ -148,7 +148,7 @@ auto WgcSessionImpl::CreateD3D11Device() {
if (DXGI_ERROR_UNSUPPORTED == hr) {
// change D3D_DRIVER_TYPE
D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_WARP;
type = D3D_DRIVER_TYPE_WARP;
hr = D3D11CreateDevice(nullptr, type, nullptr, flags, nullptr, 0,
D3D11_SDK_VERSION, d3d_device.put(), nullptr,
nullptr);
@@ -213,7 +213,7 @@ HRESULT WgcSessionImpl::CreateMappedTexture(
void WgcSessionImpl::OnFrame(
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool const &sender,
winrt::Windows::Foundation::IInspectable const &args) {
[[maybe_unused]] winrt::Windows::Foundation::IInspectable const &args) {
std::lock_guard locker(lock_);
auto is_new_size = false;

View File

@@ -1,4 +1,3 @@
#include "IconsFontAwesome6.h"
#include "layout_style.h"
#include "localization.h"
#include "rd_log.h"

View File

@@ -39,7 +39,15 @@ int Render::ConnectionStatusWindow() {
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3);
} else if (ConnectionStatus::Connected == connection_status_) {
text = localization::p2p_connected[localization_language_index_];
// show_connection_status_window_ = false;
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3);
// ok
if (ImGui::Button(
localization::ok[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Enter) ||
ImGui::IsKeyPressed(ImGuiKey_Escape)) {
show_connection_status_window_ = false;
}
} else if (ConnectionStatus::Disconnected == connection_status_) {
text = localization::p2p_disconnected[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 3 / 7);
@@ -80,6 +88,7 @@ int Render::ConnectionStatusWindow() {
} else {
text = localization::reinput_password[localization_language_index_];
}
auto window_width = ImGui::GetWindowSize().x;
auto window_height = ImGui::GetWindowSize().y;
ImGui::SetCursorPosX((window_width - IPUT_WINDOW_WIDTH / 2) * 0.5f);
@@ -92,10 +101,22 @@ int Render::ConnectionStatusWindow() {
ImGui::SetKeyboardFocusHere();
focus_on_input_widget_ = false;
}
ImGui::InputText("##password", remote_password_,
IM_ARRAYSIZE(remote_password_),
ImGuiInputTextFlags_CharsNoBlank);
ImGui::SetWindowFontScale(0.4f);
ImVec2 text_size = ImGui::CalcTextSize(
localization::remember_password[localization_language_index_]
.c_str());
ImGui::SetCursorPosX((window_width - text_size.x) * 0.5f - 13.0f);
ImGui::Checkbox(
localization::remember_password[localization_language_index_]
.c_str(),
&remember_password_);
ImGui::SetWindowFontScale(0.5f);
ImGui::PopStyleVar();
ImGui::SetCursorPosX(window_width * 0.315f);
@@ -131,8 +152,9 @@ int Render::ConnectionStatusWindow() {
// ok
if (ImGui::Button(
localization::ok[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Escape)) {
ImGui::IsKeyPressed(ImGuiKey_Enter)) {
show_connection_status_window_ = false;
re_enter_remote_id_ = true;
}
}

View File

@@ -1,15 +1,41 @@
#include "IconsFontAwesome6.h"
#include "layout_style.h"
#include "localization.h"
#include "rd_log.h"
#include "render.h"
int CountDigits(int number) {
if (number == 0) return 1;
return (int)std::floor(std::log10(std::abs(number))) + 1;
}
int BitrateDisplay(int bitrate) {
int num_of_digits = CountDigits(bitrate);
if (num_of_digits <= 3) {
ImGui::Text("%d bps", bitrate);
} else if (num_of_digits > 3 && num_of_digits <= 6) {
ImGui::Text("%d kbps", bitrate / 1000);
} else {
ImGui::Text("%.1f mbps", bitrate / 1000000.0f);
}
return 0;
}
int LossRateDisplay(float loss_rate) {
if (loss_rate < 0.01f) {
ImGui::Text("0%%");
} else {
ImGui::Text("%.0f%%", loss_rate * 100);
}
return 0;
}
int Render::ControlBar() {
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImVec2 mouse_button_pos = ImVec2(0, 0);
if (control_bar_expand_) {
ImGui::SetCursorPosX(
is_control_bar_in_left_ ? (control_window_width_ + 5.0f) : 41.0f);
is_control_bar_in_left_ ? (control_window_width_ + 5.0f) : 38.0f);
// mouse control button
ImDrawList* draw_list = ImGui::GetWindowDrawList();
@@ -22,6 +48,7 @@ int Render::ControlBar() {
IM_COL32(178, 178, 178, 255), 1.0f);
}
mouse_button_pos = ImGui::GetCursorScreenPos();
float disable_mouse_x = ImGui::GetCursorScreenPos().x + 4.0f;
float disable_mouse_y = ImGui::GetCursorScreenPos().y + 4.0f;
std::string mouse = mouse_control_button_pressed_ ? ICON_FA_COMPUTER_MOUSE
@@ -29,6 +56,7 @@ int Render::ControlBar() {
if (ImGui::Button(mouse.c_str(), ImVec2(25, 25))) {
if (connection_established_) {
control_mouse_ = !control_mouse_;
start_keyboard_capturer_ = !start_keyboard_capturer_;
mouse_control_button_pressed_ = !mouse_control_button_pressed_;
mouse_control_button_label_ =
mouse_control_button_pressed_
@@ -69,7 +97,7 @@ int Render::ControlBar() {
RemoteAction remote_action;
remote_action.type = ControlType::audio_capture;
remote_action.a = audio_capture_button_pressed_;
SendData(peer_, DATA_TYPE::DATA, (const char*)&remote_action,
SendDataFrame(peer_, (const char*)&remote_action,
sizeof(remote_action));
}
}
@@ -86,6 +114,31 @@ int Render::ControlBar() {
2.0f);
}
ImGui::SameLine();
// net traffic stats button
bool button_color_style_pushed = false;
if (net_traffic_stats_button_pressed_) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(66 / 255.0f, 150 / 255.0f,
250 / 255.0f, 1.0f));
button_color_style_pushed = true;
}
std::string net_traffic_stats = ICON_FA_SIGNAL;
if (ImGui::Button(net_traffic_stats.c_str(), ImVec2(25, 25))) {
net_traffic_stats_button_pressed_ = !net_traffic_stats_button_pressed_;
control_window_height_is_changing_ = true;
net_traffic_stats_button_pressed_time_ = ImGui::GetTime();
net_traffic_stats_button_label_ =
net_traffic_stats_button_pressed_
? localization::hide_net_traffic_stats
[localization_language_index_]
: localization::show_net_traffic_stats
[localization_language_index_];
}
if (button_color_style_pushed) {
ImGui::PopStyleColor();
button_color_style_pushed = false;
}
ImGui::SameLine();
// fullscreen button
std::string fullscreen =
@@ -96,11 +149,15 @@ int Render::ControlBar() {
fullscreen_button_pressed_
? localization::exit_fullscreen[localization_language_index_]
: localization::fullscreen[localization_language_index_];
// save stream window last size
SDL_GetWindowSize(stream_window_, &stream_window_width_last_,
&stream_window_height_last_);
if (fullscreen_button_pressed_) {
SDL_SetWindowFullscreen(main_window_, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_SetWindowFullscreen(stream_window_, SDL_WINDOW_FULLSCREEN_DESKTOP);
} else {
SDL_SetWindowFullscreen(main_window_, SDL_FALSE);
SDL_SetWindowFullscreen(stream_window_, SDL_FALSE);
}
reset_control_bar_pos_ = true;
}
ImGui::SameLine();
@@ -125,7 +182,7 @@ int Render::ControlBar() {
}
ImGui::SetCursorPosX(
is_control_bar_in_left_ ? (control_window_width_ * 2 - 18.0f) : 3.0f);
is_control_bar_in_left_ ? (control_window_width_ * 2 - 20.0f) : 5.0f);
std::string control_bar =
control_bar_expand_
@@ -136,9 +193,89 @@ int Render::ControlBar() {
control_bar_expand_ = !control_bar_expand_;
control_bar_button_pressed_time_ = ImGui::GetTime();
control_window_width_is_changing_ = true;
if (!control_bar_expand_) {
control_window_height_ = 40;
net_traffic_stats_button_pressed_ = false;
}
}
if (net_traffic_stats_button_pressed_ && control_bar_expand_) {
NetTrafficStats();
}
ImGui::PopStyleVar();
return 0;
}
int Render::NetTrafficStats() {
ImGui::SetCursorPos(ImVec2(
is_control_bar_in_left_ ? (control_window_width_ + 5.0f) : 5.0f, 40.0f));
if (ImGui::BeginTable("NetTrafficStats", 4, ImGuiTableFlags_BordersH,
ImVec2(control_window_max_width_ - 10.0f,
control_window_max_height_ - 40.0f))) {
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableNextColumn();
ImGui::Text(" ");
ImGui::TableNextColumn();
ImGui::Text("%s", localization::in[localization_language_index_].c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", localization::out[localization_language_index_].c_str());
ImGui::TableNextColumn();
ImGui::Text("%s",
localization::loss_rate[localization_language_index_].c_str());
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s",
localization::video[localization_language_index_].c_str());
ImGui::TableNextColumn();
BitrateDisplay((int)net_traffic_stats_.video_inbound_stats.bitrate);
ImGui::TableNextColumn();
BitrateDisplay((int)net_traffic_stats_.video_outbound_stats.bitrate);
ImGui::TableNextColumn();
LossRateDisplay(net_traffic_stats_.video_inbound_stats.loss_rate);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s",
localization::audio[localization_language_index_].c_str());
ImGui::TableNextColumn();
BitrateDisplay((int)net_traffic_stats_.audio_inbound_stats.bitrate);
ImGui::TableNextColumn();
BitrateDisplay((int)net_traffic_stats_.audio_outbound_stats.bitrate);
ImGui::TableNextColumn();
LossRateDisplay(net_traffic_stats_.audio_inbound_stats.loss_rate);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s", localization::data[localization_language_index_].c_str());
ImGui::TableNextColumn();
BitrateDisplay((int)net_traffic_stats_.data_inbound_stats.bitrate);
ImGui::TableNextColumn();
BitrateDisplay((int)net_traffic_stats_.data_outbound_stats.bitrate);
ImGui::TableNextColumn();
LossRateDisplay(net_traffic_stats_.data_inbound_stats.loss_rate);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s",
localization::total[localization_language_index_].c_str());
ImGui::TableNextColumn();
BitrateDisplay((int)net_traffic_stats_.total_inbound_stats.bitrate);
ImGui::TableNextColumn();
BitrateDisplay((int)net_traffic_stats_.total_outbound_stats.bitrate);
ImGui::TableNextColumn();
LossRateDisplay(net_traffic_stats_.total_inbound_stats.loss_rate);
ImGui::EndTable();
}
return 0;
}

View File

@@ -2,18 +2,33 @@
#include "render.h"
int Render::ControlWindow() {
auto time_duration = ImGui::GetTime() - control_bar_button_pressed_time_;
double time_duration = ImGui::GetTime() - control_bar_button_pressed_time_;
if (control_window_width_is_changing_) {
if (control_bar_expand_) {
control_window_width_ =
control_window_min_width_ +
(float)(control_window_min_width_ +
(control_window_max_width_ - control_window_min_width_) * 4 *
time_duration;
time_duration);
} else {
control_window_width_ =
control_window_max_width_ -
(float)(control_window_max_width_ -
(control_window_max_width_ - control_window_min_width_) * 4 *
time_duration;
time_duration);
}
}
time_duration = ImGui::GetTime() - net_traffic_stats_button_pressed_time_;
if (control_window_height_is_changing_) {
if (control_bar_expand_ && net_traffic_stats_button_pressed_) {
control_window_height_ =
(float)(control_window_min_height_ +
(control_window_max_height_ - control_window_min_height_) *
4 * time_duration);
} else if (control_bar_expand_ && !net_traffic_stats_button_pressed_) {
control_window_height_ =
(float)(control_window_max_height_ -
(control_window_max_height_ - control_window_min_height_) *
4 * time_duration);
}
}
@@ -26,21 +41,82 @@ int Render::ControlWindow() {
ImGui::SetNextWindowSize(
ImVec2(control_window_width_, control_window_height_), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(0, title_bar_height_), ImGuiCond_Once);
if (ImGui::IsMouseReleased(ImGuiPopupFlags_MouseButtonLeft) ||
if (0 == control_winodw_pos_.x && 0 == control_winodw_pos_.y) {
ImGui::SetNextWindowPos(ImVec2(0, title_bar_height_ + 1), ImGuiCond_Once);
}
if (reset_control_bar_pos_) {
float new_control_window_pos_x, new_control_window_pos_y, new_cursor_pos_x,
new_cursor_pos_y;
// set control window pos
new_control_window_pos_x = control_winodw_pos_.x;
if (control_winodw_pos_.y < stream_render_rect_last_.y) {
new_control_window_pos_y =
stream_render_rect_.y -
(stream_render_rect_last_.y - control_winodw_pos_.y);
if (fullscreen_button_pressed_ && new_control_window_pos_y < 0) {
new_control_window_pos_y = 0;
} else if (!fullscreen_button_pressed_ &&
new_control_window_pos_y < (title_bar_height_ + 1)) {
new_control_window_pos_y = title_bar_height_ + 1;
}
} else if (control_winodw_pos_.y + control_window_height_ >
stream_render_rect_last_.y + stream_render_rect_last_.h) {
new_control_window_pos_y =
stream_render_rect_.y + stream_render_rect_.h +
(control_winodw_pos_.y - stream_render_rect_last_.y -
stream_render_rect_last_.h);
if (new_control_window_pos_y >
stream_window_height_ - control_window_height_) {
new_control_window_pos_y =
stream_window_height_ - control_window_height_;
}
} else if (control_winodw_pos_.y + control_window_height_ ==
stream_render_rect_last_.y + stream_render_rect_last_.h) {
new_control_window_pos_y = stream_render_rect_.y + stream_render_rect_.h -
control_window_height_;
} else {
new_control_window_pos_y =
(control_winodw_pos_.y - stream_render_rect_last_.y) /
(float)(stream_render_rect_last_.h) * stream_render_rect_.h +
stream_render_rect_.y;
}
ImGui::SetNextWindowPos(
ImVec2(new_control_window_pos_x, new_control_window_pos_y),
ImGuiCond_Always);
if (0 != mouse_diff_control_bar_pos_x_ &&
0 != mouse_diff_control_bar_pos_y_) {
// set cursor pos
new_cursor_pos_x =
new_control_window_pos_x + mouse_diff_control_bar_pos_x_;
new_cursor_pos_y =
new_control_window_pos_y + mouse_diff_control_bar_pos_y_;
SDL_WarpMouseInWindow(stream_window_, (int)new_cursor_pos_x,
(int)new_cursor_pos_y);
}
reset_control_bar_pos_ = false;
} else if (!reset_control_bar_pos_ &&
ImGui::IsMouseReleased(ImGuiPopupFlags_MouseButtonLeft) ||
control_window_width_is_changing_) {
if (control_winodw_pos_.x <= main_window_width_ / 2) {
int pos_x = 0;
int pos_y =
if (control_winodw_pos_.x <= stream_window_width_ / 2) {
float pos_x = 0;
float pos_y =
(control_winodw_pos_.y >=
(fullscreen_button_pressed_ ? 0 : title_bar_height_) &&
(fullscreen_button_pressed_ ? 0 : (title_bar_height_ + 1)) &&
control_winodw_pos_.y <=
main_window_height_ - control_window_height_)
stream_window_height_ - control_window_height_)
? control_winodw_pos_.y
: (control_winodw_pos_.y <
(fullscreen_button_pressed_ ? 0 : title_bar_height_)
? (fullscreen_button_pressed_ ? 0 : title_bar_height_)
: (main_window_height_ - control_window_height_));
: (control_winodw_pos_.y < (fullscreen_button_pressed_
? 0
: (title_bar_height_ + 1))
? (fullscreen_button_pressed_ ? 0
: (title_bar_height_ + 1))
: (stream_window_height_ - control_window_height_));
if (control_bar_expand_) {
if (control_window_width_ >= control_window_max_width_) {
@@ -59,36 +135,38 @@ int Render::ControlWindow() {
}
ImGui::SetNextWindowPos(ImVec2(pos_x, pos_y), ImGuiCond_Always);
is_control_bar_in_left_ = true;
} else if (control_winodw_pos_.x > main_window_width_ / 2) {
int pos_x = 0;
int pos_y =
} else if (control_winodw_pos_.x > stream_window_width_ / 2) {
float pos_x = 0;
float pos_y =
(control_winodw_pos_.y >=
(fullscreen_button_pressed_ ? 0 : title_bar_height_) &&
(fullscreen_button_pressed_ ? 0 : (title_bar_height_ + 1)) &&
control_winodw_pos_.y <=
main_window_height_ - control_window_height_)
stream_window_height_ - control_window_height_)
? control_winodw_pos_.y
: (control_winodw_pos_.y <
(fullscreen_button_pressed_ ? 0 : title_bar_height_)
? (fullscreen_button_pressed_ ? 0 : title_bar_height_)
: (main_window_height_ - control_window_height_));
: (control_winodw_pos_.y < (fullscreen_button_pressed_
? 0
: (title_bar_height_ + 1))
? (fullscreen_button_pressed_ ? 0
: (title_bar_height_ + 1))
: (stream_window_height_ - control_window_height_));
if (control_bar_expand_) {
if (control_window_width_ >= control_window_max_width_) {
control_window_width_ = control_window_max_width_;
control_window_width_is_changing_ = false;
pos_x = main_window_width_ - control_window_max_width_;
pos_x = stream_window_width_ - control_window_max_width_;
} else {
control_window_width_is_changing_ = true;
pos_x = main_window_width_ - control_window_width_;
pos_x = stream_window_width_ - control_window_width_;
}
} else {
if (control_window_width_ <= control_window_min_width_) {
control_window_width_ = control_window_min_width_;
control_window_width_is_changing_ = false;
pos_x = main_window_width_ - control_window_min_width_;
pos_x = stream_window_width_ - control_window_min_width_;
} else {
control_window_width_is_changing_ = true;
pos_x = main_window_width_ - control_window_width_;
pos_x = stream_window_width_ - control_window_width_;
}
}
ImGui::SetNextWindowPos(ImVec2(pos_x, pos_y), ImGuiCond_Always);
@@ -96,13 +174,34 @@ int Render::ControlWindow() {
}
}
if (control_bar_expand_ && control_window_height_is_changing_) {
if (net_traffic_stats_button_pressed_) {
if (control_window_height_ >= control_window_max_height_) {
control_window_height_ = control_window_max_height_;
control_window_height_is_changing_ = false;
} else {
control_window_height_is_changing_ = true;
}
} else {
if (control_window_height_ <= control_window_min_height_) {
control_window_height_ = control_window_min_height_;
control_window_height_is_changing_ = false;
} else {
control_window_height_is_changing_ = true;
}
}
}
ImGui::Begin("ControlWindow", nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGuiWindowFlags_NoScrollbar);
ImGui::PopStyleVar();
control_winodw_pos_ = ImGui::GetWindowPos();
SDL_GetMouseState(&mouse_pos_x_, &mouse_pos_y_);
mouse_diff_control_bar_pos_x_ = mouse_pos_x_ - control_winodw_pos_.x;
mouse_diff_control_bar_pos_y_ = mouse_pos_y_ - control_winodw_pos_.y;
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
static bool a, b, c, d, e;
ImGui::SetNextWindowPos(
@@ -127,24 +226,5 @@ int Render::ControlWindow() {
ImGui::PopStyleVar(4);
ImGui::PopStyleColor();
ImGui::SetNextWindowPos(
ImVec2(0, fullscreen_button_pressed_ ? 0 : title_bar_height_),
ImGuiCond_Always);
ImGui::SetNextWindowSize(
ImVec2(main_window_width_,
main_window_height_ -
(fullscreen_button_pressed_ ? 0 : title_bar_height_)),
ImGuiCond_Always);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_Border,
ImVec4(178 / 255.0f, 178 / 255.0f, 178 / 255.0f,
fullscreen_button_pressed_ ? 0 : 1.0f));
ImGui::Begin("VideoBg", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleColor(2);
ImGui::End();
return 0;
}

View File

@@ -1,36 +1,42 @@
#include <random>
#include "IconsFontAwesome6.h"
#include "layout_style.h"
#include "localization.h"
#include "rd_log.h"
#include "render.h"
int Render::LocalWindow() {
ImGui::SetNextWindowPos(ImVec2(0, title_bar_height_), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(-1.0f, title_bar_height_), ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::BeginChild(
"LocalDesktopWindow",
ImVec2(local_window_width_, main_window_height_default_ -
title_bar_height_ - status_bar_height_),
ImGuiChildFlags_Border,
ImGui::BeginChild("LocalDesktopWindow",
ImVec2(local_window_width_, local_window_height_),
ImGuiChildFlags_None,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleColor();
ImGui::SetWindowFontScale(1.0f);
ImGui::Text(
"%s", localization::local_desktop[localization_language_index_].c_str());
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + main_window_text_y_padding_);
ImGui::Indent(main_child_window_x_padding_);
ImGui::TextColored(
ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s",
localization::local_desktop[localization_language_index_].c_str());
ImGui::Spacing();
{
ImGui::PushStyleColor(ImGuiCol_ChildBg,
ImVec4(239.0 / 255, 240.0 / 255, 242.0 / 255, 1.0f));
ImGui::SetNextWindowPos(
ImVec2(main_child_window_x_padding_,
title_bar_height_ + main_child_window_y_padding_),
ImGuiCond_Always);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(239.0f / 255, 240.0f / 255,
242.0f / 255, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::BeginChild("LocalDesktopWindow_1", ImVec2(330, 180),
ImGui::BeginChild(
"LocalDesktopWindow_1",
ImVec2(local_child_window_width_, local_child_window_height_),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoTitleBar |
@@ -38,7 +44,7 @@ int Render::LocalWindow() {
ImGui::PopStyleVar();
ImGui::PopStyleColor();
{
ImGui::SetWindowFontScale(0.5f);
ImGui::SetWindowFontScale(0.8f);
ImGui::Text("%s",
localization::local_id[localization_language_index_].c_str());
@@ -48,34 +54,35 @@ int Render::LocalWindow() {
ImGui::SetWindowFontScale(1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
char client_id_display[12] = "";
if (strcmp(client_id_display_, client_id_)) {
for (int i = 0, j = 0; i < sizeof(client_id_); i++, j++) {
client_id_display[j] = client_id_[i];
client_id_display_[j] = client_id_[i];
if (i == 2 || i == 5) {
client_id_display[++j] = ' ';
client_id_display_[++j] = ' ';
}
}
}
ImGui::InputText(
"##local_id", client_id_display, IM_ARRAYSIZE(client_id_display),
"##local_id", client_id_display_, IM_ARRAYSIZE(client_id_display_),
ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_ReadOnly);
ImGui::PopStyleVar();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(ICON_FA_COPY, ImVec2(35, 38))) {
local_id_copied_ = true;
ImGui::SetClipboardText(client_id_);
copy_start_time_ = ImGui::GetTime();
}
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(3);
auto time_duration = ImGui::GetTime() - copy_start_time_;
double time_duration = ImGui::GetTime() - copy_start_time_;
if (local_id_copied_ && time_duration < 1.0f) {
const ImGuiViewport *viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(
@@ -88,8 +95,9 @@ int Render::LocalWindow() {
ImGui::SetNextWindowSize(
ImVec2(notification_window_width_, notification_window_height_));
ImGui::PushStyleColor(ImGuiCol_WindowBg,
ImVec4(1.0, 1.0, 1.0, 1.0 - time_duration));
ImGui::PushStyleColor(
ImGuiCol_WindowBg,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f - (float)time_duration));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::Begin("ConnectionStatusWindow", nullptr,
@@ -107,7 +115,7 @@ int Render::LocalWindow() {
ImGui::SetCursorPosX((window_width - text_width) * 0.5f);
ImGui::SetCursorPosY(window_height * 0.5f);
ImGui::PushStyleColor(ImGuiCol_Text,
ImVec4(0, 0, 0, 1.0 - time_duration));
ImVec4(0, 0, 0, 1.0f - (float)time_duration));
ImGui::Text("%s", text.c_str());
ImGui::PopStyleColor();
ImGui::SetWindowFontScale(1.0f);
@@ -115,16 +123,14 @@ int Render::LocalWindow() {
ImGui::End();
}
ImGui::SetWindowFontScale(1.0f);
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
ImGui::SetWindowFontScale(0.5f);
ImGui::SetWindowFontScale(0.8f);
ImGui::Text("%s",
localization::password[localization_language_index_].c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::SetNextItemWidth(IPUT_WINDOW_WIDTH);
ImGui::Spacing();
@@ -132,24 +138,25 @@ int Render::LocalWindow() {
if (!password_inited_) {
char a[] = {
"123456789QWERTYUPASDFGHJKLZXCVBNMqwertyupasdfghijkzxcvbnm"};
std::mt19937 generator(
std::chrono::system_clock::now().time_since_epoch().count());
std::uniform_int_distribution<int> distribution(0, strlen(a) - 1);
std::mt19937 generator((unsigned int)std::chrono::system_clock::now()
.time_since_epoch()
.count());
std::uniform_int_distribution<int> distribution(0,
(int)(strlen(a) - 1));
random_password_.clear();
for (int i = 0, len = strlen(a); i < 6; i++) {
for (int i = 0; i < 6; i++) {
random_password_ += a[distribution(generator)];
}
password_inited_ = true;
if (0 != strcmp(random_password_.c_str(), password_saved_)) {
strncpy(password_saved_, random_password_.c_str(),
memcpy(password_saved_, random_password_.c_str(),
sizeof(password_saved_));
LOG_INFO("Generate new password and save into cache file");
SaveSettingsIntoCacheFile();
}
}
ImGui::SetWindowFontScale(1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
ImGui::InputTextWithHint(
"##server_pwd",
@@ -166,7 +173,6 @@ int Render::LocalWindow() {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
ImGui::SetWindowFontScale(0.5f);
auto l_x = ImGui::GetCursorScreenPos().x;
auto l_y = ImGui::GetCursorScreenPos().y;
@@ -238,9 +244,9 @@ int Render::LocalWindow() {
auto window_height = ImGui::GetWindowSize().y;
std::string text =
localization::new_password[localization_language_index_];
auto text_width = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetWindowFontScale(0.5f);
ImGui::SetCursorPosX((window_width - text_width / 2) * 0.5f);
auto text_width = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetCursorPosX((window_width - text_width) * 0.5f);
ImGui::SetCursorPosY(window_height * 0.2f);
ImGui::Text("%s", text.c_str());
@@ -276,7 +282,7 @@ int Render::LocalWindow() {
} else {
show_reset_password_window_ = false;
LOG_INFO("Generate new password and save into cache file");
strncpy(password_saved_, new_password_, sizeof(password_saved_));
memcpy(password_saved_, new_password_, sizeof(password_saved_));
memset(new_password_, 0, sizeof(new_password_));
SaveSettingsIntoCacheFile();
LeaveConnection(peer_, client_id_);
@@ -302,7 +308,6 @@ int Render::LocalWindow() {
}
ImGui::EndChild();
ImGui::PopStyleVar();
}
ImGui::EndChild();

View File

@@ -1,13 +1,32 @@
#include "localization.h"
#include "rd_log.h"
#include "render.h"
int Render::MainWindow() {
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetNextWindowSize(
ImVec2(main_window_width_default_, main_window_height_default_),
ImGuiCond_Always);
ImGui::SetNextWindowPos(ImVec2(0, title_bar_height_), ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::BeginChild("DeskWindow",
ImVec2(main_window_width_default_, local_window_height_),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar();
ImGui::PopStyleColor();
LocalWindow();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddLine(
ImVec2(main_window_width_default_ / 2, title_bar_height_ + 15.0f),
ImVec2(main_window_width_default_ / 2, title_bar_height_ + 225.0f),
IM_COL32(0, 0, 0, 122), 1.0f);
RemoteWindow();
ImGui::EndChild();
RecentConnectionsWindow();
StatusBar();
ConnectionStatusWindow();

View File

@@ -0,0 +1,273 @@
#include "localization.h"
#include "rd_log.h"
#include "render.h"
int Render::RecentConnectionsWindow() {
ImGui::SetNextWindowPos(
ImVec2(0, title_bar_height_ + local_window_height_ - 1.0f),
ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::BeginChild(
"RecentConnectionsWindow",
ImVec2(main_window_width_default_,
main_window_height_default_ - title_bar_height_ -
local_window_height_ - status_bar_height_ + 1.0f),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + main_window_text_y_padding_);
ImGui::Indent(main_child_window_x_padding_);
ImGui::TextColored(
ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s",
localization::recent_connections[localization_language_index_].c_str());
ShowRecentConnections();
ImGui::EndChild();
return 0;
}
int Render::ShowRecentConnections() {
ImGui::SetCursorPosX(25.0f);
ImVec2 sub_window_pos = ImGui::GetCursorPos();
std::map<std::string, ImVec2> sub_containers_pos;
float recent_connection_sub_container_width =
recent_connection_image_width_ + 16.0f;
float recent_connection_sub_container_height =
recent_connection_image_height_ + 36.0f;
ImGui::PushStyleColor(ImGuiCol_ChildBg,
ImVec4(239.0f / 255, 240.0f / 255, 242.0f / 255, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::BeginChild("RecentConnectionsContainer",
ImVec2(main_window_width_default_ - 50.0f, 145.0f),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_AlwaysHorizontalScrollbar |
ImGuiWindowFlags_NoScrollbar |
ImGuiWindowFlags_NoScrollWithMouse);
ImGui::PopStyleVar();
ImGui::PopStyleColor();
size_t recent_connections_count = recent_connection_textures_.size();
int count = 0;
float button_width = 22;
float button_height = 22;
for (auto it = recent_connection_textures_.begin();
it != recent_connection_textures_.end(); ++it) {
sub_containers_pos[it->first] = ImGui::GetCursorPos();
std::string recent_connection_sub_window_name =
"RecentConnectionsSubContainer" + it->first;
// recent connections sub container
ImGui::BeginChild(recent_connection_sub_window_name.c_str(),
ImVec2(recent_connection_sub_container_width,
recent_connection_sub_container_height),
ImGuiChildFlags_None,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus |
ImGuiWindowFlags_NoScrollbar);
std::string connection_info = it->first;
std::string remote_id;
std::string password;
std::string host_name;
// remote id length is 9
// password length is 6
// connection_info -> remote_id + 'Y' + password + host_name
// -> remote_id + 'N' + host_name
if ('Y' == connection_info[9] && connection_info.size() >= 16) {
remote_id = connection_info.substr(0, 9);
password = connection_info.substr(10, 6);
host_name = connection_info.substr(16);
} else if ('N' == connection_info[9] && connection_info.size() >= 10) {
remote_id = connection_info.substr(0, 9);
host_name = connection_info.substr(10);
} else {
host_name = "unknown";
}
ImVec2 image_screen_pos = ImVec2(ImGui::GetCursorScreenPos().x + 5.0f,
ImGui::GetCursorScreenPos().y + 5.0f);
ImVec2 image_pos =
ImVec2(ImGui::GetCursorPosX() + 5.0f, ImGui::GetCursorPosY() + 5.0f);
ImGui::SetCursorPos(image_pos);
ImGui::Image((ImTextureID)(intptr_t)it->second,
ImVec2((float)recent_connection_image_width_,
(float)recent_connection_image_height_));
// remote id display button
{
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0.2f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.2f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0.2f));
ImVec2 dummy_button_pos =
ImVec2(image_pos.x, image_pos.y + recent_connection_image_height_);
std::string dummy_button_name = "##DummyButton" + remote_id;
ImGui::SetCursorPos(dummy_button_pos);
ImGui::SetWindowFontScale(0.6f);
ImGui::Button(dummy_button_name.c_str(),
ImVec2(recent_connection_image_width_ - 2 * button_width,
button_height));
ImGui::SetWindowFontScale(1.0f);
ImGui::SetCursorPos(
ImVec2(dummy_button_pos.x + 2.0f, dummy_button_pos.y + 1.0f));
ImGui::SetWindowFontScale(0.65f);
ImGui::Text("%s", remote_id.c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(3);
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::SetWindowFontScale(0.5f);
ImGui::Text("%s", host_name.c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::EndTooltip();
}
}
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0.2f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
ImVec4(0.1f, 0.4f, 0.8f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(1.0f, 1.0f, 1.0f, 0.7f));
ImGui::SetWindowFontScale(0.5f);
// trash button
{
ImVec2 trash_can_button_pos = ImVec2(
image_pos.x + recent_connection_image_width_ - 2 * button_width,
image_pos.y + recent_connection_image_height_);
ImGui::SetCursorPos(trash_can_button_pos);
std::string trash_can = ICON_FA_TRASH_CAN;
std::string recent_connection_delete_button_name =
trash_can + "##RecentConnectionDelete" +
std::to_string(trash_can_button_pos.x);
if (ImGui::Button(recent_connection_delete_button_name.c_str(),
ImVec2(button_width, button_height))) {
show_confirm_delete_connection_ = true;
}
if (delete_connection_) {
if (!thumbnail_->DeleteThumbnail(it->first)) {
reload_recent_connections_ = true;
delete_connection_ = false;
}
}
}
// connect button
{
ImVec2 connect_button_pos =
ImVec2(image_pos.x + recent_connection_image_width_ - button_width,
image_pos.y + recent_connection_image_height_);
ImGui::SetCursorPos(connect_button_pos);
std::string connect = ICON_FA_ARROW_RIGHT_LONG;
std::string connect_to_this_connection_button_name =
connect + "##ConnectionTo" + it->first;
if (ImGui::Button(connect_to_this_connection_button_name.c_str(),
ImVec2(button_width, button_height))) {
remote_id_ = remote_id;
if (!password.empty() && password.size() == 6) {
remember_password_ = true;
}
memcpy(remote_password_, password.c_str(), 6);
ConnectTo();
}
}
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor(3);
ImGui::EndChild();
if (count != recent_connections_count - 1) {
ImVec2 line_start =
ImVec2(image_screen_pos.x + recent_connection_image_width_ + 20.0f,
image_screen_pos.y);
ImVec2 line_end = ImVec2(
image_screen_pos.x + recent_connection_image_width_ + 20.0f,
image_screen_pos.y + recent_connection_image_height_ + button_height);
ImGui::GetForegroundDrawList()->AddLine(line_start, line_end,
IM_COL32(0, 0, 0, 122), 1.0f);
}
count++;
ImGui::SameLine(0, count != recent_connections_count ? 26.0f : 0.0f);
}
ImGui::EndChild();
if (show_confirm_delete_connection_) {
ConfirmDeleteConnection();
}
return 0;
}
int Render::ConfirmDeleteConnection() {
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(ImVec2((viewport->WorkSize.x - viewport->WorkPos.x -
connection_status_window_width_) /
2,
(viewport->WorkSize.y - viewport->WorkPos.y -
connection_status_window_height_) /
2));
ImGui::SetNextWindowSize(ImVec2(connection_status_window_width_,
connection_status_window_height_));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0, 1.0, 1.0, 1.0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f);
ImGui::Begin("ConfirmDeleteConnectionWindow", nullptr,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoSavedSettings);
ImGui::PopStyleVar(2);
ImGui::PopStyleColor();
std::string text =
localization::confirm_delete_connection[localization_language_index_];
ImGui::SetCursorPosX(connection_status_window_width_ * 6 / 19);
ImGui::SetCursorPosY(connection_status_window_height_ * 2 / 3);
// ok
ImGui::SetWindowFontScale(0.5f);
if (ImGui::Button(localization::ok[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Enter)) {
delete_connection_ = true;
show_confirm_delete_connection_ = false;
}
ImGui::SameLine();
// cancel
if (ImGui::Button(
localization::cancel[localization_language_index_].c_str()) ||
ImGui::IsKeyPressed(ImGuiKey_Escape)) {
delete_connection_ = false;
show_confirm_delete_connection_ = false;
}
auto window_width = ImGui::GetWindowSize().x;
auto window_height = ImGui::GetWindowSize().y;
auto text_width = ImGui::CalcTextSize(text.c_str()).x;
ImGui::SetCursorPosX((window_width - text_width) * 0.5f);
ImGui::SetCursorPosY(window_height * 0.2f);
ImGui::Text("%s", text.c_str());
ImGui::SetWindowFontScale(1.0f);
ImGui::End();
ImGui::PopStyleVar();
return 0;
}

View File

@@ -1,9 +1,95 @@
#include "IconsFontAwesome6.h"
#include "layout_style.h"
#include "localization.h"
#include "rd_log.h"
#include "render.h"
static int InputTextCallback(ImGuiInputTextCallbackData *data);
int Render::RemoteWindow() {
ImGui::SetNextWindowPos(ImVec2(local_window_width_ + 1.0f, title_bar_height_),
ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::BeginChild("RemoteDesktopWindow",
ImVec2(remote_window_width_, remote_window_height_),
ImGuiChildFlags_None,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleColor();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + main_window_text_y_padding_);
ImGui::Indent(main_child_window_x_padding_ - 1.0f);
ImGui::TextColored(
ImVec4(0.0f, 0.0f, 0.0f, 0.5f), "%s",
localization::remote_desktop[localization_language_index_].c_str());
ImGui::Spacing();
{
ImGui::SetNextWindowPos(
ImVec2(local_window_width_ + main_child_window_x_padding_ - 1.0f,
title_bar_height_ + main_child_window_y_padding_),
ImGuiCond_Always);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(239.0f / 255, 240.0f / 255,
242.0f / 255, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::BeginChild(
"RemoteDesktopWindow_1",
ImVec2(remote_child_window_width_, remote_child_window_height_),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar();
ImGui::PopStyleColor();
{
ImGui::SetWindowFontScale(0.8f);
ImGui::Text(
"%s", localization::remote_id[localization_language_index_].c_str());
ImGui::Spacing();
ImGui::SetNextItemWidth(IPUT_WINDOW_WIDTH);
ImGui::SetWindowFontScale(1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
if (re_enter_remote_id_) {
ImGui::SetKeyboardFocusHere();
re_enter_remote_id_ = false;
memset(remote_id_display_, 0, sizeof(remote_id_display_));
}
bool enter_pressed = ImGui::InputText(
"##remote_id_", remote_id_display_, IM_ARRAYSIZE(remote_id_display_),
ImGuiInputTextFlags_CharsDecimal |
ImGuiInputTextFlags_EnterReturnsTrue |
ImGuiInputTextFlags_CallbackEdit,
InputTextCallback);
ImGui::PopStyleVar();
ImGui::SameLine();
if (ImGui::Button(ICON_FA_ARROW_RIGHT_LONG, ImVec2(55, 38)) ||
enter_pressed) {
connect_button_pressed_ = true;
remote_id_ = remote_id_display_;
remote_id_.erase(remove_if(remote_id_.begin(), remote_id_.end(),
static_cast<int (*)(int)>(&isspace)),
remote_id_.end());
ConnectTo();
}
if (rejoin_) {
ConnectTo();
}
}
ImGui::EndChild();
}
ImGui::EndChild();
ImGui::PopStyleVar();
return 0;
}
static int InputTextCallback(ImGuiInputTextCallbackData *data) {
if (data->BufTextLen > 3 && data->Buf[3] != ' ') {
data->InsertChars(3, " ");
@@ -16,68 +102,11 @@ static int InputTextCallback(ImGuiInputTextCallbackData *data) {
return 0;
}
int Render::RemoteWindow() {
ImGui::SetNextWindowPos(ImVec2(local_window_width_ - 1, title_bar_height_),
ImGuiCond_Always);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::BeginChild("RemoteDesktopWindow",
ImVec2(main_window_width_ - local_window_width_ + 1,
main_window_height_default_ - title_bar_height_ -
status_bar_height_),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleColor();
ImGui::SetWindowFontScale(1.0f);
ImGui::Text(
"%s", localization::remote_desktop[localization_language_index_].c_str());
ImGui::Spacing();
ImGui::PushStyleColor(ImGuiCol_ChildBg,
ImVec4(239.0 / 255, 240.0 / 255, 242.0 / 255, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
ImGui::BeginChild("RemoteDesktopWindow_1", ImVec2(330, 180),
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleVar();
ImGui::PopStyleColor();
{
ImGui::SetWindowFontScale(0.5f);
ImGui::Text("%s",
localization::remote_id[localization_language_index_].c_str());
ImGui::Spacing();
ImGui::SetNextItemWidth(IPUT_WINDOW_WIDTH);
ImGui::SetWindowFontScale(1.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
bool enter_pressed = ImGui::InputText(
"##remote_id_", remote_id_display_, IM_ARRAYSIZE(remote_id_display_),
ImGuiInputTextFlags_CharsUppercase |
ImGuiInputTextFlags_EnterReturnsTrue |
ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CharsNoBlank,
InputTextCallback);
ImGui::PopStyleVar();
ImGui::SameLine();
if (ImGui::Button(ICON_FA_ARROW_RIGHT_LONG, ImVec2(55, 38)) ||
enter_pressed || rejoin_) {
connect_button_pressed_ = true;
int Render::ConnectTo() {
connection_status_ = ConnectionStatus::Connecting;
int ret = -1;
if (signal_connected_) {
if (!connection_established_) {
remote_id_ = remote_id_display_;
remote_id_.erase(remove_if(remote_id_.begin(), remote_id_.end(),
static_cast<int (*)(int)>(&isspace)),
remote_id_.end());
if (0 == strcmp(remote_id_.c_str(), client_id_) && !peer_reserved_) {
peer_reserved_ = CreatePeer(&params_);
if (peer_reserved_) {
@@ -90,6 +119,7 @@ int Render::RemoteWindow() {
LOG_INFO("Create peer[reserved] instance failed");
}
}
ret = JoinConnection(peer_reserved_ ? peer_reserved_ : peer_,
remote_id_.c_str(), remote_password_);
if (0 == ret) {
@@ -100,11 +130,6 @@ int Render::RemoteWindow() {
}
}
}
}
}
ImGui::EndChild();
ImGui::EndChild();
ImGui::PopStyleVar();
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,11 @@
#include <atomic>
#include <chrono>
#include <fstream>
#include <string>
#include "../../thirdparty/projectx/src/interface/x.h"
#include "IconsFontAwesome6.h"
#include "config_center.h"
#include "device_controller_factory.h"
#include "imgui.h"
@@ -21,6 +23,7 @@
#include "imgui_impl_sdlrenderer2.h"
#include "screen_capturer_factory.h"
#include "speaker_capturer_factory.h"
#include "thumbnail.h"
class Render {
public:
@@ -32,16 +35,37 @@ class Render {
private:
int CreateStreamRenderWindow();
int TitleBar();
int TitleBar(bool main_window);
int MainWindow();
int StreamWindow();
int LocalWindow();
int RemoteWindow();
int RecentConnectionsWindow();
int SettingWindow();
int ControlWindow();
int ControlBar();
int AboutWindow();
int StatusBar();
int ConnectionStatusWindow();
int LoadRecentConnections();
int ShowRecentConnections();
private:
int CreateRtcConnection();
int ConnectTo();
int CreateMainWindow();
int DestroyMainWindow();
int CreateStreamWindow();
int DestroyStreamWindow();
int SetupFontAndStyle();
int SetupMainWindow();
int DestroyMainWindowContext();
int SetupStreamWindow();
int DestroyStreamWindowContext();
int DrawMainWindow();
int DrawStreamWindow();
int ConfirmDeleteConnection();
int NetTrafficStats();
public:
static void OnReceiveVideoBufferCb(const XVideoFrame *video_frame,
@@ -62,14 +86,19 @@ class Render {
size_t user_id_size, void *user_data);
static void NetStatusReport(const char *client_id, size_t client_id_size,
TraversalMode mode, const unsigned short send,
const unsigned short receive, void *user_data);
TraversalMode mode,
const XNetTrafficStats *net_traffic_stats,
void *user_data);
static SDL_HitTestResult HitTestCallback(SDL_Window *window,
const SDL_Point *area, void *data);
private:
int ProcessMouseKeyEven(SDL_Event &ev);
int ProcessMouseKeyEvent(SDL_Event &event);
int ProcessMouseEvent(SDL_Event &event);
int SendKeyEvent(int key_code, bool is_down);
int ProcessKeyEvent(int key_code, bool is_down);
static void SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len);
static void SdlCaptureAudioOut(void *userdata, Uint8 *stream, int len);
@@ -78,14 +107,17 @@ class Render {
int SaveSettingsIntoCacheFile();
int LoadSettingsFromCacheFile();
int StartScreenCapture();
int StopScreenCapture();
int StartScreenCapturer();
int StopScreenCapturer();
int StartSpeakerCapture();
int StopSpeakerCapture();
int StartSpeakerCapturer();
int StopSpeakerCapturer();
int StartMouseControl();
int StopMouseControl();
int StartMouseController();
int StopMouseController();
int StartKeyboardCapturer();
int StopKeyboardCapturer();
int CreateConnectionPeer();
@@ -100,15 +132,17 @@ class Render {
int video_quality;
int video_encode_format;
bool enable_hardware_video_codec;
bool enable_turn;
unsigned char key[16];
unsigned char iv[16];
} CDCache;
private:
FILE *cd_cache_file_ = nullptr;
CDCache cd_cache_;
std::mutex cd_cache_mutex_;
ConfigCenter config_center_;
ConfigCenter::LANGUAGE localization_language_ =
ConfigCenter::LANGUAGE::CHINESE;
@@ -122,6 +156,7 @@ class Render {
std::string mac_addr_str_ = "";
std::string connect_button_label_ = "Connect";
std::string fullscreen_button_label_ = "Fullscreen";
std::string net_traffic_stats_button_label_ = "Show Net Traffic Stats";
std::string mouse_control_button_label_ = "Mouse Control";
std::string audio_capture_button_label_ = "Audio Capture";
std::string settings_button_label_ = "Setting";
@@ -135,77 +170,120 @@ class Render {
char client_password_[20] = "";
private:
int title_bar_width_ = 960;
int title_bar_height_ = 30;
float title_bar_width_ = 640;
float title_bar_height_ = 30;
int screen_width_ = 1280;
int screen_height_ = 720;
int main_window_width_default_ = 960;
int main_window_height_default_ = 570;
int main_window_width_ = 960;
int main_window_height_ = 570;
int main_window_width_last_ = 960;
int main_window_height_last_ = 540;
int stream_window_width_ = 1280;
int stream_window_height_ = 720;
float main_window_width_default_ = 640;
float main_window_height_default_ = 480;
float main_window_width_ = 640;
float main_window_height_ = 480;
float main_window_width_last_ = 640;
float main_window_height_last_ = 480;
int stream_window_width_default_ = 1280;
int stream_window_height_default_ = 720;
float stream_window_width_ = 1280;
float stream_window_height_ = 720;
int stream_window_width_last_ = 1280;
int stream_window_height_last_ = 720;
int main_window_width_before_maximized_ = 960;
int main_window_height_before_maximized_ = 570;
int control_window_min_width_ = 20;
int control_window_max_width_ = 170;
int control_window_width_ = 170;
int control_window_height_ = 40;
int local_window_width_ = 350;
int status_bar_height_ = 20;
int connection_status_window_width_ = 200;
int connection_status_window_height_ = 150;
int notification_window_width_ = 200;
int notification_window_height_ = 80;
int about_window_width_ = 200;
int about_window_height_ = 150;
float stream_window_width_before_maximized_ = 1280;
float stream_window_height_before_maximized_ = 720;
float control_window_min_width_ = 20;
float control_window_max_width_ = 200;
float control_window_min_height_ = 40;
float control_window_max_height_ = 150;
float control_window_width_ = 200;
float control_window_height_ = 40;
float local_window_width_ = 320;
float local_window_height_ = 235;
float remote_window_width_ = 320;
float remote_window_height_ = 235;
float local_child_window_width_ = 266;
float local_child_window_height_ = 180;
float remote_child_window_width_ = 266;
float remote_child_window_height_ = 180;
float main_window_text_y_padding_ = 10;
float main_child_window_x_padding_ = 27;
float main_child_window_y_padding_ = 45;
float status_bar_height_ = 22;
float connection_status_window_width_ = 200;
float connection_status_window_height_ = 150;
float notification_window_width_ = 200;
float notification_window_height_ = 80;
float about_window_width_ = 200;
float about_window_height_ = 150;
int control_bar_pos_x_ = 0;
int control_bar_pos_y_ = 30;
float control_bar_pos_x_ = 0;
float control_bar_pos_y_ = 30;
float mouse_diff_control_bar_pos_x_ = 0;
float mouse_diff_control_bar_pos_y_ = 0;
int mouse_pos_x_ = 0;
int mouse_pos_y_ = 0;
int mouse_pos_x_last_ = 0;
int mouse_pos_y_last_ = 0;
int main_window_width_real_ = 960;
int main_window_width_real_ = 720;
int main_window_height_real_ = 540;
float dpi_scaling_w_ = 1.0f;
float dpi_scaling_h_ = 1.0f;
float main_window_dpi_scaling_w_ = 1.0f;
float main_window_dpi_scaling_h_ = 1.0f;
int stream_window_width_real_ = 1280;
int stream_window_height_real_ = 720;
float stream_window_dpi_scaling_w_ = 1.0f;
float stream_window_dpi_scaling_h_ = 1.0f;
int texture_width_ = 1280;
int texture_height_ = 720;
int video_width_ = 1280;
int video_height_ = 720;
int video_size_ = 1280 * 720 * 3;
size_t video_size_ = 1280 * 720 * 3;
SDL_Window *main_window_;
SDL_Window *main_window_ = nullptr;
SDL_Renderer *main_renderer_ = nullptr;
ImGuiContext *main_ctx_ = nullptr;
SDL_Window *stream_window_ = nullptr;
SDL_Renderer *stream_renderer_ = nullptr;
ImGuiContext *stream_ctx_ = nullptr;
bool stream_window_created_ = false;
bool stream_window_inited_ = false;
// recent connections
std::map<std::string, SDL_Texture *> recent_connection_textures_;
int recent_connection_image_width_ = 160;
int recent_connection_image_height_ = 90;
uint32_t recent_connection_image_save_time_ = 0;
// video window
SDL_Texture *stream_texture_ = nullptr;
SDL_Rect stream_render_rect_;
SDL_Rect stream_render_rect_last_;
uint32_t stream_pixformat_ = 0;
std::string host_name_ = "";
unsigned char aes128_key_[16];
unsigned char aes128_iv_[16];
std::unique_ptr<Thumbnail> thumbnail_;
bool resizable_ = false;
bool label_inited_ = false;
bool exit_ = false;
bool exit_video_window_ = false;
bool connection_established_ = false;
bool control_bar_hovered_ = false;
bool connect_button_pressed_ = false;
bool password_validating_ = false;
uint32_t password_validating_time_ = 0;
bool control_bar_expand_ = true;
bool fullscreen_button_pressed_ = false;
bool net_traffic_stats_button_pressed_ = false;
bool mouse_control_button_pressed_ = false;
bool audio_capture_button_pressed_ = false;
bool show_settings_window_ = false;
bool received_frame_ = false;
bool is_create_connection_ = false;
bool audio_buffer_fresh_ = false;
bool rejoin_ = false;
bool control_mouse_ = false;
bool stream_window_grabbed_ = false;
bool audio_capture_ = true;
bool local_id_copied_ = false;
bool show_password_ = true;
@@ -219,11 +297,23 @@ class Render {
bool streaming_ = false;
bool is_client_mode_ = false;
bool is_control_bar_in_left_ = true;
bool is_control_bar_in_top_ = true;
bool control_bar_hovered_ = false;
bool control_bar_expand_ = true;
bool reset_control_bar_pos_ = false;
bool control_window_width_is_changing_ = false;
bool control_window_height_is_changing_ = false;
bool reload_recent_connections_ = true;
bool hostname_sent_ = false;
bool show_confirm_delete_connection_ = false;
bool delete_connection_ = false;
bool remember_password_ = false;
bool re_enter_remote_id_ = false;
double copy_start_time_ = 0;
double regenerate_password_start_time_ = 0;
double control_bar_button_pressed_time_ = 0;
double net_traffic_stats_button_pressed_time_ = 0;
ImVec2 control_winodw_pos_;
@@ -245,14 +335,16 @@ class Render {
PeerPtr *peer_ = nullptr;
PeerPtr *peer_reserved_ = nullptr;
Params params_;
TraversalMode traversal_mode_ = TraversalMode::UnknownMode;
XNetTrafficStats net_traffic_stats_;
private:
SDL_AudioDeviceID input_dev_;
SDL_AudioDeviceID output_dev_;
unsigned char audio_buffer_[960];
unsigned char audio_buffer_[720];
int audio_len_ = 0;
unsigned char *dst_buffer_ = nullptr;
int dst_buffer_capacity_ = 0;
size_t dst_buffer_capacity_ = 0;
private:
ScreenCapturerFactory *screen_capturer_factory_ = nullptr;
@@ -261,10 +353,12 @@ class Render {
SpeakerCapturer *speaker_capturer_ = nullptr;
DeviceControllerFactory *device_controller_factory_ = nullptr;
MouseController *mouse_controller_ = nullptr;
uint32_t last_frame_time_;
KeyboardCapturer *keyboard_capturer_ = nullptr;
uint64_t last_frame_time_;
private:
char client_id_[10] = "";
char client_id_display_[12] = "";
char password_saved_[7] = "";
int language_button_value_ = 0;
int video_quality_button_value_ = 0;
@@ -279,10 +373,12 @@ class Render {
bool enable_turn_last_ = false;
private:
std::atomic<bool> start_screen_capture_{false};
std::atomic<bool> start_mouse_control_{false};
std::atomic<bool> screen_capture_is_started_{false};
std::atomic<bool> mouse_control_is_started_{false};
std::atomic<bool> start_screen_capturer_{false};
std::atomic<bool> start_mouse_controller_{false};
std::atomic<bool> start_keyboard_capturer_{false};
std::atomic<bool> screen_capturer_is_started_{false};
std::atomic<bool> mouse_controller_is_started_{false};
std::atomic<bool> keyboard_capturer_is_started_{false};
private:
bool settings_window_pos_reset_ = true;

View File

@@ -1,5 +1,6 @@
#include "device_controller.h"
#include "localization.h"
#include "platform.h"
#include "rd_log.h"
#include "render.h"
@@ -12,86 +13,94 @@
#define MOUSE_CONTROL 1
#endif
int Render::ProcessMouseKeyEven(SDL_Event &ev) {
int Render::ProcessMouseKeyEvent(SDL_Event &event) {
if (!control_mouse_ || !connection_established_) {
return 0;
}
if (SDL_KEYDOWN == event.type || SDL_KEYUP == event.type) {
} else {
ProcessMouseEvent(event);
}
return 0;
}
int Render::ProcessMouseEvent(SDL_Event &event) {
float ratio_x = (float)video_width_ / (float)stream_render_rect_.w;
float ratio_y = (float)video_height_ / (float)stream_render_rect_.h;
if (ev.button.x <= stream_render_rect_.x) {
ev.button.x = 0;
} else if (ev.button.x > stream_render_rect_.x &&
ev.button.x < stream_render_rect_.x + stream_render_rect_.w) {
ev.button.x -= stream_render_rect_.x;
} else if (ev.button.x >= stream_render_rect_.x + stream_render_rect_.w) {
ev.button.x = stream_render_rect_.w;
if (event.button.x <= stream_render_rect_.x) {
event.button.x = 0;
} else if (event.button.x > stream_render_rect_.x &&
event.button.x < stream_render_rect_.x + stream_render_rect_.w) {
event.button.x -= stream_render_rect_.x;
} else if (event.button.x >= stream_render_rect_.x + stream_render_rect_.w) {
event.button.x = stream_render_rect_.w;
}
if (ev.button.y <= stream_render_rect_.y) {
ev.button.y = 0;
} else if (ev.button.y > stream_render_rect_.y &&
ev.button.y < stream_render_rect_.y + stream_render_rect_.h) {
ev.button.y -= stream_render_rect_.y;
} else if (ev.button.y >= stream_render_rect_.y + stream_render_rect_.h) {
ev.button.y = stream_render_rect_.h;
if (event.button.y <= stream_render_rect_.y) {
event.button.y = 0;
} else if (event.button.y > stream_render_rect_.y &&
event.button.y < stream_render_rect_.y + stream_render_rect_.h) {
event.button.y -= stream_render_rect_.y;
} else if (event.button.y >= stream_render_rect_.y + stream_render_rect_.h) {
event.button.y = stream_render_rect_.h;
}
RemoteAction remote_action;
remote_action.m.x = (size_t)(ev.button.x * ratio_x);
remote_action.m.y = (size_t)(ev.button.y * ratio_y);
remote_action.m.x = (size_t)(event.button.x * ratio_x);
remote_action.m.y = (size_t)(event.button.y * ratio_y);
if (SDL_KEYDOWN == ev.type) // SDL_KEYUP
{
// printf("SDLK_DOWN: %d\n", SDL_KeyCode(ev.key.keysym.sym));
if (SDLK_DOWN == ev.key.keysym.sym) {
// printf("SDLK_DOWN \n");
} else if (SDLK_UP == ev.key.keysym.sym) {
// printf("SDLK_UP \n");
} else if (SDLK_LEFT == ev.key.keysym.sym) {
// printf("SDLK_LEFT \n");
} else if (SDLK_RIGHT == ev.key.keysym.sym) {
// printf("SDLK_RIGHT \n");
}
} else if (SDL_MOUSEBUTTONDOWN == ev.type) {
if (SDL_MOUSEBUTTONDOWN == event.type) {
remote_action.type = ControlType::mouse;
if (SDL_BUTTON_LEFT == ev.button.button) {
if (SDL_BUTTON_LEFT == event.button.button) {
remote_action.m.flag = MouseFlag::left_down;
} else if (SDL_BUTTON_RIGHT == ev.button.button) {
} else if (SDL_BUTTON_RIGHT == event.button.button) {
remote_action.m.flag = MouseFlag::right_down;
}
if (control_bar_hovered_) {
remote_action.m.flag = MouseFlag::move;
}
SendData(peer_, DATA_TYPE::DATA, (const char *)&remote_action,
sizeof(remote_action));
} else if (SDL_MOUSEBUTTONUP == ev.type) {
SendDataFrame(peer_, (const char *)&remote_action, sizeof(remote_action));
} else if (SDL_MOUSEBUTTONUP == event.type) {
remote_action.type = ControlType::mouse;
if (SDL_BUTTON_LEFT == ev.button.button) {
if (SDL_BUTTON_LEFT == event.button.button) {
remote_action.m.flag = MouseFlag::left_up;
} else if (SDL_BUTTON_RIGHT == ev.button.button) {
} else if (SDL_BUTTON_RIGHT == event.button.button) {
remote_action.m.flag = MouseFlag::right_up;
}
if (control_bar_hovered_) {
remote_action.m.flag = MouseFlag::move;
}
SendData(peer_, DATA_TYPE::DATA, (const char *)&remote_action,
sizeof(remote_action));
} else if (SDL_MOUSEMOTION == ev.type) {
SendDataFrame(peer_, (const char *)&remote_action, sizeof(remote_action));
} else if (SDL_MOUSEMOTION == event.type) {
remote_action.type = ControlType::mouse;
remote_action.m.flag = MouseFlag::move;
SendData(peer_, DATA_TYPE::DATA, (const char *)&remote_action,
sizeof(remote_action));
} else if (SDL_QUIT == ev.type) {
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
printf("SDL_QUIT\n");
SendDataFrame(peer_, (const char *)&remote_action, sizeof(remote_action));
}
return 0;
}
int Render::SendKeyEvent(int key_code, bool is_down) {
RemoteAction remote_action;
remote_action.type = ControlType::keyboard;
if (is_down) {
remote_action.k.flag = KeyFlag::key_down;
} else {
remote_action.k.flag = KeyFlag::key_up;
}
remote_action.k.key_value = key_code;
SendDataFrame(peer_, (const char *)&remote_action, sizeof(remote_action));
return 0;
}
int Render::ProcessKeyEvent(int key_code, bool is_down) {
if (keyboard_capturer_) {
keyboard_capturer_->SendKeyboardCommand(key_code, is_down);
}
return 0;
@@ -105,7 +114,7 @@ void Render::SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) {
if (1) {
if ("Connected" == render->connection_status_str_) {
SendData(render->peer_, DATA_TYPE::AUDIO, (const char *)stream, len);
SendAudioFrame(render->peer_, (const char *)stream, len);
}
} else {
memcpy(render->audio_buffer_, stream, len);
@@ -115,10 +124,12 @@ void Render::SdlCaptureAudioIn(void *userdata, Uint8 *stream, int len) {
}
}
void Render::SdlCaptureAudioOut(void *userdata, Uint8 *stream, int len) {
void Render::SdlCaptureAudioOut([[maybe_unused]] void *userdata,
[[maybe_unused]] Uint8 *stream,
[[maybe_unused]] int len) {
// Render *render = (Render *)userdata;
// if ("Connected" == render->connection_status_str_) {
// SendData(render->peer_, DATA_TYPE::AUDIO, (const char *)stream, len);
// SendAudioFrame(render->peer_, (const char *)stream, len);
// }
// if (!render->audio_buffer_fresh_) {
@@ -139,7 +150,8 @@ void Render::SdlCaptureAudioOut(void *userdata, Uint8 *stream, int len) {
}
void Render::OnReceiveVideoBufferCb(const XVideoFrame *video_frame,
const char *user_id, size_t user_id_size,
[[maybe_unused]] const char *user_id,
[[maybe_unused]] size_t user_id_size,
void *user_data) {
Render *render = (Render *)user_data;
if (!render) {
@@ -150,11 +162,6 @@ void Render::OnReceiveVideoBufferCb(const XVideoFrame *video_frame,
if (!render->dst_buffer_) {
render->dst_buffer_capacity_ = video_frame->size;
render->dst_buffer_ = new unsigned char[video_frame->size];
// Adapt stream_render_rect_ to the video resolution
SDL_Event event;
event.type = SDL_WINDOWEVENT;
event.window.event = SDL_WINDOWEVENT_SIZE_CHANGED;
SDL_PushEvent(&event);
}
if (render->dst_buffer_capacity_ < video_frame->size) {
@@ -171,13 +178,13 @@ void Render::OnReceiveVideoBufferCb(const XVideoFrame *video_frame,
SDL_Event event;
event.type = REFRESH_EVENT;
SDL_PushEvent(&event);
render->received_frame_ = true;
render->streaming_ = true;
}
}
void Render::OnReceiveAudioBufferCb(const char *data, size_t size,
const char *user_id, size_t user_id_size,
[[maybe_unused]] const char *user_id,
[[maybe_unused]] size_t user_id_size,
void *user_data) {
Render *render = (Render *)user_data;
if (!render) {
@@ -198,16 +205,23 @@ void Render::OnReceiveDataBufferCb(const char *data, size_t size,
std::string user(user_id, user_id_size);
RemoteAction remote_action;
memcpy(&remote_action, data, sizeof(remote_action));
memcpy(&remote_action, data, size);
if (ControlType::mouse == remote_action.type && render->mouse_controller_) {
render->mouse_controller_->SendCommand(remote_action);
} else if (ControlType::audio_capture == remote_action.type) {
if (remote_action.a) {
render->StartSpeakerCapture();
render->StartSpeakerCapturer();
} else {
render->StopSpeakerCapture();
render->StopSpeakerCapturer();
}
} else if (ControlType::keyboard == remote_action.type) {
render->ProcessKeyEvent((int)remote_action.k.key_value,
remote_action.k.flag == KeyFlag::key_down);
} else if (ControlType::host_infomation == remote_action.type) {
render->host_name_ =
std::string(remote_action.i.host_name, remote_action.i.host_name_size);
LOG_INFO("Remote hostname: [{}]", render->host_name_);
}
}
@@ -240,8 +254,10 @@ void Render::OnSignalStatusCb(SignalStatus status, void *user_data) {
}
}
void Render::OnConnectionStatusCb(ConnectionStatus status, const char *user_id,
const size_t user_id_size, void *user_data) {
void Render::OnConnectionStatusCb(ConnectionStatus status,
[[maybe_unused]] const char *user_id,
[[maybe_unused]] const size_t user_id_size,
void *user_data) {
Render *render = (Render *)user_data;
if (!render) {
return;
@@ -257,8 +273,21 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char *user_id,
render->connection_status_str_ = "Connected";
render->connection_established_ = true;
if (render->peer_reserved_ || !render->is_client_mode_) {
render->start_screen_capture_ = true;
render->start_mouse_control_ = true;
render->start_screen_capturer_ = true;
render->start_mouse_controller_ = true;
}
if (!render->hostname_sent_) {
// TODO: self and remote hostname
std::string host_name = GetHostName();
RemoteAction remote_action;
remote_action.type = ControlType::host_infomation;
memcpy(&remote_action.i.host_name, host_name.data(), host_name.size());
remote_action.i.host_name_size = host_name.size();
int ret = SendDataFrame(render->peer_, (const char *)&remote_action,
sizeof(remote_action));
if (0 == ret) {
render->hostname_sent_ = true;
}
}
} else if (ConnectionStatus::Disconnected == status) {
render->connection_status_str_ = "Disconnected";
@@ -269,12 +298,15 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char *user_id,
} else if (ConnectionStatus::Closed == status) {
render->connection_status_str_ = "Closed";
render->password_validating_time_ = 0;
render->start_screen_capture_ = false;
render->start_mouse_control_ = false;
render->start_screen_capturer_ = false;
render->start_mouse_controller_ = false;
render->connection_established_ = false;
render->control_mouse_ = false;
render->mouse_control_button_pressed_ = false;
render->start_keyboard_capturer_ = false;
render->hostname_sent_ = false;
if (render->audio_capture_) {
render->StopSpeakerCapture();
render->StopSpeakerCapturer();
render->audio_capture_ = false;
render->audio_capture_button_pressed_ = false;
}
@@ -311,8 +343,9 @@ void Render::OnConnectionStatusCb(ConnectionStatus status, const char *user_id,
}
void Render::NetStatusReport(const char *client_id, size_t client_id_size,
TraversalMode mode, const unsigned short send,
const unsigned short receive, void *user_data) {
TraversalMode mode,
const XNetTrafficStats *net_traffic_stats,
void *user_data) {
Render *render = (Render *)user_data;
if (!render) {
return;
@@ -320,11 +353,21 @@ void Render::NetStatusReport(const char *client_id, size_t client_id_size,
if (0 == strcmp(render->client_id_, "")) {
memset(&render->client_id_, 0, sizeof(render->client_id_));
strncpy(render->client_id_, client_id, client_id_size);
memcpy(render->client_id_, client_id, client_id_size);
LOG_INFO("Use client id [{}] and save id into cache file", client_id);
render->SaveSettingsIntoCacheFile();
}
if (mode != TraversalMode::UnknownMode) {
LOG_INFO("Net mode: [{}]", int(mode));
if (render->traversal_mode_ != mode) {
render->traversal_mode_ = mode;
LOG_INFO("Net mode: [{}]", int(render->traversal_mode_));
}
if (!net_traffic_stats) {
return;
}
// only display client side net status if connected to itself
if (!(render->peer_reserved_ && !strstr(client_id, "C-"))) {
render->net_traffic_stats_ = *net_traffic_stats;
}
}

View File

@@ -1,4 +1,3 @@
#include "IconsFontAwesome6.h"
#include "layout_style.h"
#include "localization.h"
#include "rd_log.h"
@@ -71,6 +70,10 @@ int Render::SettingWindow() {
ImGui::Separator();
if (streaming_) {
ImGui::BeginDisabled();
}
{
const char *video_quality_items[] = {
localization::video_quality_high[localization_language_index_]
@@ -158,6 +161,10 @@ int Render::SettingWindow() {
ImGui::Checkbox("##enable_turn", &enable_turn_);
}
if (streaming_) {
ImGui::EndDisabled();
}
if (ConfigCenter::LANGUAGE::CHINESE == localization_language_) {
ImGui::SetCursorPosX(SETTINGS_OK_BUTTON_PADDING_CN);
} else {
@@ -227,7 +234,7 @@ int Render::SettingWindow() {
LoadSettingsFromCacheFile();
// Recreate peer instance
{
if (!streaming_) {
LOG_INFO("Recreate peer instance");
DestroyPeer(&peer_);
is_create_connection_ = false;

View File

@@ -13,17 +13,16 @@ int Render::StatusBar() {
ImGuiChildFlags_Border,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoBringToFrontOnFocus);
ImVec2 dot_pos =
ImVec2(13, main_window_height_default_ - status_bar_height_ + 11.0f);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddCircleFilled(
ImVec2(15, main_window_height_default_ - status_bar_height_ + 9.0f), 5,
ImColor(signal_connected_ ? 0.0f : 1.0f, signal_connected_ ? 1.0f : 0.0f,
0.0f),
draw_list->AddCircleFilled(dot_pos, 5.0f,
ImColor(signal_connected_ ? 0.0f : 1.0f,
signal_connected_ ? 1.0f : 0.0f, 0.0f),
100);
draw_list->AddCircle(
ImVec2(15, main_window_height_default_ - status_bar_height_ + 10.0f), 6,
ImColor(1.0f, 1.0f, 1.0f), 100);
draw_list->AddCircle(dot_pos, 6.0f, ImColor(1.0f, 1.0f, 1.0f), 100);
ImGui::SetWindowFontScale(0.5f);
ImGui::SetWindowFontScale(0.6f);
draw_list->AddText(
ImVec2(25, main_window_height_default_ - status_bar_height_ + 3.0f),
ImColor(0.0f, 0.0f, 0.0f),

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
#include "localization.h"
#include "rd_log.h"
#include "render.h"
int Render::StreamWindow() {
ImGui::SetNextWindowPos(
ImVec2(0, fullscreen_button_pressed_ ? 0 : title_bar_height_),
ImGuiCond_Always);
ImGui::SetNextWindowSize(
ImVec2(stream_window_width_, stream_window_height_ - title_bar_height_),
ImGuiCond_Always);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1, 1, 1, 0));
ImGui::PushStyleColor(ImGuiCol_Border,
ImVec4(178 / 255.0f, 178 / 255.0f, 178 / 255.0f,
fullscreen_button_pressed_ ? 0 : 1.0f));
ImGui::Begin("VideoBg", nullptr,
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImGui::PopStyleColor(2);
ControlWindow();
ImGui::End();
return 0;
}

View File

@@ -0,0 +1,363 @@
#include "thumbnail.h"
#include <openssl/aes.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <chrono>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "libyuv.h"
#include "rd_log.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
static std::string test;
void ScaleYUV420pToABGR(char* dst_buffer_, int video_width_, int video_height_,
int scaled_video_width_, int scaled_video_height_,
char* rgba_buffer_) {
int src_y_size = video_width_ * video_height_;
int src_uv_size = (video_width_ + 1) / 2 * (video_height_ + 1) / 2;
int dst_y_size = scaled_video_width_ * scaled_video_height_;
int dst_uv_size =
(scaled_video_width_ + 1) / 2 * (scaled_video_height_ + 1) / 2;
uint8_t* src_y = reinterpret_cast<uint8_t*>(dst_buffer_);
uint8_t* src_u = src_y + src_y_size;
uint8_t* src_v = src_u + src_uv_size;
std::unique_ptr<uint8_t[]> dst_y(new uint8_t[dst_y_size]);
std::unique_ptr<uint8_t[]> dst_u(new uint8_t[dst_uv_size]);
std::unique_ptr<uint8_t[]> dst_v(new uint8_t[dst_uv_size]);
libyuv::I420Scale(src_y, video_width_, src_u, (video_width_ + 1) / 2, src_v,
(video_width_ + 1) / 2, video_width_, video_height_,
dst_y.get(), scaled_video_width_, dst_u.get(),
(scaled_video_width_ + 1) / 2, dst_v.get(),
(scaled_video_width_ + 1) / 2, scaled_video_width_,
scaled_video_height_, libyuv::kFilterBilinear);
libyuv::I420ToABGR(
dst_y.get(), scaled_video_width_, dst_u.get(),
(scaled_video_width_ + 1) / 2, dst_v.get(), (scaled_video_width_ + 1) / 2,
reinterpret_cast<uint8_t*>(rgba_buffer_), scaled_video_width_ * 4,
scaled_video_width_, scaled_video_height_);
}
Thumbnail::Thumbnail() {
RAND_bytes(aes128_key_, sizeof(aes128_key_));
RAND_bytes(aes128_iv_, sizeof(aes128_iv_));
std::filesystem::create_directory(image_path_);
}
Thumbnail::Thumbnail(unsigned char* aes128_key, unsigned char* aes128_iv) {
memcpy(aes128_key_, aes128_key, sizeof(aes128_key_));
memcpy(aes128_iv_, aes128_iv, sizeof(aes128_iv_));
std::filesystem::create_directory(image_path_);
}
Thumbnail::~Thumbnail() {
if (rgba_buffer_) {
delete[] rgba_buffer_;
rgba_buffer_ = nullptr;
}
}
int Thumbnail::SaveToThumbnail(const char* yuv420p, int width, int height,
const std::string& remote_id,
const std::string& host_name,
const std::string& password) {
if (!rgba_buffer_) {
rgba_buffer_ = new char[thumbnail_width_ * thumbnail_height_ * 4];
}
if (yuv420p) {
ScaleYUV420pToABGR((char*)yuv420p, width, height, thumbnail_width_,
thumbnail_height_, rgba_buffer_);
std::string image_name;
if (password.empty()) {
image_name = remote_id + 'N' + host_name;
} else {
// delete the file which has no password in its name
std::string filename_without_password = remote_id + "N" + host_name;
DeleteThumbnail(filename_without_password);
image_name = remote_id + 'Y' + password + host_name;
}
std::string ciphertext = AES_encrypt(image_name, aes128_key_, aes128_iv_);
std::string file_path = image_path_ + ciphertext;
stbi_write_png(file_path.data(), thumbnail_width_, thumbnail_height_, 4,
rgba_buffer_, thumbnail_width_ * 4);
}
return 0;
}
bool LoadTextureFromMemory(const void* data, size_t data_size,
SDL_Renderer* renderer, SDL_Texture** out_texture,
int* out_width, int* out_height) {
int image_width = 0;
int image_height = 0;
int channels = 4;
unsigned char* image_data =
stbi_load_from_memory((const unsigned char*)data, (int)data_size,
&image_width, &image_height, NULL, 4);
if (image_data == nullptr) {
LOG_ERROR("Failed to load image: [{}]", stbi_failure_reason());
return false;
}
// ABGR
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(
(void*)image_data, image_width, image_height, channels * 8,
channels * image_width, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
if (surface == nullptr) {
LOG_ERROR("Failed to create SDL surface: [{}]", SDL_GetError());
return false;
}
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
if (texture == nullptr) {
LOG_ERROR("Failed to create SDL texture: [{}]", SDL_GetError());
}
*out_texture = texture;
*out_width = image_width;
*out_height = image_height;
SDL_FreeSurface(surface);
stbi_image_free(image_data);
return true;
}
bool LoadTextureFromFile(const char* file_name, SDL_Renderer* renderer,
SDL_Texture** out_texture, int* out_width,
int* out_height) {
std::filesystem::path file_path(file_name);
if (!std::filesystem::exists(file_path)) return false;
std::ifstream file(file_path, std::ios::binary);
if (!file) return false;
file.seekg(0, std::ios::end);
size_t file_size = file.tellg();
file.seekg(0, std::ios::beg);
if (file_size == -1) return false;
char* file_data = new char[file_size];
if (!file_data) return false;
file.read(file_data, file_size);
bool ret = LoadTextureFromMemory(file_data, file_size, renderer, out_texture,
out_width, out_height);
delete[] file_data;
return ret;
}
std::vector<std::filesystem::path> Thumbnail::FindThumbnailPath(
const std::filesystem::path& directory) {
std::vector<std::filesystem::path> thumbnails_path;
if (!std::filesystem::is_directory(directory)) {
LOG_ERROR("No such directory [{}]", directory.string());
return thumbnails_path;
}
thumbnails_sorted_by_write_time_.clear();
for (const auto& entry : std::filesystem::directory_iterator(directory)) {
if (entry.is_regular_file()) {
std::time_t last_write_time = std::chrono::system_clock::to_time_t(
time_point_cast<std::chrono::system_clock::duration>(
entry.last_write_time() -
std::filesystem::file_time_type::clock::now() +
std::chrono::system_clock::now()));
thumbnails_sorted_by_write_time_[last_write_time] = entry.path();
}
}
for (auto it = thumbnails_sorted_by_write_time_.rbegin();
it != thumbnails_sorted_by_write_time_.rend(); ++it) {
thumbnails_path.push_back(it->second);
}
return thumbnails_path;
}
int Thumbnail::LoadThumbnail(SDL_Renderer* renderer,
std::map<std::string, SDL_Texture*>& textures,
int* width, int* height) {
for (auto& it : textures) {
if (it.second != nullptr) {
SDL_DestroyTexture(it.second);
it.second = nullptr;
}
}
textures.clear();
std::vector<std::filesystem::path> image_paths =
FindThumbnailPath(image_path_);
if (image_paths.size() == 0) {
return -1;
} else {
for (int i = 0; i < image_paths.size(); i++) {
size_t pos1 = image_paths[i].string().find('/') + 1;
std::string cipher_image_name = image_paths[i].string().substr(pos1);
std::string original_image_name =
AES_decrypt(cipher_image_name, aes128_key_, aes128_iv_);
std::string image_path = image_path_ + cipher_image_name;
textures[original_image_name] = nullptr;
LoadTextureFromFile(image_path.c_str(), renderer,
&(textures[original_image_name]), width, height);
}
return 0;
}
return 0;
}
int Thumbnail::DeleteThumbnail(const std::string& file_name) {
std::string ciphertext = AES_encrypt(file_name, aes128_key_, aes128_iv_);
std::string file_path = image_path_ + ciphertext;
if (std::filesystem::exists(file_path)) {
std::filesystem::remove(file_path);
return 0;
} else {
return -1;
}
}
int Thumbnail::DeleteAllFilesInDirectory() {
if (std::filesystem::exists(image_path_) &&
std::filesystem::is_directory(image_path_)) {
for (const auto& entry : std::filesystem::directory_iterator(image_path_)) {
if (std::filesystem::is_regular_file(entry.status())) {
std::filesystem::remove(entry.path());
}
}
return 0;
}
return -1;
}
std::string Thumbnail::AES_encrypt(const std::string& plaintext,
unsigned char* key, unsigned char* iv) {
EVP_CIPHER_CTX* ctx;
int len;
int ciphertext_len;
int ret = 0;
std::vector<unsigned char> ciphertext(plaintext.size() + AES_BLOCK_SIZE);
ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
LOG_ERROR("Error in EVP_CIPHER_CTX_new");
return plaintext;
}
ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
if (1 != ret) {
LOG_ERROR("Error in EVP_EncryptInit_ex");
EVP_CIPHER_CTX_free(ctx);
return plaintext;
}
ret = EVP_EncryptUpdate(
ctx, ciphertext.data(), &len,
reinterpret_cast<const unsigned char*>(plaintext.data()),
(int)plaintext.size());
if (1 != ret) {
LOG_ERROR("Error in EVP_EncryptUpdate");
EVP_CIPHER_CTX_free(ctx);
return plaintext;
}
ciphertext_len = len;
ret = EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len);
if (1 != ret) {
LOG_ERROR("Error in EVP_EncryptFinal_ex");
EVP_CIPHER_CTX_free(ctx);
return plaintext;
}
ciphertext_len += len;
unsigned char hex_str[256];
size_t hex_str_len = 0;
ret = OPENSSL_buf2hexstr_ex((char*)hex_str, sizeof(hex_str), &hex_str_len,
ciphertext.data(), ciphertext_len, '\0');
if (1 != ret) {
LOG_ERROR("Error in OPENSSL_buf2hexstr_ex");
EVP_CIPHER_CTX_free(ctx);
return plaintext;
}
EVP_CIPHER_CTX_free(ctx);
std::string str(reinterpret_cast<char*>(hex_str), hex_str_len);
return str;
}
std::string Thumbnail::AES_decrypt(const std::string& ciphertext,
unsigned char* key, unsigned char* iv) {
unsigned char ciphertext_buf[256];
size_t ciphertext_buf_len = 0;
unsigned char plaintext[256];
int plaintext_len = 0;
int plaintext_final_len = 0;
EVP_CIPHER_CTX* ctx;
int ret = 0;
ret = OPENSSL_hexstr2buf_ex(ciphertext_buf, sizeof(ciphertext_buf),
&ciphertext_buf_len, ciphertext.c_str(), '\0');
if (1 != ret) {
LOG_ERROR("Error in OPENSSL_hexstr2buf_ex");
return ciphertext;
}
ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
LOG_ERROR("Error in EVP_CIPHER_CTX_new");
return ciphertext;
}
ret = EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv);
if (1 != ret) {
LOG_ERROR("Error in EVP_DecryptInit_ex");
EVP_CIPHER_CTX_free(ctx);
return ciphertext;
}
ret = EVP_DecryptUpdate(ctx, plaintext, &plaintext_len, ciphertext_buf,
(int)ciphertext_buf_len);
if (1 != ret) {
LOG_ERROR("Error in EVP_DecryptUpdate");
EVP_CIPHER_CTX_free(ctx);
return ciphertext;
}
ret =
EVP_DecryptFinal_ex(ctx, plaintext + plaintext_len, &plaintext_final_len);
if (1 != ret) {
LOG_ERROR("Error in EVP_DecryptFinal_ex");
EVP_CIPHER_CTX_free(ctx);
return ciphertext;
}
plaintext_len += plaintext_final_len;
EVP_CIPHER_CTX_free(ctx);
return std::string(reinterpret_cast<char*>(plaintext), plaintext_len);
}

View File

@@ -0,0 +1,74 @@
/*
* @Author: DI JUNKUN
* @Date: 2024-11-07
* Copyright (c) 2024 by DI JUNKUN, All Rights Reserved.
*/
#ifndef _THUMBNAIL_H_
#define _THUMBNAIL_H_
#include <SDL.h>
#include <filesystem>
#include <map>
class Thumbnail {
public:
Thumbnail();
explicit Thumbnail(unsigned char* aes128_key, unsigned char* aes128_iv);
~Thumbnail();
public:
int SaveToThumbnail(const char* yuv420p, int width, int height,
const std::string& remote_id,
const std::string& host_name,
const std::string& password);
int LoadThumbnail(SDL_Renderer* renderer,
std::map<std::string, SDL_Texture*>& textures, int* width,
int* height);
int DeleteThumbnail(const std::string& file_name);
int DeleteAllFilesInDirectory();
int GetKey(unsigned char* aes128_key) {
memcpy(aes128_key, aes128_key_, sizeof(aes128_key_));
return sizeof(aes128_key_);
}
int GetIv(unsigned char* aes128_iv) {
memcpy(aes128_iv, aes128_iv_, sizeof(aes128_iv_));
return sizeof(aes128_iv_);
}
int GetKeyAndIv(unsigned char* aes128_key, unsigned char* aes128_iv) {
memcpy(aes128_key, aes128_key_, sizeof(aes128_key_));
memcpy(aes128_iv, aes128_iv_, sizeof(aes128_iv_));
return 0;
}
private:
std::vector<std::filesystem::path> FindThumbnailPath(
const std::filesystem::path& directory);
std::string AES_encrypt(const std::string& plaintext, unsigned char* key,
unsigned char* iv);
std::string AES_decrypt(const std::string& ciphertext, unsigned char* key,
unsigned char* iv);
private:
int thumbnail_width_ = 160;
int thumbnail_height_ = 90;
char* rgba_buffer_ = nullptr;
std::string image_path_ = "thumbnails/";
std::map<std::time_t, std::filesystem::path> thumbnails_sorted_by_write_time_;
unsigned char aes128_key_[16];
unsigned char aes128_iv_[16];
unsigned char ciphertext_[64];
unsigned char decryptedtext_[64];
};
#endif

View File

@@ -1,27 +1,32 @@
#include "IconsFontAwesome6.h"
#include "localization.h"
#include "render.h"
#define BUTTON_PADDING 36.0f
int Render::TitleBar() {
ImGui::PushStyleColor(ImGuiCol_MenuBarBg, ImVec4(1, 1, 1, 0.0f));
int Render::TitleBar(bool main_window) {
ImGui::PushStyleColor(ImGuiCol_MenuBarBg, ImVec4(1.0f, 1.0f, 1.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::SetNextWindowPos(ImVec2(0, 0), ImGuiCond_Always);
ImGui::SetWindowFontScale(0.8f);
ImGui::BeginChild("TitleBar", ImVec2(main_window_width_, title_bar_height_),
ImGuiChildFlags_None,
ImGui::BeginChild(
main_window ? "MainTitleBar" : "StreamTitleBar",
ImVec2(main_window ? main_window_width_ : stream_window_width_,
title_bar_height_),
ImGuiChildFlags_Border,
ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoBringToFrontOnFocus);
ImDrawList* draw_list = ImGui::GetWindowDrawList();
ImGui::SetWindowFontScale(1.0f);
ImGui::PopStyleColor();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
if (ImGui::BeginMenuBar()) {
ImGui::SetCursorPosX(main_window_width_ - (streaming_
? BUTTON_PADDING * 4 - 3
: BUTTON_PADDING * 3 - 3));
ImGui::SetCursorPosX(
(main_window ? main_window_width_ : stream_window_width_) -
(BUTTON_PADDING * 3 - 3));
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_HeaderActive,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
if (!streaming_) {
if (main_window) {
float bar_pos_x = ImGui::GetCursorPosX() + 6;
float bar_pos_y = ImGui::GetCursorPosY() + 15;
std::string menu_button = " "; // ICON_FA_BARS;
@@ -48,7 +53,6 @@ int Render::TitleBar() {
draw_list->AddLine(ImVec2(bar_pos_x, bar_pos_y + 6),
ImVec2(bar_pos_x + menu_bar_line_size, bar_pos_y + 6),
IM_COL32(0, 0, 0, 255));
ImGui::PopStyleColor(2);
{
SettingWindow();
@@ -56,10 +60,12 @@ int Render::TitleBar() {
}
}
ImGui::PopStyleColor(2);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::SetCursorPosX(main_window_width_ - (streaming_
? BUTTON_PADDING * 3
: BUTTON_PADDING * 2));
ImGui::SetCursorPosX(main_window
? (main_window_width_ - BUTTON_PADDING * 2)
: (stream_window_width_ - BUTTON_PADDING * 3));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
@@ -69,15 +75,15 @@ int Render::TitleBar() {
std::string window_minimize_button = "##minimize"; // ICON_FA_MINUS;
if (ImGui::Button(window_minimize_button.c_str(),
ImVec2(BUTTON_PADDING, 30))) {
SDL_MinimizeWindow(main_window_);
SDL_MinimizeWindow(main_window ? main_window_ : stream_window_);
}
draw_list->AddLine(ImVec2(minimize_pos_x, minimize_pos_y),
ImVec2(minimize_pos_x + 12, minimize_pos_y),
IM_COL32(0, 0, 0, 255));
ImGui::PopStyleColor(2);
if (streaming_) {
ImGui::SetCursorPosX(main_window_width_ - BUTTON_PADDING * 2);
if (!main_window) {
ImGui::SetCursorPosX(stream_window_width_ - BUTTON_PADDING * 2);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0.1f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive,
ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
@@ -91,7 +97,7 @@ int Render::TitleBar() {
"##restore"; // ICON_FA_WINDOW_RESTORE;
if (ImGui::Button(window_restore_button.c_str(),
ImVec2(BUTTON_PADDING, 30))) {
SDL_RestoreWindow(main_window_);
SDL_RestoreWindow(stream_window_);
window_maximized_ = false;
}
draw_list->AddRect(ImVec2(pos_x_top, pos_y_top),
@@ -110,7 +116,7 @@ int Render::TitleBar() {
"##maximize"; // ICON_FA_SQUARE_FULL;
if (ImGui::Button(window_maximize_button.c_str(),
ImVec2(BUTTON_PADDING, 30))) {
SDL_MaximizeWindow(main_window_);
SDL_MaximizeWindow(stream_window_);
window_maximized_ = !window_maximized_;
}
draw_list->AddRect(ImVec2(maximize_pos_x, maximize_pos_y),
@@ -120,7 +126,9 @@ int Render::TitleBar() {
ImGui::PopStyleColor(2);
}
ImGui::SetCursorPosX(main_window_width_ - BUTTON_PADDING);
ImGui::SetCursorPosX(
(main_window ? main_window_width_ : stream_window_width_) -
BUTTON_PADDING);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0, 0, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 0, 0, 0.5f));
@@ -146,11 +154,11 @@ int Render::TitleBar() {
ImGui::PopStyleColor(2);
ImGui::PopStyleColor(1);
ImGui::PopStyleColor();
}
ImGui::SetWindowFontScale(1.0f);
ImGui::EndMenuBar();
ImGui::EndChild();
ImGui::PopStyleColor(2);
ImGui::PopStyleColor();
return 0;
}

View File

@@ -17,14 +17,16 @@ if is_mode("debug") then
end
add_requires("spdlog 1.14.1", {system = false})
add_requires("imgui v1.91.0", {configs = {sdl2 = true, sdl2_renderer = true}})
add_requires("imgui v1.91.5-docking", {configs = {sdl2 = true, sdl2_renderer = true}})
add_requires("miniaudio 0.11.21")
add_requires("openssl3 3.3.2", {system = false})
if is_os("windows") then
add_requires("libyuv")
add_links("Shell32", "windowsapp", "dwmapi", "User32", "kernel32",
"SDL2-static", "SDL2main", "gdi32", "winmm", "setupapi", "version",
"Imm32", "iphlpapi")
add_cxflags("/WX")
elseif is_os("linux") then
add_requires("ffmpeg 5.1.2", {system = false})
add_syslinks("pthread", "dl")
@@ -35,12 +37,14 @@ elseif is_os("linux") then
"-lasound", "-lxcb-shape", "-lxcb-xfixes", "-lsndio", "-lxcb",
"-lxcb-shm", "-lXext", "-lX11", "-lXv", "-ldl", "-lpthread",
{force = true})
add_cxflags("-Wno-unused-variable")
elseif is_os("macosx") then
add_requires("ffmpeg 5.1.2", {system = false})
add_requires("libxcb", {system = false})
add_packages("libxcb")
add_links("SDL2", "SDL2main")
add_ldflags("-Wl,-ld_classic")
add_cxflags("-Wno-unused-variable")
add_frameworks("OpenGL", "IOSurface", "ScreenCaptureKit")
end
@@ -51,7 +55,7 @@ includes("thirdparty")
target("rd_log")
set_kind("object")
add_packages("spdlog")
add_headerfiles("src/log/rd_log.h")
add_files("src/log/rd_log.cpp")
add_includedirs("src/log", {public = true})
target("common")
@@ -102,14 +106,20 @@ target("device_controller")
add_deps("rd_log")
add_includedirs("src/device_controller", {public = true})
if is_os("windows") then
add_files("src/device_controller/mouse/windows/*.cpp")
add_includedirs("src/device_controller/mouse/windows", {public = true})
add_files("src/device_controller/mouse/windows/*.cpp",
"src/device_controller/keyboard/windows/*.cpp")
add_includedirs("src/device_controller/mouse/windows",
"src/device_controller/keyboard/windows", {public = true})
elseif is_os("macosx") then
add_files("src/device_controller/mouse/mac/*.cpp")
add_includedirs("src/device_controller/mouse/mac", {public = true})
add_files("src/device_controller/mouse/mac/*.cpp",
"src/device_controller/keyboard/mac/*.cpp")
add_includedirs("src/device_controller/mouse/mac",
"src/device_controller/keyboard/mac", {public = true})
elseif is_os("linux") then
add_files("src/device_controller/mouse/linux/*.cpp")
add_includedirs("src/device_controller/mouse/linux", {public = true})
add_files("src/device_controller/mouse/linux/*.cpp",
"src/device_controller/keyboard/linux/*.cpp")
add_includedirs("src/device_controller/mouse/linux",
"src/device_controller/keyboard/linux", {public = true})
end
target("config_center")
@@ -124,6 +134,7 @@ target("localization")
target("single_window")
set_kind("object")
add_packages("libyuv", "openssl3")
add_deps("rd_log", "common", "localization", "config_center", "projectx", "screen_capturer", "speaker_capturer", "device_controller")
if is_os("macosx") then
add_packages("ffmpeg")