mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
use common
This commit is contained in:
133
src/modules/fancyzones/FancyZonesCLI/FancyZonesData.cs
Normal file
133
src/modules/fancyzones/FancyZonesCLI/FancyZonesData.cs
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
|
||||||
|
namespace FancyZonesCLI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods to read and write FancyZones configuration data.
|
||||||
|
/// </summary>
|
||||||
|
internal static class FancyZonesData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Try to read applied layouts configuration.
|
||||||
|
/// </summary>
|
||||||
|
public static bool TryReadAppliedLayouts(out AppliedLayouts result, out string error)
|
||||||
|
{
|
||||||
|
return TryReadJsonFile(FancyZonesPaths.AppliedLayouts, FancyZonesJsonContext.Default.AppliedLayouts, out result, out error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read applied layouts or return null if not found.
|
||||||
|
/// </summary>
|
||||||
|
public static AppliedLayouts ReadAppliedLayouts()
|
||||||
|
{
|
||||||
|
return ReadJsonFileOrDefault(FancyZonesPaths.AppliedLayouts, FancyZonesJsonContext.Default.AppliedLayouts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write applied layouts configuration.
|
||||||
|
/// </summary>
|
||||||
|
public static void WriteAppliedLayouts(AppliedLayouts layouts)
|
||||||
|
{
|
||||||
|
WriteJsonFile(FancyZonesPaths.AppliedLayouts, layouts, FancyZonesJsonContext.Default.AppliedLayouts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read custom layouts or return null if not found.
|
||||||
|
/// </summary>
|
||||||
|
public static CustomLayouts ReadCustomLayouts()
|
||||||
|
{
|
||||||
|
return ReadJsonFileOrDefault(FancyZonesPaths.CustomLayouts, FancyZonesJsonContext.Default.CustomLayouts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read layout templates or return null if not found.
|
||||||
|
/// </summary>
|
||||||
|
public static LayoutTemplates ReadLayoutTemplates()
|
||||||
|
{
|
||||||
|
return ReadJsonFileOrDefault(FancyZonesPaths.LayoutTemplates, FancyZonesJsonContext.Default.LayoutTemplates);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Read layout hotkeys or return null if not found.
|
||||||
|
/// </summary>
|
||||||
|
public static LayoutHotkeys ReadLayoutHotkeys()
|
||||||
|
{
|
||||||
|
return ReadJsonFileOrDefault(FancyZonesPaths.LayoutHotkeys, FancyZonesJsonContext.Default.LayoutHotkeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write layout hotkeys configuration.
|
||||||
|
/// </summary>
|
||||||
|
public static void WriteLayoutHotkeys(LayoutHotkeys hotkeys)
|
||||||
|
{
|
||||||
|
WriteJsonFile(FancyZonesPaths.LayoutHotkeys, hotkeys, FancyZonesJsonContext.Default.LayoutHotkeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if editor parameters file exists.
|
||||||
|
/// </summary>
|
||||||
|
public static bool EditorParametersExist()
|
||||||
|
{
|
||||||
|
return File.Exists(FancyZonesPaths.EditorParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryReadJsonFile<T>(string filePath, JsonTypeInfo<T> jsonTypeInfo, out T result, out string error)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
error = null;
|
||||||
|
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
error = $"File not found: {Path.GetFileName(filePath)}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(filePath);
|
||||||
|
result = JsonSerializer.Deserialize(json, jsonTypeInfo);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
error = $"Failed to parse {Path.GetFileName(filePath)}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
error = $"JSON parse error in {Path.GetFileName(filePath)}: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
error = $"Failed to read {Path.GetFileName(filePath)}: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static T ReadJsonFileOrDefault<T>(string filePath, JsonTypeInfo<T> jsonTypeInfo, T defaultValue = null)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
if (TryReadJsonFile(filePath, jsonTypeInfo, out var result, out _))
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteJsonFile<T>(string filePath, T data, JsonTypeInfo<T> jsonTypeInfo)
|
||||||
|
{
|
||||||
|
var json = JsonSerializer.Serialize(data, jsonTypeInfo);
|
||||||
|
File.WriteAllText(filePath, json);
|
||||||
|
}
|
||||||
|
}
|
||||||
30
src/modules/fancyzones/FancyZonesCLI/FancyZonesPaths.cs
Normal file
30
src/modules/fancyzones/FancyZonesCLI/FancyZonesPaths.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace FancyZonesCLI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides paths to FancyZones configuration files.
|
||||||
|
/// </summary>
|
||||||
|
internal static class FancyZonesPaths
|
||||||
|
{
|
||||||
|
private static readonly string DataPath = Path.Combine(
|
||||||
|
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||||
|
"Microsoft",
|
||||||
|
"PowerToys",
|
||||||
|
"FancyZones");
|
||||||
|
|
||||||
|
public static string AppliedLayouts => Path.Combine(DataPath, "applied-layouts.json");
|
||||||
|
|
||||||
|
public static string CustomLayouts => Path.Combine(DataPath, "custom-layouts.json");
|
||||||
|
|
||||||
|
public static string LayoutTemplates => Path.Combine(DataPath, "layout-templates.json");
|
||||||
|
|
||||||
|
public static string LayoutHotkeys => Path.Combine(DataPath, "layout-hotkeys.json");
|
||||||
|
|
||||||
|
public static string EditorParameters => Path.Combine(DataPath, "editor-parameters.json");
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
@@ -12,20 +12,21 @@ namespace FancyZonesCLI;
|
|||||||
|
|
||||||
public static class LayoutVisualizer
|
public static class LayoutVisualizer
|
||||||
{
|
{
|
||||||
public static void DrawTemplateLayout(TemplateLayout template)
|
public static string DrawTemplateLayout(TemplateLayout template)
|
||||||
{
|
{
|
||||||
Console.WriteLine(" Visual Preview:");
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine(" Visual Preview:");
|
||||||
|
|
||||||
switch (template.Type.ToLowerInvariant())
|
switch (template.Type.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "focus":
|
case "focus":
|
||||||
DrawFocusLayout(template.ZoneCount > 0 ? template.ZoneCount : 3);
|
sb.Append(RenderFocusLayout(template.ZoneCount > 0 ? template.ZoneCount : 3));
|
||||||
break;
|
break;
|
||||||
case "columns":
|
case "columns":
|
||||||
DrawGridLayout(1, template.ZoneCount > 0 ? template.ZoneCount : 3);
|
sb.Append(RenderGridLayout(1, template.ZoneCount > 0 ? template.ZoneCount : 3));
|
||||||
break;
|
break;
|
||||||
case "rows":
|
case "rows":
|
||||||
DrawGridLayout(template.ZoneCount > 0 ? template.ZoneCount : 3, 1);
|
sb.Append(RenderGridLayout(template.ZoneCount > 0 ? template.ZoneCount : 3, 1));
|
||||||
break;
|
break;
|
||||||
case "grid":
|
case "grid":
|
||||||
// Grid layout: calculate rows and columns from zone count
|
// Grid layout: calculate rows and columns from zone count
|
||||||
@@ -45,28 +46,31 @@ public static class LayoutVisualizer
|
|||||||
cols++;
|
cols++;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawGridLayoutWithZoneCount(rows, cols, zoneCount);
|
sb.Append(RenderGridLayoutWithZoneCount(rows, cols, zoneCount));
|
||||||
break;
|
break;
|
||||||
case "priority-grid":
|
case "priority-grid":
|
||||||
DrawPriorityGridLayout(template.ZoneCount > 0 ? template.ZoneCount : 3);
|
sb.Append(RenderPriorityGridLayout(template.ZoneCount > 0 ? template.ZoneCount : 3));
|
||||||
break;
|
break;
|
||||||
case "blank":
|
case "blank":
|
||||||
Console.WriteLine(" (No zones)");
|
sb.AppendLine(" (No zones)");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Console.WriteLine($" ({template.Type} layout)");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" ({template.Type} layout)");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DrawCustomLayout(CustomLayout layout)
|
public static string DrawCustomLayout(CustomLayout layout)
|
||||||
{
|
{
|
||||||
if (layout.Info.ValueKind == JsonValueKind.Undefined || layout.Info.ValueKind == JsonValueKind.Null)
|
if (layout.Info.ValueKind == JsonValueKind.Undefined || layout.Info.ValueKind == JsonValueKind.Null)
|
||||||
{
|
{
|
||||||
return;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(" Visual Preview:");
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine(" Visual Preview:");
|
||||||
|
|
||||||
if (layout.Type == "grid" &&
|
if (layout.Type == "grid" &&
|
||||||
layout.Info.TryGetProperty("rows", out var rows) &&
|
layout.Info.TryGetProperty("rows", out var rows) &&
|
||||||
@@ -78,12 +82,12 @@ public static class LayoutVisualizer
|
|||||||
// Check if there's a cell-child-map (merged cells)
|
// Check if there's a cell-child-map (merged cells)
|
||||||
if (layout.Info.TryGetProperty("cell-child-map", out var cellMap))
|
if (layout.Info.TryGetProperty("cell-child-map", out var cellMap))
|
||||||
{
|
{
|
||||||
DrawGridLayoutWithMergedCells(r, c, cellMap);
|
sb.Append(RenderGridLayoutWithMergedCells(r, c, cellMap));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int height = r >= 4 ? 12 : 8;
|
int height = r >= 4 ? 12 : 8;
|
||||||
DrawGridLayout(r, c, 30, height);
|
sb.Append(RenderGridLayout(r, c, 30, height));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (layout.Type == "canvas" &&
|
else if (layout.Type == "canvas" &&
|
||||||
@@ -91,60 +95,61 @@ public static class LayoutVisualizer
|
|||||||
layout.Info.TryGetProperty("ref-width", out var refWidth) &&
|
layout.Info.TryGetProperty("ref-width", out var refWidth) &&
|
||||||
layout.Info.TryGetProperty("ref-height", out var refHeight))
|
layout.Info.TryGetProperty("ref-height", out var refHeight))
|
||||||
{
|
{
|
||||||
DrawCanvasLayout(zones, refWidth.GetInt32(), refHeight.GetInt32());
|
sb.Append(RenderCanvasLayout(zones, refWidth.GetInt32(), refHeight.GetInt32()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawFocusLayout(int zoneCount = 3)
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string RenderFocusLayout(int zoneCount = 3)
|
||||||
{
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
// Focus layout: overlapping zones with cascading offset
|
// Focus layout: overlapping zones with cascading offset
|
||||||
// Show first 2, ellipsis, and last 1 if more than 4 zones
|
|
||||||
if (zoneCount == 1)
|
if (zoneCount == 1)
|
||||||
{
|
{
|
||||||
Console.WriteLine(" +-------+");
|
sb.AppendLine(" +-------+");
|
||||||
Console.WriteLine(" | |");
|
sb.AppendLine(" | |");
|
||||||
Console.WriteLine(" | |");
|
sb.AppendLine(" | |");
|
||||||
Console.WriteLine(" +-------+");
|
sb.AppendLine(" +-------+");
|
||||||
}
|
}
|
||||||
else if (zoneCount == 2)
|
else if (zoneCount == 2)
|
||||||
{
|
{
|
||||||
Console.WriteLine(" +-------+");
|
sb.AppendLine(" +-------+");
|
||||||
Console.WriteLine(" | |");
|
sb.AppendLine(" | |");
|
||||||
Console.WriteLine(" | +-------+");
|
sb.AppendLine(" | +-------+");
|
||||||
Console.WriteLine(" +-| |");
|
sb.AppendLine(" +-| |");
|
||||||
Console.WriteLine(" | |");
|
sb.AppendLine(" | |");
|
||||||
Console.WriteLine(" +-------+");
|
sb.AppendLine(" +-------+");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine(" +-------+");
|
sb.AppendLine(" +-------+");
|
||||||
Console.WriteLine(" | |");
|
sb.AppendLine(" | |");
|
||||||
Console.WriteLine(" | +-------+");
|
sb.AppendLine(" | +-------+");
|
||||||
Console.WriteLine(" +-| |");
|
sb.AppendLine(" +-| |");
|
||||||
Console.WriteLine(" | +-------+");
|
sb.AppendLine(" | +-------+");
|
||||||
Console.WriteLine(" +-| |");
|
sb.AppendLine(" +-| |");
|
||||||
|
sb.AppendLine(" ...");
|
||||||
// Middle ellipsis
|
sb.AppendLine(CultureInfo.InvariantCulture, $" (total: {zoneCount} zones)");
|
||||||
Console.WriteLine(" ...");
|
sb.AppendLine(" ...");
|
||||||
Console.WriteLine($" (total: {zoneCount} zones)");
|
sb.AppendLine(" | +-------+");
|
||||||
Console.WriteLine(" ...");
|
sb.AppendLine(" +-| |");
|
||||||
|
sb.AppendLine(" | |");
|
||||||
// Show indication of last zone (without full indent)
|
sb.AppendLine(" +-------+");
|
||||||
Console.WriteLine(" | +-------+");
|
|
||||||
Console.WriteLine(" +-| |");
|
|
||||||
Console.WriteLine(" | |");
|
|
||||||
Console.WriteLine(" +-------+");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawPriorityGridLayout(int zoneCount = 3)
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string RenderPriorityGridLayout(int zoneCount = 3)
|
||||||
{
|
{
|
||||||
// Priority Grid has predefined layouts for zone counts 1-11
|
// Priority Grid has predefined layouts for zone counts 1-11
|
||||||
// Data format from GridLayoutModel._priorityData
|
// Data format from GridLayoutModel._priorityData
|
||||||
if (zoneCount >= 1 && zoneCount <= 11)
|
if (zoneCount >= 1 && zoneCount <= 11)
|
||||||
{
|
{
|
||||||
int[,] cellMap = GetPriorityGridCellMap(zoneCount);
|
int[,] cellMap = GetPriorityGridCellMap(zoneCount);
|
||||||
DrawGridLayoutWithCellMap(cellMap);
|
return RenderGridLayoutWithCellMap(cellMap);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -162,7 +167,7 @@ public static class LayoutVisualizer
|
|||||||
cols++;
|
cols++;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawGridLayoutWithZoneCount(rows, cols, zoneCount);
|
return RenderGridLayoutWithZoneCount(rows, cols, zoneCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,8 +191,9 @@ public static class LayoutVisualizer
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawGridLayoutWithCellMap(int[,] cellMap, int width = 30, int height = 8)
|
private static string RenderGridLayoutWithCellMap(int[,] cellMap, int width = 30, int height = 8)
|
||||||
{
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
int rows = cellMap.GetLength(0);
|
int rows = cellMap.GetLength(0);
|
||||||
int cols = cellMap.GetLength(1);
|
int cols = cellMap.GetLength(1);
|
||||||
|
|
||||||
@@ -197,79 +203,54 @@ public static class LayoutVisualizer
|
|||||||
for (int r = 0; r < rows; r++)
|
for (int r = 0; r < rows; r++)
|
||||||
{
|
{
|
||||||
// Top border
|
// Top border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
// Check if this cell should merge with the cell above
|
|
||||||
bool mergeTop = r > 0 && cellMap[r, c] == cellMap[r - 1, c];
|
bool mergeTop = r > 0 && cellMap[r, c] == cellMap[r - 1, c];
|
||||||
|
|
||||||
// Check if this cell should merge with the cell to the left
|
|
||||||
bool mergeLeft = c > 0 && cellMap[r, c] == cellMap[r, c - 1];
|
bool mergeLeft = c > 0 && cellMap[r, c] == cellMap[r, c - 1];
|
||||||
|
|
||||||
if (mergeTop)
|
if (mergeTop)
|
||||||
{
|
{
|
||||||
if (mergeLeft)
|
sb.Append(mergeLeft ? new string(' ', cellWidth) : new string(' ', cellWidth - 1) + "+");
|
||||||
{
|
|
||||||
Console.Write(new string(' ', cellWidth));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.Write(new string(' ', cellWidth - 1));
|
sb.Append(mergeLeft ? new string('-', cellWidth) : new string('-', cellWidth - 1) + "+");
|
||||||
Console.Write("+");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (mergeLeft)
|
|
||||||
{
|
|
||||||
Console.Write(new string('-', cellWidth));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.Write(new string('-', cellWidth - 1));
|
|
||||||
Console.Write("+");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
// Cell content
|
// Cell content
|
||||||
for (int h = 0; h < cellHeight - 1; h++)
|
for (int h = 0; h < cellHeight - 1; h++)
|
||||||
{
|
{
|
||||||
Console.Write(" ");
|
sb.Append(" ");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
bool mergeLeft = c > 0 && cellMap[r, c] == cellMap[r, c - 1];
|
bool mergeLeft = c > 0 && cellMap[r, c] == cellMap[r, c - 1];
|
||||||
if (mergeLeft)
|
sb.Append(mergeLeft ? ' ' : '|');
|
||||||
{
|
sb.Append(' ', cellWidth - 1);
|
||||||
Console.Write(" ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.Write("|");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.Write(new string(' ', cellWidth - 1));
|
sb.AppendLine("|");
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("|");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom border
|
// Bottom border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
Console.Write(new string('-', cellWidth - 1));
|
sb.Append('-', cellWidth - 1);
|
||||||
Console.Write("+");
|
sb.Append('+');
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawGridLayoutWithMergedCells(int rows, int cols, JsonElement cellMap)
|
private static string RenderGridLayoutWithMergedCells(int rows, int cols, JsonElement cellMap)
|
||||||
{
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
const int displayWidth = 39;
|
const int displayWidth = 39;
|
||||||
const int displayHeight = 12;
|
const int displayHeight = 12;
|
||||||
|
|
||||||
@@ -284,45 +265,20 @@ public static class LayoutVisualizer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find unique zones and their count
|
|
||||||
var zones = new HashSet<int>();
|
|
||||||
for (int r = 0; r < rows; r++)
|
|
||||||
{
|
|
||||||
for (int c = 0; c < cols; c++)
|
|
||||||
{
|
|
||||||
zones.Add(zoneMap[r, c]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int cellHeight = displayHeight / rows;
|
int cellHeight = displayHeight / rows;
|
||||||
int cellWidth = displayWidth / cols;
|
int cellWidth = displayWidth / cols;
|
||||||
|
|
||||||
// Draw top border
|
// Draw top border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
Console.Write(new string('-', displayWidth));
|
sb.Append('-', displayWidth);
|
||||||
Console.WriteLine("+");
|
sb.AppendLine("+");
|
||||||
|
|
||||||
// Draw rows
|
// Draw rows
|
||||||
for (int r = 0; r < rows; r++)
|
for (int r = 0; r < rows; r++)
|
||||||
{
|
{
|
||||||
// For each row, find the column range of each zone
|
|
||||||
var zoneRanges = new Dictionary<int, (int Start, int End)>();
|
|
||||||
for (int c = 0; c < cols; c++)
|
|
||||||
{
|
|
||||||
int zone = zoneMap[r, c];
|
|
||||||
if (zoneRanges.TryGetValue(zone, out var range))
|
|
||||||
{
|
|
||||||
zoneRanges[zone] = (range.Start, c);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
zoneRanges[zone] = (c, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int h = 0; h < cellHeight; h++)
|
for (int h = 0; h < cellHeight; h++)
|
||||||
{
|
{
|
||||||
Console.Write(" |");
|
sb.Append(" |");
|
||||||
|
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
@@ -330,47 +286,35 @@ public static class LayoutVisualizer
|
|||||||
int leftZone = c > 0 ? zoneMap[r, c - 1] : -1;
|
int leftZone = c > 0 ? zoneMap[r, c - 1] : -1;
|
||||||
bool needLeftBorder = c > 0 && currentZone != leftZone;
|
bool needLeftBorder = c > 0 && currentZone != leftZone;
|
||||||
|
|
||||||
// Check if this zone has a top border
|
bool zoneHasTopBorder = r > 0 && h == 0 && currentZone != zoneMap[r - 1, c];
|
||||||
bool zoneHasTopBorder = false;
|
|
||||||
if (r > 0 && h == 0)
|
|
||||||
{
|
|
||||||
int topZone = zoneMap[r - 1, c];
|
|
||||||
zoneHasTopBorder = currentZone != topZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw left border if needed
|
|
||||||
if (needLeftBorder)
|
if (needLeftBorder)
|
||||||
{
|
{
|
||||||
Console.Write("|");
|
sb.Append('|');
|
||||||
|
sb.Append(zoneHasTopBorder ? '-' : ' ', cellWidth - 1);
|
||||||
// Fill rest of cell
|
|
||||||
for (int w = 1; w < cellWidth; w++)
|
|
||||||
{
|
|
||||||
Console.Write(zoneHasTopBorder ? "-" : " ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No left border, fill entire cell
|
sb.Append(zoneHasTopBorder ? '-' : ' ', cellWidth);
|
||||||
for (int w = 0; w < cellWidth; w++)
|
|
||||||
{
|
|
||||||
Console.Write(zoneHasTopBorder ? "-" : " ");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("|");
|
sb.AppendLine("|");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw bottom border
|
// Draw bottom border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
Console.Write(new string('-', displayWidth));
|
sb.Append('-', displayWidth);
|
||||||
Console.WriteLine("+");
|
sb.AppendLine("+");
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DrawGridLayoutWithZoneCount(int rows, int cols, int zoneCount, int width = 30, int height = 8)
|
public static string RenderGridLayoutWithZoneCount(int rows, int cols, int zoneCount, int width = 30, int height = 8)
|
||||||
{
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
// Build zone map like Editor's InitGrid
|
// Build zone map like Editor's InitGrid
|
||||||
int[,] zoneMap = new int[rows, cols];
|
int[,] zoneMap = new int[rows, cols];
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@@ -392,103 +336,93 @@ public static class LayoutVisualizer
|
|||||||
for (int r = 0; r < rows; r++)
|
for (int r = 0; r < rows; r++)
|
||||||
{
|
{
|
||||||
// Top border
|
// Top border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
// Check if this cell should merge with the previous one (same zone)
|
|
||||||
bool mergeLeft = c > 0 && zoneMap[r, c] == zoneMap[r, c - 1];
|
bool mergeLeft = c > 0 && zoneMap[r, c] == zoneMap[r, c - 1];
|
||||||
if (mergeLeft)
|
sb.Append('-', mergeLeft ? cellWidth : cellWidth - 1);
|
||||||
|
if (!mergeLeft)
|
||||||
{
|
{
|
||||||
Console.Write(new string('-', cellWidth));
|
sb.Append('+');
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.Write(new string('-', cellWidth - 1));
|
|
||||||
Console.Write("+");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
// Cell content
|
// Cell content
|
||||||
for (int h = 0; h < cellHeight - 1; h++)
|
for (int h = 0; h < cellHeight - 1; h++)
|
||||||
{
|
{
|
||||||
Console.Write(" ");
|
sb.Append(" ");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
// Check if this cell should merge with the previous one
|
|
||||||
bool mergeLeft = c > 0 && zoneMap[r, c] == zoneMap[r, c - 1];
|
bool mergeLeft = c > 0 && zoneMap[r, c] == zoneMap[r, c - 1];
|
||||||
if (mergeLeft)
|
sb.Append(mergeLeft ? ' ' : '|');
|
||||||
{
|
sb.Append(' ', cellWidth - 1);
|
||||||
Console.Write(" ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.Write("|");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.Write(new string(' ', cellWidth - 1));
|
sb.AppendLine("|");
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("|");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom border
|
// Bottom border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
Console.Write(new string('-', cellWidth - 1));
|
sb.Append('-', cellWidth - 1);
|
||||||
Console.Write("+");
|
sb.Append('+');
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DrawGridLayout(int rows, int cols, int width = 30, int height = 8)
|
public static string RenderGridLayout(int rows, int cols, int width = 30, int height = 8)
|
||||||
{
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
int cellWidth = width / cols;
|
int cellWidth = width / cols;
|
||||||
int cellHeight = height / rows;
|
int cellHeight = height / rows;
|
||||||
|
|
||||||
for (int r = 0; r < rows; r++)
|
for (int r = 0; r < rows; r++)
|
||||||
{
|
{
|
||||||
// Top border
|
// Top border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
Console.Write(new string('-', cellWidth - 1));
|
sb.Append('-', cellWidth - 1);
|
||||||
Console.Write("+");
|
sb.Append('+');
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
// Cell content
|
// Cell content
|
||||||
for (int h = 0; h < cellHeight - 1; h++)
|
for (int h = 0; h < cellHeight - 1; h++)
|
||||||
{
|
{
|
||||||
Console.Write(" ");
|
sb.Append(" ");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
Console.Write("|");
|
sb.Append('|');
|
||||||
Console.Write(new string(' ', cellWidth - 1));
|
sb.Append(' ', cellWidth - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("|");
|
sb.AppendLine("|");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom border
|
// Bottom border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
for (int c = 0; c < cols; c++)
|
for (int c = 0; c < cols; c++)
|
||||||
{
|
{
|
||||||
Console.Write(new string('-', cellWidth - 1));
|
sb.Append('-', cellWidth - 1);
|
||||||
Console.Write("+");
|
sb.Append('+');
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DrawCanvasLayout(JsonElement zones, int refWidth, int refHeight)
|
private static string RenderCanvasLayout(JsonElement zones, int refWidth, int refHeight)
|
||||||
{
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
const int displayWidth = 49;
|
const int displayWidth = 49;
|
||||||
const int displayHeight = 15;
|
const int displayHeight = 15;
|
||||||
|
|
||||||
@@ -518,7 +452,6 @@ public static class LayoutVisualizer
|
|||||||
int dw = Math.Max(3, w * displayWidth / refWidth);
|
int dw = Math.Max(3, w * displayWidth / refWidth);
|
||||||
int dh = Math.Max(2, h * displayHeight / refHeight);
|
int dh = Math.Max(2, h * displayHeight / refHeight);
|
||||||
|
|
||||||
// Clamp to display bounds
|
|
||||||
if (dx + dw > displayWidth)
|
if (dx + dw > displayWidth)
|
||||||
{
|
{
|
||||||
dw = displayWidth - dx;
|
dw = displayWidth - dx;
|
||||||
@@ -531,7 +464,6 @@ public static class LayoutVisualizer
|
|||||||
|
|
||||||
zoneList.Add((dx, dy, dw, dh, zoneId));
|
zoneList.Add((dx, dy, dw, dh, zoneId));
|
||||||
|
|
||||||
// Fill the grid for this zone
|
|
||||||
for (int r = dy; r < dy + dh && r < displayHeight; r++)
|
for (int r = dy; r < dy + dh && r < displayHeight; r++)
|
||||||
{
|
{
|
||||||
for (int c = dx; c < dx + dw && c < displayWidth; c++)
|
for (int c = dx; c < dx + dw && c < displayWidth; c++)
|
||||||
@@ -544,82 +476,75 @@ public static class LayoutVisualizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw top border
|
// Draw top border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
Console.Write(new string('-', displayWidth));
|
sb.Append('-', displayWidth);
|
||||||
Console.WriteLine("+");
|
sb.AppendLine("+");
|
||||||
|
|
||||||
// Draw each row
|
// Draw each row
|
||||||
|
char[] shades = { '.', ':', '░', '▒', '▓', '█', '◆', '●', '■', '▪' };
|
||||||
|
|
||||||
for (int r = 0; r < displayHeight; r++)
|
for (int r = 0; r < displayHeight; r++)
|
||||||
{
|
{
|
||||||
Console.Write(" |");
|
sb.Append(" |");
|
||||||
for (int c = 0; c < displayWidth; c++)
|
for (int c = 0; c < displayWidth; c++)
|
||||||
{
|
{
|
||||||
var zonesHere = zoneGrid[r, c];
|
var zonesHere = zoneGrid[r, c];
|
||||||
|
|
||||||
if (zonesHere.Count == 0)
|
if (zonesHere.Count == 0)
|
||||||
{
|
{
|
||||||
Console.Write(" ");
|
sb.Append(' ');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Get the topmost zone at this position
|
|
||||||
int topZone = zonesHere[zonesHere.Count - 1];
|
int topZone = zonesHere[zonesHere.Count - 1];
|
||||||
var rect = zoneList[topZone];
|
var rect = zoneList[topZone];
|
||||||
|
|
||||||
int x = rect.X;
|
bool isTopEdge = r == rect.Y;
|
||||||
int y = rect.Y;
|
bool isBottomEdge = r == rect.Y + rect.Height - 1;
|
||||||
int w = rect.Width;
|
bool isLeftEdge = c == rect.X;
|
||||||
int h = rect.Height;
|
bool isRightEdge = c == rect.X + rect.Width - 1;
|
||||||
|
|
||||||
bool isTopEdge = r == y;
|
|
||||||
bool isBottomEdge = r == y + h - 1;
|
|
||||||
bool isLeftEdge = c == x;
|
|
||||||
bool isRightEdge = c == x + w - 1;
|
|
||||||
|
|
||||||
// Draw borders
|
|
||||||
if ((isTopEdge || isBottomEdge) && (isLeftEdge || isRightEdge))
|
if ((isTopEdge || isBottomEdge) && (isLeftEdge || isRightEdge))
|
||||||
{
|
{
|
||||||
Console.Write("+");
|
sb.Append('+');
|
||||||
}
|
}
|
||||||
else if (isTopEdge || isBottomEdge)
|
else if (isTopEdge || isBottomEdge)
|
||||||
{
|
{
|
||||||
Console.Write("-");
|
sb.Append('-');
|
||||||
}
|
}
|
||||||
else if (isLeftEdge || isRightEdge)
|
else if (isLeftEdge || isRightEdge)
|
||||||
{
|
{
|
||||||
Console.Write("|");
|
sb.Append('|');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Use shading to show different zones
|
sb.Append(shades[topZone % shades.Length]);
|
||||||
char[] shades = { '.', ':', '░', '▒', '▓', '█', '◆', '●', '■', '▪' };
|
|
||||||
Console.Write(shades[topZone % shades.Length]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("|");
|
sb.AppendLine("|");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw bottom border
|
// Draw bottom border
|
||||||
Console.Write(" +");
|
sb.Append(" +");
|
||||||
Console.Write(new string('-', displayWidth));
|
sb.Append('-', displayWidth);
|
||||||
Console.WriteLine("+");
|
sb.AppendLine("+");
|
||||||
|
|
||||||
// Draw legend
|
// Draw legend
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
Console.Write(" Legend: ");
|
sb.Append(" Legend: ");
|
||||||
char[] legendShades = { '.', ':', '░', '▒', '▓', '█', '◆', '●', '■', '▪' };
|
for (int i = 0; i < Math.Min(zoneId, shades.Length); i++)
|
||||||
for (int i = 0; i < Math.Min(zoneId, legendShades.Length); i++)
|
|
||||||
{
|
{
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
{
|
{
|
||||||
Console.Write(", ");
|
sb.Append(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.Write($"Zone {i} = {legendShades[i]}");
|
sb.Append(CultureInfo.InvariantCulture, $"Zone {i} = {shades[i]}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,108 +15,96 @@ namespace FancyZonesCLI;
|
|||||||
|
|
||||||
internal sealed class Program
|
internal sealed class Program
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true };
|
|
||||||
|
|
||||||
private static int Main(string[] args)
|
private static int Main(string[] args)
|
||||||
{
|
{
|
||||||
// Initialize Windows messages
|
// Initialize Windows messages
|
||||||
InitializeWindowMessages();
|
InitializeWindowMessages();
|
||||||
|
|
||||||
|
(int ExitCode, string Output) result;
|
||||||
|
|
||||||
if (args.Length == 0)
|
if (args.Length == 0)
|
||||||
{
|
{
|
||||||
PrintUsage();
|
result = (1, GetUsageText());
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
var command = args[0].ToLowerInvariant();
|
var command = args[0].ToLowerInvariant();
|
||||||
|
|
||||||
return command switch
|
result = command switch
|
||||||
{
|
{
|
||||||
"open-editor" or "editor" or "e" => OpenEditor(),
|
"open-editor" or "editor" or "e" => OpenEditor(),
|
||||||
"get-monitors" or "monitors" or "m" => GetMonitors(),
|
"get-monitors" or "monitors" or "m" => GetMonitors(),
|
||||||
"get-layouts" or "layouts" or "ls" => GetLayouts(),
|
"get-layouts" or "layouts" or "ls" => GetLayouts(),
|
||||||
"get-active-layout" or "active" or "get-active" or "a" => GetActiveLayout(),
|
"get-active-layout" or "active" or "get-active" or "a" => GetActiveLayout(),
|
||||||
"set-layout" or "set" or "s" => args.Length >= 2 ? SetLayout(args.Skip(1).ToArray()) : PrintErrorAndReturn("Error: set-layout requires a UUID parameter"),
|
"set-layout" or "set" or "s" => args.Length >= 2 ? SetLayout(args.Skip(1).ToArray()) : (1, "Error: set-layout requires a UUID parameter"),
|
||||||
"open-settings" or "settings" => OpenSettings(),
|
"open-settings" or "settings" => OpenSettings(),
|
||||||
"get-hotkeys" or "hotkeys" or "hk" => GetHotkeys(),
|
"get-hotkeys" or "hotkeys" or "hk" => GetHotkeys(),
|
||||||
"set-hotkey" or "shk" => args.Length >= 3 ? SetHotkey(int.Parse(args[1], CultureInfo.InvariantCulture), args[2]) : PrintErrorAndReturn("Error: set-hotkey requires <key> <uuid>"),
|
"set-hotkey" or "shk" => args.Length >= 3 ? SetHotkey(int.Parse(args[1], CultureInfo.InvariantCulture), args[2]) : (1, "Error: set-hotkey requires <key> <uuid>"),
|
||||||
"remove-hotkey" or "rhk" => args.Length >= 2 ? RemoveHotkey(int.Parse(args[1], CultureInfo.InvariantCulture)) : PrintErrorAndReturn("Error: remove-hotkey requires <key>"),
|
"remove-hotkey" or "rhk" => args.Length >= 2 ? RemoveHotkey(int.Parse(args[1], CultureInfo.InvariantCulture)) : (1, "Error: remove-hotkey requires <key>"),
|
||||||
"help" or "--help" or "-h" => PrintUsageAndReturn(),
|
"help" or "--help" or "-h" => (0, GetUsageText()),
|
||||||
_ => PrintUnknownCommandAndReturn(command),
|
_ => (1, $"Error: Unknown command: {command}\n\n{GetUsageText()}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int PrintErrorAndReturn(string message)
|
// Output result
|
||||||
|
if (!string.IsNullOrEmpty(result.Output))
|
||||||
{
|
{
|
||||||
Console.WriteLine(message);
|
Console.WriteLine(result.Output);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int PrintUsageAndReturn()
|
return result.ExitCode;
|
||||||
{
|
|
||||||
PrintUsage();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int PrintUnknownCommandAndReturn(string command)
|
private static string GetUsageText()
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error: Unknown command: {command}\n");
|
return """
|
||||||
PrintUsage();
|
FancyZones CLI - Command line interface for FancyZones
|
||||||
return 1;
|
======================================================
|
||||||
|
|
||||||
|
Usage: FancyZonesCLI.exe <command> [options]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
open-editor (editor, e) Launch FancyZones layout editor
|
||||||
|
get-monitors (monitors, m) List all monitors and their properties
|
||||||
|
get-layouts (layouts, ls) List all available layouts
|
||||||
|
get-active-layout (get-active, active, a)
|
||||||
|
Show currently active layout
|
||||||
|
set-layout (set, s) <uuid> [options]
|
||||||
|
Set layout by UUID
|
||||||
|
--monitor <n> Apply to monitor N (1-based)
|
||||||
|
--all Apply to all monitors
|
||||||
|
open-settings (settings) Open FancyZones settings page
|
||||||
|
get-hotkeys (hotkeys, hk) List all layout hotkeys
|
||||||
|
set-hotkey (shk) <key> <uuid> Assign hotkey (0-9) to CUSTOM layout
|
||||||
|
Note: Only custom layouts work with hotkeys
|
||||||
|
remove-hotkey (rhk) <key> Remove hotkey assignment
|
||||||
|
help Show this help message
|
||||||
|
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
FancyZonesCLI.exe e # Open editor (short)
|
||||||
|
FancyZonesCLI.exe m # List monitors (short)
|
||||||
|
FancyZonesCLI.exe ls # List layouts (short)
|
||||||
|
FancyZonesCLI.exe a # Get active layout (short)
|
||||||
|
FancyZonesCLI.exe s focus --all # Set layout (short)
|
||||||
|
FancyZonesCLI.exe open-editor # Open editor (long)
|
||||||
|
FancyZonesCLI.exe get-monitors
|
||||||
|
FancyZonesCLI.exe get-layouts
|
||||||
|
FancyZonesCLI.exe set-layout {12345678-1234-1234-1234-123456789012}
|
||||||
|
FancyZonesCLI.exe set-layout focus --monitor 2
|
||||||
|
FancyZonesCLI.exe set-layout columns --all
|
||||||
|
FancyZonesCLI.exe set-hotkey 3 {12345678-1234-1234-1234-123456789012}
|
||||||
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrintUsage()
|
private static (int ExitCode, string Output) OpenEditor()
|
||||||
{
|
|
||||||
Console.WriteLine("FancyZones CLI - Command line interface for FancyZones");
|
|
||||||
Console.WriteLine("======================================================");
|
|
||||||
Console.WriteLine();
|
|
||||||
Console.WriteLine("Usage: FancyZonesCLI.exe <command> [options]");
|
|
||||||
Console.WriteLine();
|
|
||||||
Console.WriteLine("Commands:");
|
|
||||||
Console.WriteLine(" open-editor (editor, e) Launch FancyZones layout editor");
|
|
||||||
Console.WriteLine(" get-monitors (monitors, m) List all monitors and their properties");
|
|
||||||
Console.WriteLine(" get-layouts (layouts, ls) List all available layouts");
|
|
||||||
Console.WriteLine(" get-active-layout (active, a) Show currently active layout");
|
|
||||||
Console.WriteLine(" set-layout (set, s) <uuid> [options]");
|
|
||||||
Console.WriteLine(" Set layout by UUID");
|
|
||||||
Console.WriteLine(" --monitor <n> Apply to monitor N (1-based)");
|
|
||||||
Console.WriteLine(" --all Apply to all monitors");
|
|
||||||
Console.WriteLine(" open-settings (settings) Open FancyZones settings page");
|
|
||||||
Console.WriteLine(" get-hotkeys (hotkeys, hk) List all layout hotkeys");
|
|
||||||
Console.WriteLine(" set-hotkey (shk) <key> <uuid> Assign hotkey (0-9) to CUSTOM layout");
|
|
||||||
Console.WriteLine(" Note: Only custom layouts work with hotkeys");
|
|
||||||
Console.WriteLine(" remove-hotkey (rhk) <key> Remove hotkey assignment");
|
|
||||||
Console.WriteLine(" help Show this help message");
|
|
||||||
Console.WriteLine();
|
|
||||||
Console.WriteLine();
|
|
||||||
Console.WriteLine("Examples:");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe e # Open editor (short)");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe m # List monitors (short)");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe ls # List layouts (short)");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe a # Get active layout (short)");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe s focus --all # Set layout (short)");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe open-editor # Open editor (long)");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe get-monitors");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe get-layouts");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe set-layout {12345678-1234-1234-1234-123456789012}");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe set-layout focus --monitor 2");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe set-layout columns --all");
|
|
||||||
Console.WriteLine(" FancyZonesCLI.exe set-hotkey 3 {12345678-1234-1234-1234-123456789012}");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int OpenEditor()
|
|
||||||
{
|
{
|
||||||
var editorExe = "PowerToys.FancyZonesEditor.exe";
|
var editorExe = "PowerToys.FancyZonesEditor.exe";
|
||||||
|
|
||||||
// Check if editor-parameters.json exists
|
// Check if editor-parameters.json exists
|
||||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
if (!FancyZonesData.EditorParametersExist())
|
||||||
var editorParamsPath = Path.Combine(localAppData, "Microsoft", "PowerToys", "FancyZones", "editor-parameters.json");
|
|
||||||
|
|
||||||
if (!File.Exists(editorParamsPath))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error: editor-parameters.json not found.");
|
return (1, "Error: editor-parameters.json not found.\nPlease launch FancyZones Editor using Win+` (Win+Backtick) hotkey first.");
|
||||||
Console.WriteLine("Please launch FancyZones Editor using Win+` (Win+Backtick) hotkey first.");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if editor is already running
|
// Check if editor is already running
|
||||||
@@ -124,8 +112,7 @@ internal sealed class Program
|
|||||||
if (existingProcess != null)
|
if (existingProcess != null)
|
||||||
{
|
{
|
||||||
NativeMethods.SetForegroundWindow(existingProcess.MainWindowHandle);
|
NativeMethods.SetForegroundWindow(existingProcess.MainWindowHandle);
|
||||||
Console.WriteLine("FancyZones Editor is already running. Brought window to foreground.");
|
return (0, "FancyZones Editor is already running. Brought window to foreground.");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only check same directory as CLI
|
// Only check same directory as CLI
|
||||||
@@ -140,21 +127,18 @@ internal sealed class Program
|
|||||||
FileName = editorPath,
|
FileName = editorPath,
|
||||||
UseShellExecute = true,
|
UseShellExecute = true,
|
||||||
});
|
});
|
||||||
Console.WriteLine("FancyZones Editor launched successfully.");
|
return (0, "FancyZones Editor launched successfully.");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed to launch: {ex.Message}");
|
return (1, $"Failed to launch: {ex.Message}");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Error: Could not find {editorExe} in {AppContext.BaseDirectory}");
|
return (1, $"Error: Could not find {editorExe} in {AppContext.BaseDirectory}");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int OpenSettings()
|
private static (int ExitCode, string Output) OpenSettings()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -170,8 +154,7 @@ internal sealed class Program
|
|||||||
|
|
||||||
if (powertoysExe == null)
|
if (powertoysExe == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error: PowerToys.exe not found. Please ensure PowerToys is installed.");
|
return (1, "Error: PowerToys.exe not found. Please ensure PowerToys is installed.");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Process.Start(new ProcessStartInfo
|
Process.Start(new ProcessStartInfo
|
||||||
@@ -180,232 +163,180 @@ internal sealed class Program
|
|||||||
Arguments = "--open-settings=FancyZones",
|
Arguments = "--open-settings=FancyZones",
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
});
|
});
|
||||||
Console.WriteLine("FancyZones Settings opened successfully.");
|
return (0, "FancyZones Settings opened successfully.");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error: Failed to open FancyZones Settings. {ex.Message}");
|
return (1, $"Error: Failed to open FancyZones Settings. {ex.Message}");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetMonitors()
|
private static (int ExitCode, string Output) GetMonitors()
|
||||||
{
|
{
|
||||||
var dataPath = GetFancyZonesDataPath();
|
if (!FancyZonesData.TryReadAppliedLayouts(out var appliedLayouts, out var error))
|
||||||
var appliedLayoutsPath = Path.Combine(dataPath, "applied-layouts.json");
|
|
||||||
|
|
||||||
if (!File.Exists(appliedLayoutsPath))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error: applied-layouts.json not found.");
|
return (1, $"Error: {error}");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
if (appliedLayouts.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
||||||
{
|
{
|
||||||
var json = File.ReadAllText(appliedLayoutsPath);
|
return (0, "No monitors found.");
|
||||||
var appliedLayouts = JsonSerializer.Deserialize<AppliedLayouts>(json, FancyZonesJsonContext.Default.AppliedLayouts);
|
|
||||||
|
|
||||||
if (appliedLayouts?.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
|
||||||
{
|
|
||||||
Console.WriteLine("No monitors found.");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"=== Monitors ({appliedLayouts.Layouts.Count} total) ===");
|
var sb = new System.Text.StringBuilder();
|
||||||
Console.WriteLine();
|
sb.AppendLine(CultureInfo.InvariantCulture, $"=== Monitors ({appliedLayouts.Layouts.Count} total) ===");
|
||||||
|
sb.AppendLine();
|
||||||
|
|
||||||
for (int i = 0; i < appliedLayouts.Layouts.Count; i++)
|
for (int i = 0; i < appliedLayouts.Layouts.Count; i++)
|
||||||
{
|
{
|
||||||
var layout = appliedLayouts.Layouts[i];
|
var layout = appliedLayouts.Layouts[i];
|
||||||
var monitorNum = i + 1;
|
var monitorNum = i + 1;
|
||||||
|
|
||||||
Console.WriteLine($"Monitor {monitorNum}:");
|
sb.AppendLine(CultureInfo.InvariantCulture, $"Monitor {monitorNum}:");
|
||||||
Console.WriteLine($" Monitor: {layout.Device.Monitor}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Monitor: {layout.Device.Monitor}");
|
||||||
Console.WriteLine($" Monitor Instance: {layout.Device.MonitorInstance}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Monitor Instance: {layout.Device.MonitorInstance}");
|
||||||
Console.WriteLine($" Monitor Number: {layout.Device.MonitorNumber}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Monitor Number: {layout.Device.MonitorNumber}");
|
||||||
Console.WriteLine($" Serial Number: {layout.Device.SerialNumber}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Serial Number: {layout.Device.SerialNumber}");
|
||||||
Console.WriteLine($" Virtual Desktop: {layout.Device.VirtualDesktop}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Virtual Desktop: {layout.Device.VirtualDesktop}");
|
||||||
Console.WriteLine($" Sensitivity Radius: {layout.AppliedLayout.SensitivityRadius}px");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Sensitivity Radius: {layout.AppliedLayout.SensitivityRadius}px");
|
||||||
Console.WriteLine($" Active Layout: {layout.AppliedLayout.Type}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Active Layout: {layout.AppliedLayout.Type}");
|
||||||
Console.WriteLine($" Zone Count: {layout.AppliedLayout.ZoneCount}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Zone Count: {layout.AppliedLayout.ZoneCount}");
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return (0, sb.ToString().TrimEnd());
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: Failed to read monitor information. {ex.Message}");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetLayouts()
|
private static (int ExitCode, string Output) GetLayouts()
|
||||||
{
|
{
|
||||||
var dataPath = GetFancyZonesDataPath();
|
var sb = new System.Text.StringBuilder();
|
||||||
var templatesPath = Path.Combine(dataPath, "layout-templates.json");
|
|
||||||
var customLayoutsPath = Path.Combine(dataPath, "custom-layouts.json");
|
|
||||||
|
|
||||||
// Print template layouts
|
// Print template layouts
|
||||||
if (File.Exists(templatesPath))
|
var templatesJson = FancyZonesData.ReadLayoutTemplates();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var templatesJson = JsonSerializer.Deserialize(File.ReadAllText(templatesPath), FancyZonesJsonContext.Default.LayoutTemplates);
|
|
||||||
if (templatesJson?.Templates != null)
|
if (templatesJson?.Templates != null)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"=== Built-in Template Layouts ({templatesJson.Templates.Count} total) ===\n");
|
sb.AppendLine(CultureInfo.InvariantCulture, $"=== Built-in Template Layouts ({templatesJson.Templates.Count} total) ===\n");
|
||||||
|
|
||||||
for (int i = 0; i < templatesJson.Templates.Count; i++)
|
for (int i = 0; i < templatesJson.Templates.Count; i++)
|
||||||
{
|
{
|
||||||
var template = templatesJson.Templates[i];
|
var template = templatesJson.Templates[i];
|
||||||
Console.WriteLine($"[T{i + 1}] {template.Type}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $"[T{i + 1}] {template.Type}");
|
||||||
Console.WriteLine($" Zones: {template.ZoneCount}");
|
sb.Append(CultureInfo.InvariantCulture, $" Zones: {template.ZoneCount}");
|
||||||
if (template.ShowSpacing && template.Spacing > 0)
|
if (template.ShowSpacing && template.Spacing > 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine($", Spacing: {template.Spacing}px");
|
sb.Append(CultureInfo.InvariantCulture, $", Spacing: {template.Spacing}px");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
|
sb.AppendLine();
|
||||||
|
|
||||||
// Draw visual preview
|
// Draw visual preview
|
||||||
LayoutVisualizer.DrawTemplateLayout(template);
|
sb.Append(LayoutVisualizer.DrawTemplateLayout(template));
|
||||||
|
|
||||||
if (i < templatesJson.Templates.Count - 1)
|
if (i < templatesJson.Templates.Count - 1)
|
||||||
{
|
{
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("\n");
|
sb.AppendLine("\n");
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error parsing templates: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print custom layouts
|
// Print custom layouts
|
||||||
if (File.Exists(customLayoutsPath))
|
var customLayouts = FancyZonesData.ReadCustomLayouts();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var customLayouts = JsonSerializer.Deserialize(File.ReadAllText(customLayoutsPath), FancyZonesJsonContext.Default.CustomLayouts);
|
|
||||||
if (customLayouts?.Layouts != null)
|
if (customLayouts?.Layouts != null)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"=== Custom Layouts ({customLayouts.Layouts.Count} total) ===");
|
sb.AppendLine(CultureInfo.InvariantCulture, $"=== Custom Layouts ({customLayouts.Layouts.Count} total) ===");
|
||||||
|
|
||||||
for (int i = 0; i < customLayouts.Layouts.Count; i++)
|
for (int i = 0; i < customLayouts.Layouts.Count; i++)
|
||||||
{
|
{
|
||||||
var layout = customLayouts.Layouts[i];
|
var layout = customLayouts.Layouts[i];
|
||||||
Console.WriteLine($"[{i + 1}] {layout.Name}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $"[{i + 1}] {layout.Name}");
|
||||||
Console.WriteLine($" UUID: {layout.Uuid}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" UUID: {layout.Uuid}");
|
||||||
Console.Write($" Type: {layout.Type}");
|
sb.Append(CultureInfo.InvariantCulture, $" Type: {layout.Type}");
|
||||||
|
|
||||||
bool isCanvasLayout = false;
|
bool isCanvasLayout = false;
|
||||||
if (layout.Info.ValueKind != JsonValueKind.Undefined && layout.Info.ValueKind != JsonValueKind.Null)
|
if (layout.Info.ValueKind != JsonValueKind.Undefined && layout.Info.ValueKind != JsonValueKind.Null)
|
||||||
{
|
{
|
||||||
if (layout.Type == "grid" && layout.Info.TryGetProperty("rows", out var rows) && layout.Info.TryGetProperty("columns", out var cols))
|
if (layout.Type == "grid" && layout.Info.TryGetProperty("rows", out var rows) && layout.Info.TryGetProperty("columns", out var cols))
|
||||||
{
|
{
|
||||||
Console.Write($" ({rows.GetInt32()}x{cols.GetInt32()} grid)");
|
sb.Append(CultureInfo.InvariantCulture, $" ({rows.GetInt32()}x{cols.GetInt32()} grid)");
|
||||||
}
|
}
|
||||||
else if (layout.Type == "canvas" && layout.Info.TryGetProperty("zones", out var zones))
|
else if (layout.Type == "canvas" && layout.Info.TryGetProperty("zones", out var zones))
|
||||||
{
|
{
|
||||||
Console.Write($" ({zones.GetArrayLength()} zones)");
|
sb.Append(CultureInfo.InvariantCulture, $" ({zones.GetArrayLength()} zones)");
|
||||||
isCanvasLayout = true;
|
isCanvasLayout = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("\n");
|
sb.AppendLine("\n");
|
||||||
|
|
||||||
// Draw visual preview
|
// Draw visual preview
|
||||||
LayoutVisualizer.DrawCustomLayout(layout);
|
sb.Append(LayoutVisualizer.DrawCustomLayout(layout));
|
||||||
|
|
||||||
// Add note for canvas layouts
|
// Add note for canvas layouts
|
||||||
if (isCanvasLayout)
|
if (isCanvasLayout)
|
||||||
{
|
{
|
||||||
Console.WriteLine("\n Note: Canvas layout preview is approximate.");
|
sb.AppendLine("\n Note: Canvas layout preview is approximate.");
|
||||||
Console.WriteLine(" Open FancyZones Editor for precise zone boundaries.");
|
sb.AppendLine(" Open FancyZones Editor for precise zone boundaries.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < customLayouts.Layouts.Count - 1)
|
if (i < customLayouts.Layouts.Count - 1)
|
||||||
{
|
{
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("\nUse 'FancyZonesCLI.exe set-layout <UUID>' to apply a layout.");
|
sb.AppendLine("\nUse 'FancyZonesCLI.exe set-layout <UUID>' to apply a layout.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (0, sb.ToString().TrimEnd());
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
|
private static (int ExitCode, string Output) GetActiveLayout()
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error parsing custom layouts: {ex.Message}");
|
if (!FancyZonesData.TryReadAppliedLayouts(out var appliedLayouts, out var error))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int GetActiveLayout()
|
|
||||||
{
|
{
|
||||||
var dataPath = GetFancyZonesDataPath();
|
return (1, $"Error: {error}");
|
||||||
var appliedLayoutsPath = Path.Combine(dataPath, "applied-layouts.json");
|
|
||||||
|
|
||||||
if (!File.Exists(appliedLayoutsPath))
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: Could not find applied-layouts.json");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
if (appliedLayouts.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
||||||
{
|
{
|
||||||
var appliedLayouts = JsonSerializer.Deserialize(File.ReadAllText(appliedLayoutsPath), FancyZonesJsonContext.Default.AppliedLayouts);
|
return (0, "No active layouts found.");
|
||||||
if (appliedLayouts?.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
|
||||||
{
|
|
||||||
Console.WriteLine("No active layouts found.");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("\n=== Active FancyZones Layout(s) ===\n");
|
var sb = new System.Text.StringBuilder();
|
||||||
|
sb.AppendLine("\n=== Active FancyZones Layout(s) ===\n");
|
||||||
|
|
||||||
for (int i = 0; i < appliedLayouts.Layouts.Count; i++)
|
for (int i = 0; i < appliedLayouts.Layouts.Count; i++)
|
||||||
{
|
{
|
||||||
var layout = appliedLayouts.Layouts[i];
|
var layout = appliedLayouts.Layouts[i];
|
||||||
Console.WriteLine($"Monitor {i + 1}:");
|
sb.AppendLine(CultureInfo.InvariantCulture, $"Monitor {i + 1}:");
|
||||||
Console.WriteLine($" Name: {layout.AppliedLayout.Type}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Name: {layout.AppliedLayout.Type}");
|
||||||
Console.WriteLine($" UUID: {layout.AppliedLayout.Uuid}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" UUID: {layout.AppliedLayout.Uuid}");
|
||||||
Console.WriteLine($" Type: {layout.AppliedLayout.Type} ({layout.AppliedLayout.ZoneCount} zones)");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Type: {layout.AppliedLayout.Type} ({layout.AppliedLayout.ZoneCount} zones)");
|
||||||
|
|
||||||
if (layout.AppliedLayout.ShowSpacing)
|
if (layout.AppliedLayout.ShowSpacing)
|
||||||
{
|
{
|
||||||
Console.WriteLine($" Spacing: {layout.AppliedLayout.Spacing}px");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Spacing: {layout.AppliedLayout.Spacing}px");
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($" Sensitivity Radius: {layout.AppliedLayout.SensitivityRadius}px");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" Sensitivity Radius: {layout.AppliedLayout.SensitivityRadius}px");
|
||||||
|
|
||||||
if (i < appliedLayouts.Layouts.Count - 1)
|
if (i < appliedLayouts.Layouts.Count - 1)
|
||||||
{
|
{
|
||||||
Console.WriteLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return (0, sb.ToString().TrimEnd());
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int SetLayout(string[] args)
|
private static (int ExitCode, string Output) SetLayout(string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length == 0)
|
if (args.Length == 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error: set-layout requires a UUID parameter");
|
return (1, "Error: set-layout requires a UUID parameter");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string uuid = args[0];
|
string uuid = args[0];
|
||||||
@@ -424,8 +355,7 @@ internal sealed class Program
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error: Invalid monitor number: {args[i + 1]}");
|
return (1, $"Error: Invalid monitor number: {args[i + 1]}");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (args[i] == "--all")
|
else if (args[i] == "--all")
|
||||||
@@ -436,56 +366,35 @@ internal sealed class Program
|
|||||||
|
|
||||||
if (targetMonitor.HasValue && applyToAll)
|
if (targetMonitor.HasValue && applyToAll)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error: Cannot specify both --monitor and --all");
|
return (1, "Error: Cannot specify both --monitor and --all");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataPath = GetFancyZonesDataPath();
|
|
||||||
var appliedLayoutsPath = Path.Combine(dataPath, "applied-layouts.json");
|
|
||||||
var customLayoutsPath = Path.Combine(dataPath, "custom-layouts.json");
|
|
||||||
var templatesPath = Path.Combine(dataPath, "layout-templates.json");
|
|
||||||
|
|
||||||
if (!File.Exists(appliedLayoutsPath))
|
|
||||||
{
|
|
||||||
Console.WriteLine("Error: applied-layouts.json not found");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Try to find layout in custom layouts first (by UUID)
|
// Try to find layout in custom layouts first (by UUID)
|
||||||
CustomLayout targetCustomLayout = null;
|
var customLayouts = FancyZonesData.ReadCustomLayouts();
|
||||||
|
var targetCustomLayout = customLayouts?.Layouts?.FirstOrDefault(l => l.Uuid.Equals(uuid, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
// If not found in custom layouts, try template layouts (by type name)
|
||||||
TemplateLayout targetTemplate = null;
|
TemplateLayout targetTemplate = null;
|
||||||
|
if (targetCustomLayout == null)
|
||||||
if (File.Exists(customLayoutsPath))
|
|
||||||
{
|
{
|
||||||
var customLayouts = JsonSerializer.Deserialize(File.ReadAllText(customLayoutsPath), FancyZonesJsonContext.Default.CustomLayouts);
|
var templates = FancyZonesData.ReadLayoutTemplates();
|
||||||
targetCustomLayout = customLayouts?.Layouts?.FirstOrDefault(l => l.Uuid.Equals(uuid, StringComparison.OrdinalIgnoreCase));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not found in custom layouts, try template layouts (by type name or UUID)
|
|
||||||
if (targetCustomLayout == null && File.Exists(templatesPath))
|
|
||||||
{
|
|
||||||
var templates = JsonSerializer.Deserialize(File.ReadAllText(templatesPath), FancyZonesJsonContext.Default.LayoutTemplates);
|
|
||||||
|
|
||||||
// Try matching by type name (case-insensitive)
|
|
||||||
targetTemplate = templates?.Templates?.FirstOrDefault(t => t.Type.Equals(uuid, StringComparison.OrdinalIgnoreCase));
|
targetTemplate = templates?.Templates?.FirstOrDefault(t => t.Type.Equals(uuid, StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetCustomLayout == null && targetTemplate == null)
|
if (targetCustomLayout == null && targetTemplate == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error: Layout '{uuid}' not found");
|
return (1, $"Error: Layout '{uuid}' not found\nTip: For templates, use the type name (e.g., 'focus', 'columns', 'rows', 'grid', 'priority-grid')\n For custom layouts, use the UUID from 'get-layouts'");
|
||||||
Console.WriteLine("Tip: For templates, use the type name (e.g., 'focus', 'columns', 'rows', 'grid', 'priority-grid')");
|
|
||||||
Console.WriteLine(" For custom layouts, use the UUID from 'get-layouts'");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read current applied layouts
|
// Read current applied layouts
|
||||||
var appliedLayouts = JsonSerializer.Deserialize(File.ReadAllText(appliedLayoutsPath), FancyZonesJsonContext.Default.AppliedLayouts);
|
if (!FancyZonesData.TryReadAppliedLayouts(out var appliedLayouts, out var error))
|
||||||
if (appliedLayouts?.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error: No monitors configured");
|
return (1, $"Error: {error}");
|
||||||
return 1;
|
}
|
||||||
|
|
||||||
|
if (appliedLayouts.Layouts == null || appliedLayouts.Layouts.Count == 0)
|
||||||
|
{
|
||||||
|
return (1, "Error: No monitors configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine which monitors to update
|
// Determine which monitors to update
|
||||||
@@ -502,8 +411,7 @@ internal sealed class Program
|
|||||||
int monitorIndex = targetMonitor.Value - 1; // Convert to 0-based
|
int monitorIndex = targetMonitor.Value - 1; // Convert to 0-based
|
||||||
if (monitorIndex < 0 || monitorIndex >= appliedLayouts.Layouts.Count)
|
if (monitorIndex < 0 || monitorIndex >= appliedLayouts.Layouts.Count)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error: Monitor {targetMonitor.Value} not found. Available monitors: 1-{appliedLayouts.Layouts.Count}");
|
return (1, $"Error: Monitor {targetMonitor.Value} not found. Available monitors: 1-{appliedLayouts.Layouts.Count}");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
monitorsToUpdate.Add(monitorIndex);
|
monitorsToUpdate.Add(monitorIndex);
|
||||||
@@ -534,7 +442,7 @@ internal sealed class Program
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write back to file
|
// Write back to file
|
||||||
File.WriteAllText(appliedLayoutsPath, JsonSerializer.Serialize(appliedLayouts, FancyZonesJsonContext.Default.AppliedLayouts));
|
FancyZonesData.WriteAppliedLayouts(appliedLayouts);
|
||||||
|
|
||||||
// Notify FancyZones to reload
|
// Notify FancyZones to reload
|
||||||
NotifyFancyZones(wmPrivAppliedLayoutsFileUpdate);
|
NotifyFancyZones(wmPrivAppliedLayoutsFileUpdate);
|
||||||
@@ -542,109 +450,52 @@ internal sealed class Program
|
|||||||
string layoutName = targetCustomLayout?.Name ?? targetTemplate?.Type ?? uuid;
|
string layoutName = targetCustomLayout?.Name ?? targetTemplate?.Type ?? uuid;
|
||||||
if (applyToAll)
|
if (applyToAll)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Layout '{layoutName}' applied to all {monitorsToUpdate.Count} monitors");
|
return (0, $"Layout '{layoutName}' applied to all {monitorsToUpdate.Count} monitors");
|
||||||
}
|
}
|
||||||
else if (targetMonitor.HasValue)
|
else if (targetMonitor.HasValue)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Layout '{layoutName}' applied to monitor {targetMonitor.Value}");
|
return (0, $"Layout '{layoutName}' applied to monitor {targetMonitor.Value}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Layout '{layoutName}' applied to monitor 1");
|
return (0, $"Layout '{layoutName}' applied to monitor 1");
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetHotkeys()
|
private static (int ExitCode, string Output) GetHotkeys()
|
||||||
{
|
{
|
||||||
var dataPath = GetFancyZonesDataPath();
|
var hotkeys = FancyZonesData.ReadLayoutHotkeys();
|
||||||
var hotkeysPath = Path.Combine(dataPath, "layout-hotkeys.json");
|
|
||||||
|
|
||||||
if (!File.Exists(hotkeysPath))
|
|
||||||
{
|
|
||||||
Console.WriteLine("No hotkeys configured.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var hotkeys = JsonSerializer.Deserialize(File.ReadAllText(hotkeysPath), FancyZonesJsonContext.Default.LayoutHotkeys);
|
|
||||||
if (hotkeys?.Hotkeys == null || hotkeys.Hotkeys.Count == 0)
|
if (hotkeys?.Hotkeys == null || hotkeys.Hotkeys.Count == 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine("No hotkeys configured.");
|
return (0, "No hotkeys configured.");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("=== Layout Hotkeys ===\n");
|
var sb = new System.Text.StringBuilder();
|
||||||
Console.WriteLine("Press Win + Ctrl + Alt + <number> to switch layouts:\n");
|
sb.AppendLine("=== Layout Hotkeys ===\n");
|
||||||
|
sb.AppendLine("Press Win + Ctrl + Alt + <number> to switch layouts:\n");
|
||||||
|
|
||||||
foreach (var hotkey in hotkeys.Hotkeys.OrderBy(h => h.Key))
|
foreach (var hotkey in hotkeys.Hotkeys.OrderBy(h => h.Key))
|
||||||
{
|
{
|
||||||
Console.WriteLine($" [{hotkey.Key}] → {hotkey.LayoutId}");
|
sb.AppendLine(CultureInfo.InvariantCulture, $" [{hotkey.Key}] → {hotkey.LayoutId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return (0, sb.ToString().TrimEnd());
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int SetHotkey(int key, string layoutUuid)
|
private static (int ExitCode, string Output) SetHotkey(int key, string layoutUuid)
|
||||||
{
|
{
|
||||||
if (key < 0 || key > 9)
|
if (key < 0 || key > 9)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Error: Key must be between 0 and 9");
|
return (1, "Error: Key must be between 0 and 9");
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is a custom layout UUID
|
// Check if this is a custom layout UUID
|
||||||
var dataPath = GetFancyZonesDataPath();
|
var customLayouts = FancyZonesData.ReadCustomLayouts();
|
||||||
var customLayoutsPath = Path.Combine(dataPath, "custom-layouts.json");
|
var matchedLayout = customLayouts?.Layouts?.FirstOrDefault(l => l.Uuid.Equals(layoutUuid, StringComparison.OrdinalIgnoreCase));
|
||||||
bool isCustomLayout = false;
|
bool isCustomLayout = matchedLayout != null;
|
||||||
string layoutName = layoutUuid;
|
string layoutName = matchedLayout?.Name ?? layoutUuid;
|
||||||
|
|
||||||
if (File.Exists(customLayoutsPath))
|
var hotkeys = FancyZonesData.ReadLayoutHotkeys() ?? new LayoutHotkeys();
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var customLayoutsJson = File.ReadAllText(customLayoutsPath);
|
|
||||||
var customLayouts = JsonSerializer.Deserialize<CustomLayouts>(customLayoutsJson, FancyZonesJsonContext.Default.CustomLayouts);
|
|
||||||
var layout = customLayouts?.Layouts?.FirstOrDefault(l => l.Uuid.Equals(layoutUuid, StringComparison.OrdinalIgnoreCase));
|
|
||||||
if (layout != null)
|
|
||||||
{
|
|
||||||
isCustomLayout = true;
|
|
||||||
layoutName = layout.Name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore parse errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var hotkeysPath = Path.Combine(dataPath, "layout-hotkeys.json");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
LayoutHotkeys hotkeys;
|
|
||||||
if (File.Exists(hotkeysPath))
|
|
||||||
{
|
|
||||||
hotkeys = JsonSerializer.Deserialize(File.ReadAllText(hotkeysPath), FancyZonesJsonContext.Default.LayoutHotkeys) ?? new LayoutHotkeys();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
hotkeys = new LayoutHotkeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
hotkeys.Hotkeys ??= new List<LayoutHotkey>();
|
hotkeys.Hotkeys ??= new List<LayoutHotkey>();
|
||||||
|
|
||||||
@@ -655,80 +506,42 @@ internal sealed class Program
|
|||||||
hotkeys.Hotkeys.Add(new LayoutHotkey { Key = key, LayoutId = layoutUuid });
|
hotkeys.Hotkeys.Add(new LayoutHotkey { Key = key, LayoutId = layoutUuid });
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
File.WriteAllText(hotkeysPath, JsonSerializer.Serialize(hotkeys, FancyZonesJsonContext.Default.LayoutHotkeys));
|
File.WriteAllText(FancyZonesPaths.LayoutHotkeys, JsonSerializer.Serialize(hotkeys, FancyZonesJsonContext.Default.LayoutHotkeys));
|
||||||
|
|
||||||
// Notify FancyZones
|
// Notify FancyZones
|
||||||
NotifyFancyZones(wmPrivLayoutHotkeysFileUpdate);
|
NotifyFancyZones(wmPrivLayoutHotkeysFileUpdate);
|
||||||
|
|
||||||
if (isCustomLayout)
|
if (isCustomLayout)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"✓ Hotkey {key} assigned to custom layout '{layoutName}'");
|
return (0, $"✓ Hotkey {key} assigned to custom layout '{layoutName}'\n Press Win + Ctrl + Alt + {key} to switch to this layout");
|
||||||
Console.WriteLine($" Press Win + Ctrl + Alt + {key} to switch to this layout");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"⚠ Warning: Hotkey {key} assigned to '{layoutUuid}'");
|
return (0, $"⚠ Warning: Hotkey {key} assigned to '{layoutUuid}'\n Note: FancyZones hotkeys only work with CUSTOM layouts.\n Template layouts (focus, columns, rows, etc.) cannot be used with hotkeys.\n Create a custom layout in the FancyZones Editor to use this hotkey.");
|
||||||
Console.WriteLine($" Note: FancyZones hotkeys only work with CUSTOM layouts.");
|
|
||||||
Console.WriteLine($" Template layouts (focus, columns, rows, etc.) cannot be used with hotkeys.");
|
|
||||||
Console.WriteLine($" Create a custom layout in the FancyZones Editor to use this hotkey.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int RemoveHotkey(int key)
|
private static (int ExitCode, string Output) RemoveHotkey(int key)
|
||||||
{
|
{
|
||||||
var dataPath = GetFancyZonesDataPath();
|
var hotkeys = FancyZonesData.ReadLayoutHotkeys();
|
||||||
var hotkeysPath = Path.Combine(dataPath, "layout-hotkeys.json");
|
|
||||||
|
|
||||||
if (!File.Exists(hotkeysPath))
|
|
||||||
{
|
|
||||||
Console.WriteLine($"No hotkey assigned to key {key}");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var hotkeys = JsonSerializer.Deserialize(File.ReadAllText(hotkeysPath), FancyZonesJsonContext.Default.LayoutHotkeys);
|
|
||||||
if (hotkeys?.Hotkeys == null)
|
if (hotkeys?.Hotkeys == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"No hotkey assigned to key {key}");
|
return (0, $"No hotkey assigned to key {key}");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var removed = hotkeys.Hotkeys.RemoveAll(h => h.Key == key);
|
var removed = hotkeys.Hotkeys.RemoveAll(h => h.Key == key);
|
||||||
if (removed == 0)
|
if (removed == 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"No hotkey assigned to key {key}");
|
return (0, $"No hotkey assigned to key {key}");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
File.WriteAllText(hotkeysPath, JsonSerializer.Serialize(hotkeys, FancyZonesJsonContext.Default.LayoutHotkeys));
|
FancyZonesData.WriteLayoutHotkeys(hotkeys);
|
||||||
|
|
||||||
// Notify FancyZones
|
// Notify FancyZones
|
||||||
NotifyFancyZones(wmPrivLayoutHotkeysFileUpdate);
|
NotifyFancyZones(wmPrivLayoutHotkeysFileUpdate);
|
||||||
|
|
||||||
Console.WriteLine($"Hotkey {key} removed");
|
return (0, $"Hotkey {key} removed");
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetFancyZonesDataPath()
|
|
||||||
{
|
|
||||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
|
||||||
return Path.Combine(localAppData, "Microsoft", "PowerToys", "FancyZones");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Windows Messages for notifying FancyZones
|
// Windows Messages for notifying FancyZones
|
||||||
|
|||||||
Reference in New Issue
Block a user