Merge pull request #1409 from 21pages/remote-modification
option remote modification
This commit is contained in:
commit
1e07a604e8
@ -664,8 +664,6 @@ Future<void> initGlobalFFI() async {
|
|||||||
debugPrint("_globalFFI init end");
|
debugPrint("_globalFFI init end");
|
||||||
// after `put`, can also be globally found by Get.find<FFI>();
|
// after `put`, can also be globally found by Get.find<FFI>();
|
||||||
Get.put(_globalFFI, permanent: true);
|
Get.put(_globalFFI, permanent: true);
|
||||||
// trigger connection status updater
|
|
||||||
await bind.mainCheckConnectStatus();
|
|
||||||
// global shared preference
|
// global shared preference
|
||||||
await Get.putAsync(() => SharedPreferences.getInstance());
|
await Get.putAsync(() => SharedPreferences.getInstance());
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,6 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 24,
|
height: 24,
|
||||||
width: 72,
|
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: ftPressed.value
|
color: ftPressed.value
|
||||||
@ -257,7 +256,7 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
color: ftPressed.value
|
color: ftPressed.value
|
||||||
? MyTheme.color(context).bg
|
? MyTheme.color(context).bg
|
||||||
: MyTheme.color(context).text),
|
: MyTheme.color(context).text),
|
||||||
),
|
).marginSymmetric(horizontal: 12),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@ -272,7 +271,6 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
onTap: onConnect,
|
onTap: onConnect,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 24,
|
height: 24,
|
||||||
width: 65,
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: connPressed.value
|
color: connPressed.value
|
||||||
? MyTheme.accent
|
? MyTheme.accent
|
||||||
@ -289,12 +287,12 @@ class _ConnectionPageState extends State<ConnectionPage> {
|
|||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
translate(
|
translate(
|
||||||
"Connection",
|
"Connect",
|
||||||
),
|
),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12, color: MyTheme.color(context).bg),
|
fontSize: 12, color: MyTheme.color(context).bg),
|
||||||
),
|
),
|
||||||
),
|
).marginSymmetric(horizontal: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -93,7 +93,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
body: Obx(() => DesktopTab(
|
body: Obx(() => DesktopTab(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
isMainWindow: false,
|
tabType: DesktopTabType.remoteScreen,
|
||||||
showTabBar: fullscreen.isFalse,
|
showTabBar: fullscreen.isFalse,
|
||||||
onClose: () {
|
onClose: () {
|
||||||
tabController.clear();
|
tabController.clear();
|
||||||
|
@ -46,7 +46,7 @@ class _DesktopTabPageState extends State<DesktopTabPage> {
|
|||||||
body: DesktopTab(
|
body: DesktopTab(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
theme: dark ? TarBarTheme.dark() : TarBarTheme.light(),
|
theme: dark ? TarBarTheme.dark() : TarBarTheme.light(),
|
||||||
isMainWindow: true,
|
tabType: DesktopTabType.main,
|
||||||
tail: ActionIcon(
|
tail: ActionIcon(
|
||||||
message: 'Settings',
|
message: 'Settings',
|
||||||
icon: IconFont.menu,
|
icon: IconFont.menu,
|
||||||
|
@ -37,7 +37,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
tabController.onRemove = (_, id) => onRemoveId(id);
|
tabController.onRemove = (_, id) => onRemoveId(id);
|
||||||
|
|
||||||
rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
|
rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
|
||||||
@ -74,9 +74,9 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
|
|||||||
body: DesktopTab(
|
body: DesktopTab(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
isMainWindow: false,
|
tabType: DesktopTabType.fileTransfer,
|
||||||
onClose: () {
|
onClose: () {
|
||||||
tabController.clear();
|
tabController.clear();
|
||||||
},
|
},
|
||||||
tail: AddButton(
|
tail: AddButton(
|
||||||
theme: theme,
|
theme: theme,
|
||||||
|
@ -19,11 +19,13 @@ class PortForwardTabPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _PortForwardTabPageState extends State<PortForwardTabPage> {
|
class _PortForwardTabPageState extends State<PortForwardTabPage> {
|
||||||
final tabController = Get.put(DesktopTabController());
|
final tabController = Get.put(DesktopTabController());
|
||||||
|
late final bool isRDP;
|
||||||
|
|
||||||
static final IconData selectedIcon = Icons.forward_sharp;
|
static const IconData selectedIcon = Icons.forward_sharp;
|
||||||
static final IconData unselectedIcon = Icons.forward_outlined;
|
static const IconData unselectedIcon = Icons.forward_outlined;
|
||||||
|
|
||||||
_PortForwardTabPageState(Map<String, dynamic> params) {
|
_PortForwardTabPageState(Map<String, dynamic> params) {
|
||||||
|
isRDP = params['isRDP'];
|
||||||
tabController.add(TabInfo(
|
tabController.add(TabInfo(
|
||||||
key: params['id'],
|
key: params['id'],
|
||||||
label: params['id'],
|
label: params['id'],
|
||||||
@ -32,7 +34,7 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
|
|||||||
page: PortForwardPage(
|
page: PortForwardPage(
|
||||||
key: ValueKey(params['id']),
|
key: ValueKey(params['id']),
|
||||||
id: params['id'],
|
id: params['id'],
|
||||||
isRDP: params['isRDP'],
|
isRDP: isRDP,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +78,7 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
|
|||||||
body: DesktopTab(
|
body: DesktopTab(
|
||||||
controller: tabController,
|
controller: tabController,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
isMainWindow: false,
|
tabType: isRDP ? DesktopTabType.rdp : DesktopTabType.portForward,
|
||||||
onClose: () {
|
onClose: () {
|
||||||
tabController.clear();
|
tabController.clear();
|
||||||
},
|
},
|
||||||
|
@ -111,7 +111,7 @@ class ConnectionManagerState extends State<ConnectionManager> {
|
|||||||
showMaximize: false,
|
showMaximize: false,
|
||||||
showMinimize: false,
|
showMinimize: false,
|
||||||
controller: serverModel.tabController,
|
controller: serverModel.tabController,
|
||||||
isMainWindow: true,
|
tabType: DesktopTabType.cm,
|
||||||
pageViewBuilder: (pageView) => Row(children: [
|
pageViewBuilder: (pageView) => Row(children: [
|
||||||
Expanded(child: pageView),
|
Expanded(child: pageView),
|
||||||
Consumer<ChatModel>(
|
Consumer<ChatModel>(
|
||||||
@ -294,7 +294,8 @@ class _CmHeaderState extends State<_CmHeader>
|
|||||||
Offstage(
|
Offstage(
|
||||||
offstage: client.isFileTransfer,
|
offstage: client.isFileTransfer,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
onPressed: () => gFFI.chatModel.toggleCMChatPage(client.id),
|
onPressed: () => checkClickTime(
|
||||||
|
client.id, () => gFFI.chatModel.toggleCMChatPage(client.id)),
|
||||||
icon: Icon(Icons.message_outlined),
|
icon: Icon(Icons.message_outlined),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -326,7 +327,8 @@ class _PrivilegeBoardState extends State<_PrivilegeBoard> {
|
|||||||
BoxDecoration(color: enabled ? MyTheme.accent80 : Colors.grey),
|
BoxDecoration(color: enabled ? MyTheme.accent80 : Colors.grey),
|
||||||
padding: EdgeInsets.all(4.0),
|
padding: EdgeInsets.all(4.0),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => onTap?.call(!enabled),
|
onTap: () =>
|
||||||
|
checkClickTime(widget.client.id, () => onTap?.call(!enabled)),
|
||||||
child: Image(
|
child: Image(
|
||||||
image: icon,
|
image: icon,
|
||||||
width: 50,
|
width: 50,
|
||||||
@ -422,7 +424,8 @@ class _CmControlPanel extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.redAccent, borderRadius: BorderRadius.circular(10)),
|
color: Colors.redAccent, borderRadius: BorderRadius.circular(10)),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => handleDisconnect(context),
|
onTap: () =>
|
||||||
|
checkClickTime(client.id, () => handleDisconnect(context)),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -447,7 +450,8 @@ class _CmControlPanel extends StatelessWidget {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: MyTheme.accent, borderRadius: BorderRadius.circular(10)),
|
color: MyTheme.accent, borderRadius: BorderRadius.circular(10)),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => handleAccept(context),
|
onTap: () =>
|
||||||
|
checkClickTime(client.id, () => handleAccept(context)),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -469,7 +473,8 @@ class _CmControlPanel extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
border: Border.all(color: Colors.grey)),
|
border: Border.all(color: Colors.grey)),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => handleDisconnect(context),
|
onTap: () =>
|
||||||
|
checkClickTime(client.id, () => handleDisconnect(context)),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -572,3 +577,12 @@ Widget clientInfo(Client client) {
|
|||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkClickTime(int id, Function() callback) async {
|
||||||
|
var clickCallbackTime = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
await bind.cmCheckClickTime(connId: id);
|
||||||
|
Timer(const Duration(milliseconds: 120), () async {
|
||||||
|
var d = clickCallbackTime - await bind.cmGetClickTime();
|
||||||
|
if (d > 120) callback();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
import 'package:desktop_multi_window/desktop_multi_window.dart';
|
||||||
@ -6,6 +7,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
import 'package:flutter_hbb/consts.dart';
|
import 'package:flutter_hbb/consts.dart';
|
||||||
import 'package:flutter_hbb/main.dart';
|
import 'package:flutter_hbb/main.dart';
|
||||||
|
import 'package:flutter_hbb/models/platform_model.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:scroll_pos/scroll_pos.dart';
|
import 'package:scroll_pos/scroll_pos.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
@ -34,6 +36,15 @@ class TabInfo {
|
|||||||
required this.page});
|
required this.page});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DesktopTabType {
|
||||||
|
main,
|
||||||
|
cm,
|
||||||
|
remoteScreen,
|
||||||
|
fileTransfer,
|
||||||
|
portForward,
|
||||||
|
rdp,
|
||||||
|
}
|
||||||
|
|
||||||
class DesktopTabState {
|
class DesktopTabState {
|
||||||
final List<TabInfo> tabs = [];
|
final List<TabInfo> tabs = [];
|
||||||
final ScrollPosController scrollController =
|
final ScrollPosController scrollController =
|
||||||
@ -64,6 +75,7 @@ class DesktopTabController {
|
|||||||
state.update((val) {
|
state.update((val) {
|
||||||
val!.tabs.add(tab);
|
val!.tabs.add(tab);
|
||||||
});
|
});
|
||||||
|
state.value.scrollController.itemCount = state.value.tabs.length;
|
||||||
toIndex = state.value.tabs.length - 1;
|
toIndex = state.value.tabs.length - 1;
|
||||||
assert(toIndex >= 0);
|
assert(toIndex >= 0);
|
||||||
}
|
}
|
||||||
@ -96,8 +108,16 @@ class DesktopTabController {
|
|||||||
void jumpTo(int index) {
|
void jumpTo(int index) {
|
||||||
state.update((val) {
|
state.update((val) {
|
||||||
val!.selected = index;
|
val!.selected = index;
|
||||||
val.pageController.jumpToPage(index);
|
Future.delayed(Duration.zero, (() {
|
||||||
val.scrollController.scrollToItem(index, center: true, animate: true);
|
if (val.pageController.hasClients) {
|
||||||
|
val.pageController.jumpToPage(index);
|
||||||
|
}
|
||||||
|
if (val.scrollController.hasClients &&
|
||||||
|
val.scrollController.canScroll &&
|
||||||
|
val.scrollController.itemCount >= index) {
|
||||||
|
val.scrollController.scrollToItem(index, center: true, animate: true);
|
||||||
|
}
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
onSelected?.call(index);
|
onSelected?.call(index);
|
||||||
}
|
}
|
||||||
@ -134,6 +154,7 @@ typedef LabelGetter = Rx<String> Function(String key);
|
|||||||
class DesktopTab extends StatelessWidget {
|
class DesktopTab extends StatelessWidget {
|
||||||
final Function(String)? onTabClose;
|
final Function(String)? onTabClose;
|
||||||
final TarBarTheme theme;
|
final TarBarTheme theme;
|
||||||
|
final DesktopTabType tabType;
|
||||||
final bool isMainWindow;
|
final bool isMainWindow;
|
||||||
final bool showTabBar;
|
final bool showTabBar;
|
||||||
final bool showLogo;
|
final bool showLogo;
|
||||||
@ -152,7 +173,7 @@ class DesktopTab extends StatelessWidget {
|
|||||||
|
|
||||||
const DesktopTab({
|
const DesktopTab({
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.isMainWindow,
|
required this.tabType,
|
||||||
this.theme = const TarBarTheme.light(),
|
this.theme = const TarBarTheme.light(),
|
||||||
this.onTabClose,
|
this.onTabClose,
|
||||||
this.showTabBar = true,
|
this.showTabBar = true,
|
||||||
@ -166,7 +187,8 @@ class DesktopTab extends StatelessWidget {
|
|||||||
this.onClose,
|
this.onClose,
|
||||||
this.tabBuilder,
|
this.tabBuilder,
|
||||||
this.labelGetter,
|
this.labelGetter,
|
||||||
});
|
}) : isMainWindow =
|
||||||
|
tabType == DesktopTabType.main || tabType == DesktopTabType.cm;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -195,11 +217,48 @@ class DesktopTab extends StatelessWidget {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildBlock({required Widget child}) {
|
||||||
|
if (tabType != DesktopTabType.main) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
var block = false.obs;
|
||||||
|
return Obx(() => MouseRegion(
|
||||||
|
onEnter: (_) async {
|
||||||
|
if (!option2bool(
|
||||||
|
'allow-remote-config-modification',
|
||||||
|
await bind.mainGetOption(
|
||||||
|
key: 'allow-remote-config-modification'))) {
|
||||||
|
var time0 = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
await bind.mainCheckMouseTime();
|
||||||
|
Timer(const Duration(milliseconds: 120), () async {
|
||||||
|
var d = time0 - await bind.mainGetMouseTime();
|
||||||
|
if (d < 120) {
|
||||||
|
block.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onExit: (_) => block.value = false,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
child,
|
||||||
|
Offstage(
|
||||||
|
offstage: !block.value,
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black.withOpacity(0.5),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildPageView() {
|
Widget _buildPageView() {
|
||||||
return Obx(() => PageView(
|
return _buildBlock(
|
||||||
controller: state.value.pageController,
|
child: Obx(() => PageView(
|
||||||
children:
|
controller: state.value.pageController,
|
||||||
state.value.tabs.map((tab) => tab.page).toList(growable: false)));
|
children: state.value.tabs
|
||||||
|
.map((tab) => tab.page)
|
||||||
|
.toList(growable: false))));
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBar() {
|
Widget _buildBar() {
|
||||||
|
@ -81,6 +81,8 @@ Future<void> initEnv(String appType) async {
|
|||||||
|
|
||||||
void runMainApp(bool startService) async {
|
void runMainApp(bool startService) async {
|
||||||
await initEnv(kAppTypeMain);
|
await initEnv(kAppTypeMain);
|
||||||
|
// trigger connection status updater
|
||||||
|
await bind.mainCheckConnectStatus();
|
||||||
if (startService) {
|
if (startService) {
|
||||||
// await windowManager.ensureInitialized();
|
// await windowManager.ensureInitialized();
|
||||||
// disable tray
|
// disable tray
|
||||||
@ -89,10 +91,11 @@ void runMainApp(bool startService) async {
|
|||||||
}
|
}
|
||||||
runApp(App());
|
runApp(App());
|
||||||
// set window option
|
// set window option
|
||||||
WindowOptions windowOptions = getHiddenTitleBarWindowOptions(const Size(1280, 720));
|
WindowOptions windowOptions =
|
||||||
|
getHiddenTitleBarWindowOptions(const Size(1280, 720));
|
||||||
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
windowManager.waitUntilReadyToShow(windowOptions, () async {
|
||||||
await windowManager.show();
|
await windowManager.show();
|
||||||
await windowManager.focus();
|
await windowManager.focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,12 +22,13 @@ use crate::ui_interface;
|
|||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
use crate::ui_interface::{change_id, check_connect_status, is_ok_change_id};
|
use crate::ui_interface::{change_id, check_connect_status, is_ok_change_id};
|
||||||
use crate::ui_interface::{
|
use crate::ui_interface::{
|
||||||
check_super_user_permission, discover, forget_password, get_api_server, get_app_name,
|
check_mouse_time, check_super_user_permission, discover, forget_password, get_api_server,
|
||||||
get_async_job_status, get_connect_status, get_fav, get_id, get_lan_peers, get_langs,
|
get_app_name, get_async_job_status, get_connect_status, get_fav, get_id, get_lan_peers,
|
||||||
get_license, get_local_option, get_option, get_options, get_peer, get_peer_option, get_socks,
|
get_langs, get_license, get_local_option, get_mouse_time, get_option, get_options, get_peer,
|
||||||
get_sound_inputs, get_uuid, get_version, has_hwcodec, has_rendezvous_service, post_request,
|
get_peer_option, get_socks, get_sound_inputs, get_uuid, get_version, has_hwcodec,
|
||||||
set_local_option, set_option, set_options, set_peer_option, set_permanent_password, set_socks,
|
has_rendezvous_service, post_request, set_local_option, set_option, set_options,
|
||||||
store_fav, test_if_valid_server, update_temporary_password, using_public_server,
|
set_peer_option, set_permanent_password, set_socks, store_fav, test_if_valid_server,
|
||||||
|
update_temporary_password, using_public_server,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn initialize(app_dir: &str) {
|
fn initialize(app_dir: &str) {
|
||||||
@ -472,7 +473,7 @@ pub fn main_get_connect_status() -> String {
|
|||||||
|
|
||||||
pub fn main_check_connect_status() {
|
pub fn main_check_connect_status() {
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
check_connect_status(true);
|
check_mouse_time(); // avoid multi calls
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main_is_using_public_server() -> bool {
|
pub fn main_is_using_public_server() -> bool {
|
||||||
@ -764,6 +765,14 @@ pub fn main_check_super_user_permission() -> bool {
|
|||||||
check_super_user_permission()
|
check_super_user_permission()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn main_check_mouse_time() {
|
||||||
|
check_mouse_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main_get_mouse_time() -> f64 {
|
||||||
|
get_mouse_time()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cm_send_chat(conn_id: i32, msg: String) {
|
pub fn cm_send_chat(conn_id: i32, msg: String) {
|
||||||
connection_manager::send_chat(conn_id, msg);
|
connection_manager::send_chat(conn_id, msg);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user