-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7d7b97f
commit 5772ed6
Showing
6 changed files
with
302 additions
and
139 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
using FancyMouse.Displays.DeviceManagement; | ||
using System.Diagnostics; | ||
using System.Management; | ||
|
||
namespace FancyMouse.Displays; | ||
|
||
public sealed class VirtualDisplayManager | ||
{ | ||
|
||
#region Constructors | ||
|
||
public VirtualDisplayManager(string rootFolder, string hardwareId) | ||
{ | ||
this.RootFolder = rootFolder ?? throw new ArgumentNullException(nameof(rootFolder)); | ||
this.HardwareId = hardwareId ?? throw new ArgumentNullException(nameof(hardwareId)); | ||
} | ||
|
||
#endregion | ||
|
||
#region Properties | ||
|
||
public string RootFolder | ||
{ | ||
get; | ||
} | ||
|
||
public string HardwareId | ||
{ | ||
get; | ||
} | ||
|
||
#endregion | ||
|
||
#region Display Driver | ||
|
||
/// <summary> | ||
/// Checks if the Amyuni Technologies USB Mobile Monitor Virtual Display driver is installed. | ||
/// </summary> | ||
public Dictionary<string, object>? GetDisplayDriver() | ||
{ | ||
var drivers = VirtualDisplayManager.GetManagementObjects( | ||
string.Join(" ", | ||
$"SELECT * FROM Win32_PnPSignedDriver", | ||
$"WHERE ClassGuid='{DeviceClassGuids.Display}'", | ||
$"AND Manufacturer='Amyuni'", | ||
$"AND DeviceName='USB Mobile Monitor Virtual Display'", | ||
$"AND HardWareID='{this.HardwareId}'" | ||
) | ||
).ToList(); | ||
return drivers.SingleOrDefault(); | ||
} | ||
|
||
/// <summary> | ||
/// </summary> | ||
/// <returns></returns> | ||
public void InstallDisplayDriver() | ||
{ | ||
this.ExecuteDeviceInstallerCommand( | ||
new List<string> | ||
{ | ||
"install", | ||
Path.Combine(this.RootFolder, "usbmmidd.inf"), | ||
this.HardwareId | ||
} | ||
); | ||
} | ||
|
||
/// <summary> | ||
/// </summary> | ||
/// <returns></returns> | ||
public void UninstallDisplayDriver() | ||
{ | ||
this.ExecuteDeviceInstallerCommand( | ||
new List<string> { "stop", this.HardwareId } | ||
); | ||
this.ExecuteDeviceInstallerCommand( | ||
new List<string> { "remove", this.HardwareId } | ||
); | ||
} | ||
|
||
#endregion | ||
|
||
#region Display Adapter | ||
|
||
public Dictionary<string, object>? GetDisplayAdapter() | ||
{ | ||
var devices = VirtualDisplayManager.GetManagementObjects( | ||
string.Join(" ", | ||
$"SELECT * FROM Win32_PnPEntity", | ||
$"WHERE ClassGuid='{DeviceClassGuids.Display}'", | ||
$"AND Manufacturer='Amyuni'", | ||
$"AND Name='USB Mobile Monitor Virtual Display'" | ||
//$"AND HardWareID='{this.HardwareId}'" | ||
) | ||
).Where( | ||
device => (device["HardwareID"] is string[] hardwareIds) && (hardwareIds?.Contains(this.HardwareId) ?? false) | ||
).OrderBy(d => d["Name"]) | ||
.ToList(); | ||
return devices.SingleOrDefault(); | ||
} | ||
|
||
#endregion | ||
|
||
#region Helpers | ||
|
||
private static List<Dictionary<string, object>> GetManagementObjects(string query) | ||
{ | ||
return new ManagementObjectSearcher(query).Get() | ||
.Cast<ManagementObject>() | ||
.Select( | ||
obj => obj.Properties | ||
.Cast<PropertyData>() | ||
.OrderBy(p => p.Name) | ||
.ToDictionary( | ||
p => p.Name, | ||
p => p.Value | ||
) | ||
).ToList(); | ||
} | ||
|
||
public int ExecuteDeviceInstallerCommand(IEnumerable<string> args) | ||
{ | ||
var startInfo = new ProcessStartInfo | ||
{ | ||
FileName = Path.Combine(this.RootFolder, "deviceinstaller64.exe"), | ||
UseShellExecute = true, | ||
Verb = "RunAs" | ||
}; | ||
foreach(var arg in args) | ||
{ | ||
startInfo.ArgumentList.Add(arg); | ||
} | ||
var process = Process.Start(startInfo) ?? throw new InvalidOperationException(); | ||
process.WaitForExit(); | ||
var exitcode = process.ExitCode; | ||
if (exitcode != 0) | ||
{ | ||
throw new InvalidOperationException( | ||
$"installer failed with exit code {exitcode}" | ||
); | ||
} | ||
return exitcode; | ||
} | ||
|
||
#endregion | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using System.Drawing; | ||
using FancyMouse.Drawing.Models; | ||
using FancyMouse.Helpers; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
||
namespace FancyMouse.UnitTests.Helpers; | ||
|
||
[TestClass] | ||
public static class MouseHelperTests | ||
{ | ||
[TestClass] | ||
public class GetJumpLocationTests | ||
{ | ||
public class TestCase | ||
{ | ||
public TestCase(PointInfo previewLocation, SizeInfo previewSize, RectangleInfo desktopBounds, PointInfo expectedResult) | ||
{ | ||
this.PreviewLocation = previewLocation; | ||
this.PreviewSize = previewSize; | ||
this.DesktopBounds = desktopBounds; | ||
this.ExpectedResult = expectedResult; | ||
} | ||
|
||
public PointInfo PreviewLocation { get; set; } | ||
|
||
public SizeInfo PreviewSize { get; set; } | ||
|
||
public RectangleInfo DesktopBounds { get; set; } | ||
|
||
public PointInfo ExpectedResult { get; set; } | ||
} | ||
|
||
public static IEnumerable<object[]> GetTestCases() | ||
{ | ||
// corners and midpoint with a zero origin | ||
yield return new[] { new TestCase(new(0, 0), new(160, 120), new(0, 0, 1600, 1200), new(0, 0)) }; | ||
yield return new[] { new TestCase(new(160, 0), new(160, 120), new(0, 0, 1600, 1200), new(1600, 0)) }; | ||
yield return new[] { new TestCase(new(0, 120), new(160, 120), new(0, 0, 1600, 1200), new(0, 1200)) }; | ||
yield return new[] { new TestCase(new(160, 120), new(160, 120), new(0, 0, 1600, 1200), new(1600, 1200)) }; | ||
yield return new[] { new TestCase(new(80, 60), new(160, 120), new(0, 0, 1600, 1200), new(800, 600)) }; | ||
|
||
// corners and midpoint with a positive origin | ||
yield return new[] { new TestCase(new(0, 0), new(160, 120), new(1000, 1000, 1600, 1200), new(1000, 1000)) }; | ||
yield return new[] { new TestCase(new(160, 0), new(160, 120), new(1000, 1000, 1600, 1200), new(2600, 1000)) }; | ||
yield return new[] { new TestCase(new(0, 120), new(160, 120), new(1000, 1000, 1600, 1200), new(1000, 2200)) }; | ||
yield return new[] { new TestCase(new(160, 120), new(160, 120), new(1000, 1000, 1600, 1200), new(2600, 2200)) }; | ||
yield return new[] { new TestCase(new(80, 60), new(160, 120), new(1000, 1000, 1600, 1200), new(1800, 1600)) }; | ||
|
||
// corners and midpoint with a negative origin | ||
yield return new[] { new TestCase(new(0, 0), new(160, 120), new(-1000, -1000, 1600, 1200), new(-1000, -1000)) }; | ||
yield return new[] { new TestCase(new(160, 0), new(160, 120), new(-1000, -1000, 1600, 1200), new(600, -1000)) }; | ||
yield return new[] { new TestCase(new(0, 120), new(160, 120), new(-1000, -1000, 1600, 1200), new(-1000, 200)) }; | ||
yield return new[] { new TestCase(new(160, 120), new(160, 120), new(-1000, -1000, 1600, 1200), new(600, 200)) }; | ||
yield return new[] { new TestCase(new(80, 60), new(160, 120), new(-1000, -1000, 1600, 1200), new(-200, -400)) }; | ||
} | ||
|
||
[TestMethod] | ||
[DynamicData(nameof(GetTestCases), DynamicDataSourceType.Method)] | ||
public void RunTestCases(TestCase data) | ||
{ | ||
var actual = MouseHelper.GetJumpLocation( | ||
data.PreviewLocation, | ||
data.PreviewSize, | ||
data.DesktopBounds); | ||
var expected = data.ExpectedResult; | ||
Assert.AreEqual(expected.X, actual.X); | ||
Assert.AreEqual(expected.Y, actual.Y); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.