Files
parsec-vdd/app/CLI.cs
T
2024-11-05 13:28:43 +07:00

328 lines
11 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
namespace ParsecVDisplay
{
internal static class CLI
{
static StreamWriter _stdOutWriter;
public static int Execute(string[] args)
{
AttachConsole(-1);
if (args.Length > 0)
{
try
{
switch (args[0])
{
case "add":
return AddDisplay();
case "remove":
return RemoveDisplay(args);
case "list":
return ListDisplay();
case "set":
return SetDisplayMode(args);
case "status":
return QueryDriverStatus();
case "version":
return QueryDriverVersion();
case "help":
ShowHelp();
return 0;
default:
Console.WriteLine("Invalid command '{0}'", args[0]);
ShowHelp();
return 0;
}
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}", ex.Message);
#if DEBUG
Console.Error.WriteLine(ex.StackTrace);
#endif
return -1;
}
finally
{
ParsecVDD.Uninit();
}
}
else
{
ShowHelp();
return 0;
}
}
static Device.Status PrepareVdd()
{
var status = ParsecVDD.QueryStatus();
if (status == Device.Status.NOT_INSTALLED)
{
throw new Exception("The driver is not found, please install it first");
}
else if (status != Device.Status.OK)
{
throw new Exception($"The driver is not OK, got status {status}");
}
if (!ParsecVDD.Init())
{
throw new Exception("Failed to obtain the driver device handle");
}
return status;
}
static void CheckAppRunning()
{
if (!EventWaitHandle.TryOpenExisting(Program.AppId, out var _))
{
throw new Exception($"{Program.AppName} app is not running");
}
}
static int AddDisplay()
{
var displays = ParsecVDD.GetDisplays();
if (displays.Count >= ParsecVDD.MAX_DISPLAYS)
{
throw new Exception(string.Format("Exceeded limit ({0}), could not add more displays", ParsecVDD.MAX_DISPLAYS));
}
PrepareVdd();
CheckAppRunning();
if (ParsecVDD.AddDisplay(out int index))
{
Console.WriteLine($"Added a virtual display with index {0}.", index);
return index;
}
else
{
throw new Exception("Failed to add a virtual display.");
}
}
static int RemoveDisplay(string[] args)
{
var arg1 = args.Length >= 2 ? args[1] : "";
bool removeAll = arg1 == "all" || arg1 == "*";
int index = -1;
if (args.Length == 1 || removeAll || int.TryParse(arg1, out index))
{
var displays = ParsecVDD.GetDisplays();
if (displays.Count == 0)
{
Console.WriteLine("No Parsec Display available.");
return 0;
}
else if (removeAll)
{
PrepareVdd();
foreach (var di in displays)
{
if (!ParsecVDD.RemoveDisplay(di.DisplayIndex))
throw new Exception(string.Format("Failed to remove the display at index {0}.", index));
}
Console.WriteLine("Removed all added displays.");
return 0;
}
else
{
var display = index < 0 ? displays.LastOrDefault()
: displays.FirstOrDefault(di => di.DisplayIndex == index);
if (display != null)
{
PrepareVdd();
if (!ParsecVDD.RemoveDisplay(display.DisplayIndex))
throw new Exception(string.Format("Failed to remove the display at index {0}.", display.DisplayIndex));
Console.WriteLine("Removed display at index {0}.", display.DisplayIndex);
return 0;
}
else
{
throw new Exception(string.Format("Display index {0} is not found.", index));
}
}
}
else
{
throw new Exception(string.Format("Invalid display index '{0}'.", arg1));
}
}
static int ListDisplay()
{
var displays = ParsecVDD.GetDisplays();
if (displays.Count > 0)
{
foreach (var di in displays)
{
Console.WriteLine("Index: {0}", di.DisplayIndex);
Console.WriteLine(" - Device: {0}", di.DeviceName);
Console.WriteLine(" - Number: {0}", di.Identifier);
Console.WriteLine(" - Name: {0}", di.DisplayName);
Console.WriteLine(" - Mode: {0}", di.CurrentMode);
Console.WriteLine(" - Orientation: {0} ({1}°)", di.CurrentOrientation, (int)di.CurrentOrientation * 90);
}
}
else
{
Console.WriteLine("No Parsec Display available.");
}
return 0;
}
static int SetDisplayMode(string[] args)
{
if (args.Length < 2)
throw new Exception("Missing display index.");
if (args.Length < 3)
throw new Exception("Missing resolution and/or refresh rate.");
var argIndex = args[1];
var argDMode = string.Join(" ", args.Skip(2));
if (int.TryParse(argIndex, out int index))
{
var displays = ParsecVDD.GetDisplays();
if (displays.Count == 0)
{
Console.WriteLine("No Parsec Display available.");
return 0;
}
else
{
var display = displays.Find(di => di.DisplayIndex == index);
if (display == null)
throw new Exception(string.Format("Display index {0} is not found.", index));
int? width, height, hz;
ParseDisplayModeArg(argDMode, out width, out height, out hz);
if ((width != null && height != null) || hz != null)
{
if (display.ChangeMode(width, height, hz, null))
{
Console.WriteLine($"Display index {index} is set to '{argDMode}'.");
return 0;
}
else
{
throw new Exception($"Failed to set, display mode '{argDMode}' is not supported.");
}
}
else
{
throw new Exception("Nothing to do, recheck your syntax.");
}
}
}
else
{
throw new Exception(string.Format("Invalid display index '{0}'.", argIndex));
}
}
static int QueryDriverStatus()
{
var status = ParsecVDD.QueryStatus();
Console.WriteLine("The driver status is {0}", status);
return (int)status;
}
static int QueryDriverVersion()
{
PrepareVdd();
if (ParsecVDD.QueryVersion(out var version))
{
Console.WriteLine("{0} v{1}", ParsecVDD.ADAPTER, version);
return 0;
}
else
{
throw new Exception("Failed to query the driver version.");
}
}
static void ShowHelp()
{
Console.WriteLine("vdd-cli [command] [args...]");
Console.WriteLine(" add - Add a virtual display");
Console.WriteLine(" remove - Remove the last added virtual display");
Console.WriteLine(" X - Remove the virtual display at index X (number)");
Console.WriteLine(" all - Remove all the added virtual displays");
Console.WriteLine(" list - Show all the added virtual displays and specs");
Console.WriteLine(" set X WxH - Set resolution for a virtual display");
Console.WriteLine(" where X is index number, WxH is size, e.g 1920x1080");
Console.WriteLine(" X @R - Set only the refresh rate R, e.g @60, @120 (hz)");
Console.WriteLine(" on Powershell, you should replace '@' with 'r'");
Console.WriteLine(" X WxH@R - Set full display mode as above, e.g 1920x1080@144");
Console.WriteLine(" status - Query the driver status");
Console.WriteLine(" version - Query the driver version");
Console.WriteLine(" help - Show this help");
}
static void ParseDisplayModeArg(string arg, out int? width, out int? height, out int? hz)
{
Match match;
arg = arg.Trim();
width = null;
height = null;
hz = null;
const string regexSize = @"^(\d+)\s*[xX]\s*(\d+)$";
if (Regex.IsMatch(arg, regexSize))
{
match = Regex.Match(arg, regexSize);
width = int.Parse(match.Groups[1].Value);
height = int.Parse(match.Groups[2].Value);
return;
}
const string regexHz = @"^[r@](\d+)$";
if (Regex.IsMatch(arg, regexHz))
{
match = Regex.Match(arg, regexHz);
hz = int.Parse(match.Groups[1].Value);
return;
}
const string regexAll = @"^(\d+)\s*[xX]\s*(\d+)\s*[r@](\d+)$";
if (Regex.IsMatch(arg, regexAll))
{
match = Regex.Match(arg, regexAll);
width = int.Parse(match.Groups[1].Value);
height = int.Parse(match.Groups[2].Value);
hz = int.Parse(match.Groups[3].Value);
return;
}
}
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AttachConsole(int dwProcessId);
}
}