mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-14 03:32:23 +01:00
9.0.4
This commit is contained in:
@@ -1,57 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:reboot_launcher/src/controller/game_controller.dart';
|
||||
import 'package:reboot_launcher/src/controller/hosting_controller.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
final File _executable = File("${assetsDirectory.path}\\misc\\watch.exe");
|
||||
|
||||
extension GameInstanceWatcher on GameInstance {
|
||||
Future<void> startObserver() async {
|
||||
if(observerPid != null) {
|
||||
Process.killPid(observerPid!, ProcessSignal.sigabrt);
|
||||
}
|
||||
|
||||
final hostingController = Get.find<HostingController>();
|
||||
final gameController = Get.find<GameController>();
|
||||
watchProcess(gamePid).then((value) async {
|
||||
gameController.started.value = false;
|
||||
gameController.instance.value?.kill();
|
||||
if(_nestedHosting) {
|
||||
hostingController.started.value = false;
|
||||
hostingController.instance.value?.kill();
|
||||
await Supabase.instance.client.from("hosting")
|
||||
.delete()
|
||||
.match({'id': hostingController.uuid});
|
||||
}
|
||||
});
|
||||
|
||||
final process = await startProcess(
|
||||
executable: _executable,
|
||||
args: [
|
||||
hostingController.uuid,
|
||||
gamePid.toString(),
|
||||
launcherPid?.toString() ?? "-1",
|
||||
eacPid?.toString() ?? "-1",
|
||||
hosting.toString()
|
||||
],
|
||||
|
||||
);
|
||||
observerPid = process.pid;
|
||||
}
|
||||
|
||||
bool get _nestedHosting {
|
||||
GameInstance? child = this;
|
||||
while(child != null) {
|
||||
if(child.hosting) {
|
||||
return true;
|
||||
}
|
||||
|
||||
child = child.child;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -9,33 +9,49 @@ import 'package:reboot_launcher/src/dialog/abstract/info_bar.dart';
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
|
||||
final UpdateController _updateController = Get.find<UpdateController>();
|
||||
Future<void> downloadCriticalDllInteractive(String filePath) async {
|
||||
final Map<String, Future<void>> _operations = {};
|
||||
|
||||
Future<void> downloadCriticalDllInteractive(String filePath) {
|
||||
final old = _operations[filePath];
|
||||
if(old != null) {
|
||||
return old;
|
||||
}
|
||||
|
||||
final newRun = _downloadCriticalDllInteractive(filePath);
|
||||
_operations[filePath] = newRun;
|
||||
return newRun;
|
||||
}
|
||||
|
||||
Future<void> _downloadCriticalDllInteractive(String filePath) async {
|
||||
final fileName = path.basename(filePath).toLowerCase();
|
||||
InfoBarEntry? entry;
|
||||
try {
|
||||
final fileName = path.basename(filePath).toLowerCase();
|
||||
if (fileName == "reboot.dll") {
|
||||
_updateController.update(true);
|
||||
await _updateController.update(true);
|
||||
return;
|
||||
}
|
||||
|
||||
final fileNameWithoutExtension = path.basenameWithoutExtension(filePath);
|
||||
await showInfoBar(
|
||||
entry = showInfoBar(
|
||||
translations.downloadingDll(fileNameWithoutExtension),
|
||||
loading: true,
|
||||
duration: null
|
||||
);
|
||||
await downloadCriticalDll(fileName, filePath);
|
||||
await showInfoBar(
|
||||
entry.close();
|
||||
entry = await showInfoBar(
|
||||
translations.downloadDllSuccess(fileNameWithoutExtension),
|
||||
severity: InfoBarSeverity.success,
|
||||
duration: infoBarShortDuration
|
||||
);
|
||||
}catch(message) {
|
||||
entry?.close();
|
||||
var error = message.toString();
|
||||
error = error.contains(": ") ? error.substring(error.indexOf(": ") + 2) : error;
|
||||
error = error.toLowerCase();
|
||||
final completer = Completer();
|
||||
await showInfoBar(
|
||||
translations.downloadDllError(error.toString()),
|
||||
translations.downloadDllError(fileName, error.toString()),
|
||||
duration: infoBarLongDuration,
|
||||
severity: InfoBarSeverity.error,
|
||||
onDismissed: () => completer.complete(null),
|
||||
@@ -48,5 +64,7 @@ Future<void> downloadCriticalDllInteractive(String filePath) async {
|
||||
)
|
||||
);
|
||||
await completer.future;
|
||||
}finally {
|
||||
_operations.remove(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
202
gui/lib/src/util/keyboard.dart
Normal file
202
gui/lib/src/util/keyboard.dart
Normal file
@@ -0,0 +1,202 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
extension UnrealEngineKeyboard on PhysicalKeyboardKey {
|
||||
static const Map<int, String> _keyboardKeyNames = <int, String>{
|
||||
0x0007003a: 'F1',
|
||||
0x0007003b: 'F2',
|
||||
0x0007003c: 'F3',
|
||||
0x0007003d: 'F4',
|
||||
0x0007003e: 'F5',
|
||||
0x0007003f: 'F6',
|
||||
0x00070040: 'F7',
|
||||
0x00070041: 'F8',
|
||||
0x00070042: 'F9',
|
||||
0x00070043: 'F10',
|
||||
0x00070044: 'F11',
|
||||
0x00070045: 'F12',
|
||||
|
||||
0x00070004: 'A',
|
||||
0x00070005: 'B',
|
||||
0x00070006: 'C',
|
||||
0x00070007: 'D',
|
||||
0x00070008: 'E',
|
||||
0x00070009: 'F',
|
||||
0x0007000a: 'G',
|
||||
0x0007000b: 'H',
|
||||
0x0007000c: 'I',
|
||||
0x0007000d: 'J',
|
||||
0x0007000e: 'K',
|
||||
0x0007000f: 'L',
|
||||
0x00070010: 'M',
|
||||
0x00070011: 'N',
|
||||
0x00070012: 'O',
|
||||
0x00070013: 'P',
|
||||
0x00070014: 'Q',
|
||||
0x00070015: 'R',
|
||||
0x00070016: 'S',
|
||||
0x00070017: 'T',
|
||||
0x00070018: 'U',
|
||||
0x00070019: 'V',
|
||||
0x0007001a: 'W',
|
||||
0x0007001b: 'X',
|
||||
0x0007001c: 'Y',
|
||||
0x0007001d: 'Z',
|
||||
|
||||
0x0007001e: 'one',
|
||||
0x0007001f: 'two',
|
||||
0x00070020: 'three',
|
||||
0x00070021: 'four',
|
||||
0x00070022: 'five',
|
||||
0x00070023: 'six',
|
||||
0x00070024: 'seven',
|
||||
0x00070025: 'eight',
|
||||
0x00070026: 'nine',
|
||||
0x00070027: 'zero',
|
||||
|
||||
0x00070028: 'Enter',
|
||||
0x00070029: 'Escape',
|
||||
0x0007002a: 'Backspace',
|
||||
0x0007002b: 'Tab',
|
||||
0x0007002c: 'SpaceBar',
|
||||
0x0007002d: 'Minus',
|
||||
0x0007002e: 'Equals',
|
||||
0x0007002f: 'LeftBracket',
|
||||
0x00070030: 'RightBracket',
|
||||
0x00070031: 'Backslash',
|
||||
0x00070033: 'Semicolon',
|
||||
0x00070034: 'Quote',
|
||||
0x00070036: 'Comma',
|
||||
0x00070037: 'Period',
|
||||
0x00070038: 'Slash',
|
||||
0x00070039: 'CapsLock',
|
||||
0x00070047: 'ScrollLock',
|
||||
0x00070048: 'Pause',
|
||||
0x00070049: 'Insert',
|
||||
0x0007004a: 'Home',
|
||||
0x0007004b: 'PageUp',
|
||||
0x0007004c: 'Delete',
|
||||
0x0007004d: 'End',
|
||||
0x0007004e: 'PageDown',
|
||||
0x00070053: 'NumLock',
|
||||
0x00070054: 'Divide',
|
||||
0x00070055: 'Multiply',
|
||||
0x00070056: 'Subtract',
|
||||
0x00070057: 'Add',
|
||||
0x00070058: 'Enter',
|
||||
0x00070059: 'NumPadOne',
|
||||
0x0007005a: 'NumPadTwo',
|
||||
0x0007005b: 'NumPadThree',
|
||||
0x0007005c: 'NumPadFour',
|
||||
0x0007005d: 'NumPadFive',
|
||||
0x0007005e: 'NumPadSix',
|
||||
0x0007005f: 'NumPadSeven',
|
||||
0x00070060: 'NumPadEight',
|
||||
0x00070061: 'NumPadNine',
|
||||
0x00070062: 'NumPadZero',
|
||||
0x00070063: 'Decimal',
|
||||
0x00070064: 'Backslash'
|
||||
};
|
||||
|
||||
static const Map<int, String> _keyboardKeyPrettyNames = <int, String>{
|
||||
0x0007003a: 'F1',
|
||||
0x0007003b: 'F2',
|
||||
0x0007003c: 'F3',
|
||||
0x0007003d: 'F4',
|
||||
0x0007003e: 'F5',
|
||||
0x0007003f: 'F6',
|
||||
0x00070040: 'F7',
|
||||
0x00070041: 'F8',
|
||||
0x00070042: 'F9',
|
||||
0x00070043: 'F10',
|
||||
0x00070044: 'F11',
|
||||
0x00070045: 'F12',
|
||||
|
||||
0x00070004: 'A',
|
||||
0x00070005: 'B',
|
||||
0x00070006: 'C',
|
||||
0x00070007: 'D',
|
||||
0x00070008: 'E',
|
||||
0x00070009: 'F',
|
||||
0x0007000a: 'G',
|
||||
0x0007000b: 'H',
|
||||
0x0007000c: 'I',
|
||||
0x0007000d: 'J',
|
||||
0x0007000e: 'K',
|
||||
0x0007000f: 'L',
|
||||
0x00070010: 'M',
|
||||
0x00070011: 'N',
|
||||
0x00070012: 'O',
|
||||
0x00070013: 'P',
|
||||
0x00070014: 'Q',
|
||||
0x00070015: 'R',
|
||||
0x00070016: 'S',
|
||||
0x00070017: 'T',
|
||||
0x00070018: 'U',
|
||||
0x00070019: 'V',
|
||||
0x0007001a: 'W',
|
||||
0x0007001b: 'X',
|
||||
0x0007001c: 'Y',
|
||||
0x0007001d: 'Z',
|
||||
|
||||
0x0007001e: '1',
|
||||
0x0007001f: '2',
|
||||
0x00070020: '3',
|
||||
0x00070021: '4',
|
||||
0x00070022: '5',
|
||||
0x00070023: '6',
|
||||
0x00070024: '7',
|
||||
0x00070025: '8',
|
||||
0x00070026: '9',
|
||||
0x00070027: '10',
|
||||
|
||||
0x00070028: 'ENTER',
|
||||
0x00070029: 'ESCAPE',
|
||||
0x0007002a: 'BACKSPACE',
|
||||
0x0007002b: 'TAB',
|
||||
0x0007002c: 'SPACEBAR',
|
||||
0x0007002d: 'MINUS',
|
||||
0x0007002e: 'EQUALS',
|
||||
0x0007002f: 'LEFTBRACKET',
|
||||
0x00070030: 'RIGHTBRACKET',
|
||||
0x00070031: 'BACKSLASH',
|
||||
0x00070033: 'SEMICOLON',
|
||||
0x00070034: 'QUOTE',
|
||||
0x00070036: 'COMMA',
|
||||
0x00070037: 'PERIOD',
|
||||
0x00070038: 'SLASH',
|
||||
0x00070039: 'CAPSLOCK',
|
||||
0x00070047: 'SCROLLLOCK',
|
||||
0x00070048: 'PAUSE',
|
||||
0x00070049: 'INSERT',
|
||||
0x0007004a: 'HOME',
|
||||
0x0007004b: 'PAGEUP',
|
||||
0x0007004c: 'DELETE',
|
||||
0x0007004d: 'END',
|
||||
0x0007004e: 'PAGEDOWN',
|
||||
0x00070053: 'NUMLOCK',
|
||||
0x00070054: 'DIVIDE',
|
||||
0x00070055: 'MULTIPLY',
|
||||
0x00070056: 'SUBTRACT',
|
||||
0x00070057: 'ADD',
|
||||
0x00070058: 'ENTER',
|
||||
0x00070059: '1',
|
||||
0x0007005a: '2',
|
||||
0x0007005b: '3',
|
||||
0x0007005c: '4',
|
||||
0x0007005d: '5',
|
||||
0x0007005e: '6',
|
||||
0x0007005f: '7',
|
||||
0x00070060: '8',
|
||||
0x00070061: '9',
|
||||
0x00070062: '0',
|
||||
0x00070063: 'DECIMAL',
|
||||
0x00070064: 'BACKSLASH'
|
||||
};
|
||||
|
||||
|
||||
String? get unrealEngineName => _keyboardKeyNames[this.usbHidUsage];
|
||||
|
||||
bool get isUnrealEngineKey => _keyboardKeyNames[this.usbHidUsage] != null;
|
||||
|
||||
String? get unrealEnginePrettyName => _keyboardKeyPrettyNames[this.usbHidUsage];
|
||||
}
|
||||
23
gui/lib/src/util/log.dart
Normal file
23
gui/lib/src/util/log.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:reboot_common/common.dart';
|
||||
import 'package:sync/semaphore.dart';
|
||||
|
||||
final File _loggingFile = _createLoggingFile();
|
||||
final Semaphore _semaphore = Semaphore(1);
|
||||
|
||||
File _createLoggingFile() {
|
||||
final file = File("${logsDirectory.path}\\launcher.log");
|
||||
file.parent.createSync(recursive: true);
|
||||
if(file.existsSync()) {
|
||||
file.deleteSync();
|
||||
}
|
||||
file.createSync();
|
||||
return file;
|
||||
}
|
||||
|
||||
void log(String message) async {
|
||||
await _semaphore.acquire();
|
||||
await _loggingFile.writeAsString("$message\n", mode: FileMode.append, flush: true);
|
||||
_semaphore.release();
|
||||
}
|
||||
@@ -6,22 +6,26 @@ import 'package:reboot_common/common.dart';
|
||||
const Duration _timeout = Duration(seconds: 2);
|
||||
|
||||
Future<bool> _pingGameServer(String hostname, int port) async {
|
||||
var socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0);
|
||||
var dataToSend = utf8.encode(DateTime.now().toIso8601String());
|
||||
socket.send(dataToSend, InternetAddress(hostname), port);
|
||||
await for (var event in socket) {
|
||||
switch(event) {
|
||||
case RawSocketEvent.read:
|
||||
return true;
|
||||
case RawSocketEvent.readClosed:
|
||||
case RawSocketEvent.closed:
|
||||
return false;
|
||||
case RawSocketEvent.write:
|
||||
break;
|
||||
RawDatagramSocket? socket;
|
||||
try {
|
||||
socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0);
|
||||
final dataToSend = utf8.encode(DateTime.now().toIso8601String());
|
||||
socket.send(dataToSend, InternetAddress(hostname), port);
|
||||
await for (var event in socket) {
|
||||
switch(event) {
|
||||
case RawSocketEvent.read:
|
||||
case RawSocketEvent.write:
|
||||
return true;
|
||||
case RawSocketEvent.readClosed:
|
||||
case RawSocketEvent.closed:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}finally {
|
||||
socket?.close();
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> get _timeoutFuture => Future.delayed(_timeout).then((value) => false);
|
||||
|
||||
@@ -2,18 +2,399 @@ import 'dart:io';
|
||||
|
||||
import 'package:fluent_ui/fluent_ui.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'dart:collection';
|
||||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:win32/win32.dart';
|
||||
|
||||
final RegExp _winBuildRegex = RegExp(r'(?<=\(Build )(.*)(?=\))');
|
||||
|
||||
bool get isWin11 {
|
||||
var result = _winBuildRegex.firstMatch(Platform.operatingSystemVersion)?.group(1);
|
||||
if(result == null){
|
||||
return false;
|
||||
int? get windowsBuild {
|
||||
final result = _winBuildRegex.firstMatch(Platform.operatingSystemVersion)?.group(1);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var intBuild = int.tryParse(result);
|
||||
return int.tryParse(result);
|
||||
}
|
||||
|
||||
bool get isWin11 {
|
||||
final intBuild = windowsBuild;
|
||||
return intBuild != null && intBuild > 22000;
|
||||
}
|
||||
|
||||
bool get isDarkMode
|
||||
=> SchedulerBinding.instance.platformDispatcher.platformBrightness.isDark;
|
||||
bool get isDarkMode =>
|
||||
SchedulerBinding.instance.platformDispatcher.platformBrightness.isDark;
|
||||
|
||||
class _ServiceProvider10 extends IUnknown {
|
||||
static const String _CLSID = "{C2F03A33-21F5-47FA-B4BB-156362A2F239}";
|
||||
static const String _IID = "{6D5140C1-7436-11CE-8034-00AA006009FA}";
|
||||
|
||||
_ServiceProvider10._internal(Pointer<COMObject> ptr) : super(ptr);
|
||||
|
||||
factory _ServiceProvider10.createInstance() =>
|
||||
_ServiceProvider10._internal(COMObject.createFromID(_CLSID, _IID));
|
||||
|
||||
Pointer<COMObject> queryService(String classId, String instanceId) {
|
||||
final result = calloc<COMObject>();
|
||||
final code = (ptr.ref.vtable + 3)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<
|
||||
HRESULT Function(Pointer, Pointer<GUID>, Pointer<GUID>,
|
||||
Pointer<COMObject>)>>>()
|
||||
.value
|
||||
.asFunction<
|
||||
int Function(Pointer, Pointer<GUID>, Pointer<GUID>,
|
||||
Pointer<COMObject>)>()(ptr.ref.lpVtbl,
|
||||
GUIDFromString(classId), GUIDFromString(instanceId), result);
|
||||
if (code != 0) {
|
||||
free(result);
|
||||
throw WindowsException(code);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
class IVirtualDesktop extends IUnknown {
|
||||
static const String _CLSID = "{3F07F4BE-B107-441A-AF0F-39D82529072C}";
|
||||
|
||||
IVirtualDesktop._internal(super.ptr);
|
||||
|
||||
String getName() {
|
||||
final result = calloc<HSTRING>();
|
||||
final code = (ptr.ref.vtable + 5)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<HRESULT Function(Pointer, Pointer<HSTRING>)>>>()
|
||||
.value
|
||||
.asFunction<
|
||||
int Function(Pointer, Pointer<HSTRING>)>()(ptr.ref.lpVtbl, result);
|
||||
if (code != 0) {
|
||||
free(result);
|
||||
throw WindowsException(code);
|
||||
}
|
||||
|
||||
return convertFromHString(result.value);
|
||||
}
|
||||
}
|
||||
|
||||
class IApplicationView extends IUnknown {
|
||||
// static const String _CLSID = "{372E1D3B-38D3-42E4-A15B-8AB2B178F513}";
|
||||
|
||||
IApplicationView._internal(super.ptr);
|
||||
}
|
||||
|
||||
class _IObjectArray extends IUnknown {
|
||||
_IObjectArray(super.ptr);
|
||||
|
||||
int getCount() {
|
||||
final result = calloc<Int32>();
|
||||
final code = (ptr.ref.vtable + 3)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<HRESULT Function(Pointer, Pointer<Int32>)>>>()
|
||||
.value
|
||||
.asFunction<
|
||||
int Function(Pointer, Pointer<Int32>)>()(ptr.ref.lpVtbl, result);
|
||||
if (code != 0) {
|
||||
free(result);
|
||||
throw WindowsException(code);
|
||||
}
|
||||
|
||||
return result.value;
|
||||
}
|
||||
|
||||
Pointer<COMObject> getAt(int index, String guid) {
|
||||
final result = calloc<COMObject>();
|
||||
final code = (ptr.ref.vtable + 4)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<
|
||||
HRESULT Function(Pointer, Int32 index, Pointer<GUID>,
|
||||
Pointer<COMObject>)>>>()
|
||||
.value
|
||||
.asFunction<
|
||||
int Function(
|
||||
Pointer, int index, Pointer<GUID>, Pointer<COMObject>)>()(
|
||||
ptr.ref.lpVtbl, index, GUIDFromString(guid), result);
|
||||
if (code != 0) {
|
||||
free(result);
|
||||
throw WindowsException(code);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
typedef _IObjectMapper<T> = T Function(Pointer<COMObject>);
|
||||
|
||||
class _IObjectArrayList<T> extends ListBase<T> {
|
||||
final _IObjectArray _array;
|
||||
final String _guid;
|
||||
final _IObjectMapper<T> _mapper;
|
||||
|
||||
_IObjectArrayList(
|
||||
{required _IObjectArray array,
|
||||
required String guid,
|
||||
required _IObjectMapper<T> mapper})
|
||||
: _array = array,
|
||||
_guid = guid,
|
||||
_mapper = mapper;
|
||||
|
||||
@override
|
||||
int get length => _array.getCount();
|
||||
|
||||
@override
|
||||
set length(int newLength) {
|
||||
throw UnsupportedError("Immutable list");
|
||||
}
|
||||
|
||||
@override
|
||||
T operator [](int index) => _mapper(_array.getAt(index, _guid));
|
||||
|
||||
@override
|
||||
void operator []=(int index, T value) {
|
||||
throw UnsupportedError("Immutable list");
|
||||
}
|
||||
}
|
||||
|
||||
class _IVirtualDesktopManagerInternal extends IUnknown {
|
||||
static const String _CLSID = "{C5E0CDCA-7B6E-41B2-9FC4-D93975CC467B}";
|
||||
static const String _IID_WIN10 = "{F31574D6-B682-4CDC-BD56-1827860ABEC6}";
|
||||
static const String _IID_WIN_21H2 = "{B2F925B9-5A0F-4D2E-9F4D-2B1507593C10}";
|
||||
static const String _IID_WIN_23H2 = "{A3175F2D-239C-4BD2-8AA0-EEBA8B0B138E}";
|
||||
static const String _IID_WIN_23H2_3085 = "{53F5CA0B-158F-4124-900C-057158060B27}";
|
||||
|
||||
_IVirtualDesktopManagerInternal._internal(super.ptr);
|
||||
|
||||
int getDesktopsCount() {
|
||||
final result = calloc<Int32>();
|
||||
final code = (ptr.ref.vtable + 3)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<HRESULT Function(Pointer, Pointer<Int32>)>>>()
|
||||
.value
|
||||
.asFunction<
|
||||
int Function(Pointer, Pointer<Int32>)>()(ptr.ref.lpVtbl, result);
|
||||
if (code != 0) {
|
||||
free(result);
|
||||
throw WindowsException(code);
|
||||
}
|
||||
|
||||
return result.value;
|
||||
}
|
||||
|
||||
List<IVirtualDesktop> getDesktops() {
|
||||
final result = calloc<COMObject>();
|
||||
final code = (ptr.ref.vtable + 7)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<
|
||||
HRESULT Function(Pointer, Pointer<COMObject>)>>>()
|
||||
.value
|
||||
.asFunction<int Function(Pointer, Pointer<COMObject>)>()(
|
||||
ptr.ref.lpVtbl, result);
|
||||
if (code != 0) {
|
||||
free(result);
|
||||
throw WindowsException(code);
|
||||
}
|
||||
|
||||
final array = _IObjectArray(result);
|
||||
return _IObjectArrayList(
|
||||
array: array,
|
||||
guid: IVirtualDesktop._CLSID,
|
||||
mapper: (comObject) => IVirtualDesktop._internal(comObject));
|
||||
}
|
||||
|
||||
void moveWindowToDesktop(IApplicationView view, IVirtualDesktop desktop) {
|
||||
final code = (ptr.ref.vtable + 4)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<
|
||||
Int32 Function(Pointer, COMObject, COMObject)>>>()
|
||||
.value
|
||||
.asFunction<int Function(Pointer, COMObject, COMObject)>()(
|
||||
ptr.ref.lpVtbl, view.ptr.ref, desktop.ptr.ref);
|
||||
if (code != 0) {
|
||||
throw WindowsException(code);
|
||||
}
|
||||
}
|
||||
|
||||
IVirtualDesktop createDesktop() {
|
||||
final result = calloc<COMObject>();
|
||||
final code = (ptr.ref.vtable + 10)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<
|
||||
HRESULT Function(Pointer, Pointer<COMObject>)>>>()
|
||||
.value
|
||||
.asFunction<int Function(Pointer, Pointer<COMObject>)>()(
|
||||
ptr.ref.lpVtbl, result);
|
||||
if (code != 0) {
|
||||
free(result);
|
||||
throw WindowsException(code);
|
||||
}
|
||||
|
||||
return IVirtualDesktop._internal(result);
|
||||
}
|
||||
|
||||
void removeDesktop(IVirtualDesktop desktop, IVirtualDesktop fallback) {
|
||||
final code = (ptr.ref.vtable + 12)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<
|
||||
HRESULT Function(Pointer, COMObject, COMObject)>>>()
|
||||
.value
|
||||
.asFunction<int Function(Pointer, COMObject, COMObject)>()(
|
||||
ptr.ref.lpVtbl, desktop.ptr.ref, fallback.ptr.ref);
|
||||
if (code != 0) {
|
||||
throw WindowsException(code);
|
||||
}
|
||||
}
|
||||
|
||||
void setDesktopName(IVirtualDesktop desktop, String newName) {
|
||||
final code =
|
||||
(ptr.ref.vtable + 15)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<
|
||||
HRESULT Function(Pointer, COMObject, Int8)>>>()
|
||||
.value
|
||||
.asFunction<int Function(Pointer, COMObject, int)>()(
|
||||
ptr.ref.lpVtbl, desktop.ptr.ref, convertToHString(newName));
|
||||
if (code != 0) {
|
||||
throw WindowsException(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _IApplicationViewCollection extends IUnknown {
|
||||
static const String _CLSID = "{1841C6D7-4F9D-42C0-AF41-8747538F10E5}";
|
||||
static const String _IID = "{1841C6D7-4F9D-42C0-AF41-8747538F10E5}";
|
||||
|
||||
_IApplicationViewCollection._internal(super.ptr);
|
||||
|
||||
IApplicationView getViewForHWnd(int HWnd) {
|
||||
final result = calloc<COMObject>();
|
||||
final code =
|
||||
(ptr.ref.vtable + 6)
|
||||
.cast<
|
||||
Pointer<
|
||||
NativeFunction<
|
||||
HRESULT Function(
|
||||
Pointer, IntPtr, Pointer<COMObject>)>>>()
|
||||
.value
|
||||
.asFunction<int Function(Pointer, int, Pointer<COMObject>)>()(
|
||||
ptr.ref.lpVtbl, HWnd, result);
|
||||
if (code != 0) {
|
||||
free(result);
|
||||
throw WindowsException(code);
|
||||
}
|
||||
|
||||
return IApplicationView._internal(result);
|
||||
}
|
||||
}
|
||||
|
||||
final class _Process extends Struct {
|
||||
@Uint32()
|
||||
external int pid;
|
||||
|
||||
@Uint32()
|
||||
external int HWnd;
|
||||
|
||||
static int _filter(int HWnd, int lParam) {
|
||||
final structure = Pointer.fromAddress(lParam).cast<_Process>();
|
||||
final pidPointer = calloc<Uint32>();
|
||||
GetWindowThreadProcessId(HWnd, pidPointer);
|
||||
final pid = pidPointer.value;
|
||||
free(pidPointer);
|
||||
if (pid != structure.ref.pid) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
structure.ref.HWnd = HWnd;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int getHWndFromPid(int pid) {
|
||||
final result = calloc<_Process>();
|
||||
result.ref.pid = pid;
|
||||
EnumWindows(
|
||||
Pointer.fromFunction<EnumWindowsProc>(_filter, TRUE), result.address);
|
||||
final HWnd = result.ref.HWnd;
|
||||
calloc.free(result);
|
||||
return HWnd;
|
||||
}
|
||||
}
|
||||
|
||||
class VirtualDesktopManager {
|
||||
static VirtualDesktopManager? _instance;
|
||||
|
||||
final _IVirtualDesktopManagerInternal windowManager;
|
||||
final _IApplicationViewCollection applicationViewCollection;
|
||||
|
||||
VirtualDesktopManager._internal(this.windowManager, this.applicationViewCollection);
|
||||
|
||||
factory VirtualDesktopManager.getInstance() {
|
||||
if (_instance != null) {
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
final hr = CoInitializeEx(
|
||||
nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (FAILED(hr)) {
|
||||
throw WindowsException(hr);
|
||||
}
|
||||
|
||||
final shell = _ServiceProvider10.createInstance();
|
||||
final windowManager = _createWindowManager(shell);
|
||||
final applicationViewCollection = _IApplicationViewCollection._internal(
|
||||
shell.queryService(_IApplicationViewCollection._CLSID,
|
||||
_IApplicationViewCollection._IID));
|
||||
return _instance =
|
||||
VirtualDesktopManager._internal(windowManager, applicationViewCollection);
|
||||
}
|
||||
|
||||
static _IVirtualDesktopManagerInternal _createWindowManager(_ServiceProvider10 shell) {
|
||||
final build = windowsBuild;
|
||||
if(build == null || build < 19044) {
|
||||
return _IVirtualDesktopManagerInternal._internal(
|
||||
shell.queryService(_IVirtualDesktopManagerInternal._CLSID,
|
||||
_IVirtualDesktopManagerInternal._IID_WIN10));
|
||||
}else if(build >= 19044 && build < 22631) {
|
||||
return _IVirtualDesktopManagerInternal._internal(
|
||||
shell.queryService(_IVirtualDesktopManagerInternal._CLSID,
|
||||
_IVirtualDesktopManagerInternal._IID_WIN_21H2));
|
||||
}else if(build >= 22631 && build < 22631) {
|
||||
return _IVirtualDesktopManagerInternal._internal(
|
||||
shell.queryService(_IVirtualDesktopManagerInternal._CLSID,
|
||||
_IVirtualDesktopManagerInternal._IID_WIN_23H2));
|
||||
}else {
|
||||
return _IVirtualDesktopManagerInternal._internal(
|
||||
shell.queryService(_IVirtualDesktopManagerInternal._CLSID,
|
||||
_IVirtualDesktopManagerInternal._IID_WIN_23H2_3085));
|
||||
}
|
||||
}
|
||||
|
||||
int getDesktopsCount() => windowManager.getDesktopsCount();
|
||||
|
||||
List<IVirtualDesktop> getDesktops() => windowManager.getDesktops();
|
||||
|
||||
void moveWindowToDesktop(int pid, IVirtualDesktop desktop) {
|
||||
final HWnd = _Process.getHWndFromPid(pid);
|
||||
final window = applicationViewCollection.getViewForHWnd(HWnd);
|
||||
windowManager.moveWindowToDesktop(window, desktop);
|
||||
}
|
||||
|
||||
IVirtualDesktop createDesktop() => windowManager.createDesktop();
|
||||
|
||||
void removeDesktop(IVirtualDesktop desktop, [IVirtualDesktop? fallback]) {
|
||||
fallback ??= getDesktops().first;
|
||||
return windowManager.removeDesktop(desktop, fallback);
|
||||
}
|
||||
|
||||
void setDesktopName(IVirtualDesktop desktop, String newName) =>
|
||||
windowManager.setDesktopName(desktop, newName);
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import 'package:reboot_launcher/src/util/translations.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
Future<void> openYoutubeTutorial() => launchUrl(Uri.parse("https://www.youtube.com/watch?v=nrVE2RB0qa4"));
|
||||
|
||||
Future<void> openDiscordServer() => launchUrl(Uri.parse("https://discord.gg/reboot"));
|
||||
|
||||
Future<void> openTutorials() => launchUrl(Uri.parse("https://github.com/Auties00/reboot_launcher/blob/master/documentation/$currentLocale"));
|
||||
|
||||
Future<void> openPortTutorial() => launchUrl(Uri.parse("https://github.com/Auties00/reboot_launcher/blob/master/documentation/$currentLocale/PortForwarding.md"));
|
||||
|
||||
Future<void> openBugReport() => launchUrl(Uri.parse("https://github.com/Auties00/reboot_launcher/issues"));
|
||||
Reference in New Issue
Block a user