43 Commits
Author SHA1 Message Date
Stone_Red 76327ddba1 Merge pull request #8 from Stone-Red-Code/develop
Develop
2024-12-04 00:20:41 +01:00
Stone_Red 183e56ccce Merge pull request #7 from Stone-Red-Code/Stone-Red-Code-patch-1
Stone red code patch 1
2024-12-04 00:20:12 +01:00
Stone_Red 09d4b006ae Remove quote in README.md 2024-12-04 00:19:50 +01:00
Stone_Red 23a277bf00 Merge pull request #6 from Stone-Red-Code/develop
Develop
2024-12-03 21:58:13 +01:00
Stone_Red 6b1b5dcba9 Add missing assets to README.md 2024-12-03 21:57:39 +01:00
Stone_Red a1e40bb87a Standardize README 2024-12-03 21:53:23 +01:00
Stone_Red 64e702a0da Update installer 2024-12-01 18:11:44 +01:00
Stone_Red f4f1be87dd Add MSIX packaging project 2024-12-01 17:54:19 +01:00
Stone_Red 611702eddc Update libraries 2024-11-21 23:12:56 +01:00
Stone_Red 0be21101f0 Fix auto type not stopping when auto paste enabled 2024-08-09 00:12:57 +02:00
Stone_Red 816c55e4b5 Don't clear clipboard when auto paste disabled 2024-06-27 21:28:05 +02:00
Stone_Red 2fb46a6e33 Remove unnecessary debug message 2024-06-27 21:27:47 +02:00
Stone_Red 643ea1af3d Fix spelling mistakes 2024-06-10 15:14:54 +02:00
Stone_Red ca665f09a8 Add import and export functionality 2024-05-08 16:07:30 +02:00
Stone_Red b29fbc4ea2 Decrease delay before and after paste 2024-05-08 13:16:39 +02:00
Stone_Red 3a712091d6 Improve actions system 2024-05-08 01:03:14 +02:00
Stone_Red fcaaa2922c Add custom actions to the ps scripts 2024-05-08 00:42:27 +02:00
Stone_Red f7d075168f Create appdata directory if it doesn't exist 2024-05-07 17:02:42 +02:00
Stone_Red 08a65eb017 Small code improvments 2024-05-07 16:58:26 +02:00
Stone_Red 93dbf73b23 Add icon, tray icon and better title 2024-05-07 16:19:35 +02:00
Stone_Red 9322e10913 Implement most features the old app had 2024-05-06 19:32:38 +02:00
Stone_Red 8890a203d3 Fix directory structure 2024-05-05 22:03:16 +02:00
Stone_Red 7b32b3397f Migrate project to avalonia (basic code structure) 2024-05-05 20:04:20 +02:00
Stone_Red 7ce3ce5b3b Merge remote-tracking branch 'origin/main' 2024-05-02 21:58:02 +02:00
Stone_Red 2d749381e8 Fix AutoType not writing all text bug 2024-05-02 21:57:54 +02:00
Stone_Red 75b795abe5 Update usage information 2023-12-16 23:36:52 +01:00
Stone_Red d2aa8fda8d Update README.md 2023-12-15 00:34:28 +01:00
Stone_Red f6d8c5180b Add hash for HyperbolicDownloader 2023-12-14 19:32:57 +01:00
Stone_Red 87c9e03802 Update installer 2023-11-22 22:23:53 +01:00
Stone_Red c1288a1b6c Paste output as files when every line is a file path 2023-11-22 22:13:09 +01:00
Stone_Red dee84710a5 Update Microsoft.PowerShell.SDK and System.Management.Automation libraries 2023-11-22 19:06:20 +01:00
Stone_Red d4a9424fb2 Fix licence links in README.md 2023-11-22 18:18:26 +01:00
Stone_Red f2f28e863a Merge pull request #5 from Stone-Red-Code/Stone-Red-Code-patch-1
Add third party licences section to README.md
2023-11-22 18:13:52 +01:00
Stone_Red 40292a1424 Update README.md 2023-11-22 18:13:12 +01:00
Stone_Red 2139938496 Upgrade project to .NET 8 2023-11-22 17:38:53 +01:00
Stone_Red 6439c9c4bb Add inno setup installer script 2023-11-22 17:14:45 +01:00
Stone_Red 21e50c4f0e Move source files to src directory 2023-11-22 16:55:03 +01:00
Stone_Red 923b00cfc8 Use guid instead of app name to create the mutex 2023-11-22 16:53:31 +01:00
Stone_Red 64c693e81b Merge pull request #4 from yassinMi/main
fixed mutex lifetime issue
2023-11-22 16:41:07 +01:00
yassinMi 1afa6cef02 fixed mutex lifetime issue 2023-11-22 09:06:10 +00:00
Stone_Red bca0c378c1 Fixed a whoopsie 2023-06-06 23:21:53 +02:00
Stone_Red 6048a8330c Small UI improvments 2023-06-06 23:20:52 +02:00
Stone_Red 4f75699850 Add AutoType option and rework setting storeage 2023-06-06 19:08:34 +02:00
101 changed files with 1719 additions and 566 deletions
-25
View File
@@ -1,25 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32421.90
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClipCMD", "ClipCMD\ClipCMD.csproj", "{D5BA1B2C-E995-45C8-A952-8F5A809F2566}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D5BA1B2C-E995-45C8-A952-8F5A809F2566}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5BA1B2C-E995-45C8-A952-8F5A809F2566}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5BA1B2C-E995-45C8-A952-8F5A809F2566}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5BA1B2C-E995-45C8-A952-8F5A809F2566}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E8688A15-37F6-4D71-A342-449BA8244CFA}
EndGlobalSection
EndGlobal
-9
View File
@@ -1,9 +0,0 @@
<Application x:Class="ClipCMD.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClipCMD"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
-26
View File
@@ -1,26 +0,0 @@
using System.Threading;
using System.Windows;
namespace ClipCMD;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
const string appName = "ClipCMD";
_ = new Mutex(true, appName, out bool createdNew);
if (!createdNew)
{
//App is already running! Exiting the application
_ = MessageBox.Show($"Another instance of {appName} already running!", $"{appName} is already running!", MessageBoxButton.OK, MessageBoxImage.Exclamation);
Current.Shutdown();
}
base.OnStartup(e);
}
}
-10
View File
@@ -1,10 +0,0 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
-33
View File
@@ -1,33 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<AssemblyVersion>0.0.0.2</AssemblyVersion>
<FileVersion>0.0.0.2</FileVersion>
<Version>0.0.0.2</Version>
<ApplicationIcon>logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Content Include="logo.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="InputSimulator" Version="1.0.4" />
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.0.0" />
<PackageReference Include="System.Management.Automation" Version="7.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<None Update="logo.ico">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
-46
View File
@@ -1,46 +0,0 @@
using System;
using System.Windows;
using System.Windows.Interop;
namespace ClipCMD;
public class ClipboardManager
{
public event EventHandler? ClipboardChanged;
public ClipboardManager(Window windowSource)
{
if (PresentationSource.FromVisual(windowSource) is not HwndSource source)
{
throw new ArgumentException(
"Window source MUST be initialized first, such as in the Window's OnSourceInitialized handler."
, nameof(windowSource));
}
source.AddHook(WndProc);
// get window handle for interop
IntPtr windowHandle = new WindowInteropHelper(windowSource).Handle;
// register for clipboard events
NativeMethods.AddClipboardFormatListener(windowHandle);
}
private void OnClipboardChanged()
{
ClipboardChanged?.Invoke(this, EventArgs.Empty);
}
private static readonly IntPtr WndProcSuccess = IntPtr.Zero;
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == NativeMethods.WM_CLIPBOARDUPDATE)
{
OnClipboardChanged();
handled = true;
}
return WndProcSuccess;
}
}
-42
View File
@@ -1,42 +0,0 @@
<Window x:Class="ClipCMD.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ClipCMD"
mc:Ignorable="d"
Title="ClipCMD" Height="450" Width="800"
Closing="OnClose" StateChanged="OnStateChanged" Icon="logo.ico">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Label Content="Prefix:" Width="45" />
<TextBox x:Name="prefixTextBox" KeyUp="FixTextBox_TextChanged" Text="_" />
</StackPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Label Content="Suffix:" Width="45" />
<TextBox x:Name="suffixTextBox" KeyUp="FixTextBox_TextChanged" Text="_" />
</StackPanel>
<Grid DockPanel.Dock="Top" VerticalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0">
<Label DockPanel.Dock="Top" Content="Commands:" />
<TextBox DockPanel.Dock="Top" x:Name="commandsTextBox" HorizontalScrollBarVisibility="Visible" TextChanged="StaticCommandsTextBox_TextChanged" AcceptsReturn="True" VerticalAlignment="Stretch" />
</DockPanel>
<DockPanel x:Name="logPanel" Grid.Column="1">
<Label DockPanel.Dock="Top" Content="History:" />
<ListBox DockPanel.Dock="Top" x:Name="logListBox" VerticalAlignment="Stretch" />
</DockPanel>
<DockPanel Visibility="Collapsed" x:Name="errorPanel" Grid.Column="1">
<Label DockPanel.Dock="Top" Content="Errors:" />
<ListBox DockPanel.Dock="Top" x:Name="errorListBox" Foreground="Red" VerticalAlignment="Stretch" />
</DockPanel>
</Grid>
</DockPanel>
</Window>
-271
View File
@@ -1,271 +0,0 @@
using Microsoft.VisualBasic.FileIO;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Language;
using System.Text;
using System.Windows;
using WindowsInput;
using WindowsInput.Native;
namespace ClipCMD;
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly Dictionary<string, string> commands = new Dictionary<string, string>();
private readonly System.Windows.Forms.NotifyIcon notifyIcon;
private WindowState storedWindowState = WindowState.Normal;
private readonly string cmdPath;
private readonly string fixPath;
public MainWindow()
{
notifyIcon = new System.Windows.Forms.NotifyIcon
{
BalloonTipText = "ClipCMD has been minimized. Click the tray icon to show.",
BalloonTipTitle = "ClipCMD",
Text = "ClipCMD",
Icon = new System.Drawing.Icon("logo.ico"),
Visible = true
};
notifyIcon.Click += NotifyIcon_Click;
InitializeComponent();
string applicationDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string folderPath = Path.Combine(applicationDataPath, "ClipCMD");
if (!Directory.Exists(folderPath))
{
_ = Directory.CreateDirectory(folderPath);
}
cmdPath = Path.Combine(folderPath, "cmd.txt");
fixPath = Path.Combine(folderPath, "fix.txt");
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Initialize the clipboard now that we have a window source to use
ClipboardManager windowClipboardManager = new ClipboardManager(this);
windowClipboardManager.ClipboardChanged += ClipboardManager_ClipboardChanged;
if (File.Exists(cmdPath))
{
commandsTextBox.Text = File.ReadAllText(cmdPath);
}
if (File.Exists(fixPath))
{
string[] lines = File.ReadAllLines(fixPath);
if (lines.Length == 2)
{
prefixTextBox.Text = lines[0];
suffixTextBox.Text = lines[1];
}
else
{
File.Delete(fixPath);
}
}
}
private void OnClose(object? sender, CancelEventArgs args)
{
notifyIcon.Dispose();
}
private void OnStateChanged(object? sender, EventArgs args)
{
if (WindowState == WindowState.Minimized)
{
Hide();
notifyIcon?.ShowBalloonTip(2000);
}
else
{
storedWindowState = WindowState;
}
}
private void NotifyIcon_Click(object? sender, EventArgs e)
{
Show();
WindowState = storedWindowState;
}
private IDataObject? oldData;
private void ClipboardManager_ClipboardChanged(object? sender, EventArgs e)
{
if (!Clipboard.ContainsText() || (oldData is not null && Clipboard.IsCurrent(oldData)))
{
return;
}
try
{
bool result = SafeRepeat.Start(() => Clipboard.GetText().Trim(), 100, out string? clipboardText);
if (!result || clipboardText is null)
{
return;
}
if (!clipboardText.StartsWith(prefixTextBox.Text) || !clipboardText.EndsWith(suffixTextBox.Text))
{
oldData = Clipboard.GetDataObject();
return;
}
clipboardText = clipboardText[prefixTextBox.Text.Length..^suffixTextBox.Text.Length].Trim().Replace("\"\"", "\0");
TextFieldParser parser = new TextFieldParser(new StringReader(clipboardText))
{
HasFieldsEnclosedInQuotes = true
};
parser.SetDelimiters(" ");
string[] sections = parser.ReadFields() ?? Array.Empty<string>();
sections = sections.Select(s => s.Replace('\0', '\"')).ToArray();
if (sections.Length == 0)
{
return;
}
string command = sections[0].Trim();
if (!commands.TryGetValue(command, out string? script))
{
oldData = Clipboard.GetDataObject();
return;
}
PowerShell ps = PowerShell
.Create()
.AddScript(script)
.AddParameters(sections.Skip(1).ToList());
StringBuilder outText = new StringBuilder();
foreach (PSObject commandResult in ps.Invoke())
{
_ = outText.AppendLine(commandResult?.ToString() ?? string.Empty);
}
logListBox.Items.Insert(0, $"{command} > {outText.ToString().TrimEnd()}");
Clipboard.SetText(outText.ToString().TrimEnd());
oldData = Clipboard.GetDataObject();
InputSimulator inputSimulator = new InputSimulator();
_ = inputSimulator.Keyboard.ModifiedKeyStroke(new[] { VirtualKeyCode.CONTROL }, new[] { VirtualKeyCode.VK_V });
}
catch (Exception ex)
{
logListBox.Items.Insert(0, $"Error: {ex.Message}");
Debug.WriteLine(ex);
}
}
private void StaticCommandsTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
string[] lines = commandsTextBox.Text.Split('\n').Append("[#END#]").ToArray();
string commandNames = string.Empty;
StringBuilder script = new StringBuilder();
commandsTextBox.Foreground = System.Windows.Media.Brushes.Black;
errorPanel.Visibility = Visibility.Collapsed;
logPanel.Visibility = Visibility.Visible;
errorListBox.Items.Clear();
commands.Clear();
foreach (string l in lines)
{
string line = l.Trim('\n', '\r');
if (line.StartsWith('[') && line.EndsWith(']'))
{
if (!string.IsNullOrEmpty(commandNames))
{
_ = Parser.ParseInput(script.ToString(), out _, out ParseError[] errors);
if (errors.Length > 0)
{
foreach (ParseError error in errors)
{
AddError(commandNames, error.ToString());
}
}
foreach (string commandName in commandNames.Split(','))
{
if (string.IsNullOrWhiteSpace(commandName))
{
AddError(commandNames, "Command \"{commandName}\" is empty!");
}
else if (!commands.TryAdd(commandName.Trim(), script.ToString()))
{
AddError(commandNames, "Command \"{commandName}\" already exists!");
}
}
}
commandNames = line.Trim()[1..^1].Trim();
script = new StringBuilder();
}
else if (!string.IsNullOrEmpty(commandNames))
{
if (!string.IsNullOrWhiteSpace(line))
{
_ = script.AppendLine(line);
}
}
else
{
AddError(commandNames, "Input has to start with [<Command Name>]!");
return;
}
}
_ = commands.TryAdd("list", $"\"{string.Join(", ", commands.Keys)}\"");
File.WriteAllText(cmdPath, commandsTextBox.Text);
}
private void AddError(string commandNames, string error)
{
errorPanel.Visibility = Visibility.Visible;
logPanel.Visibility = Visibility.Collapsed;
commandsTextBox.Foreground = System.Windows.Media.Brushes.Red;
_ = errorListBox.Items.Add($"[{commandNames}]\n{error}");
}
private void FixTextBox_TextChanged(object sender, System.Windows.Input.KeyEventArgs e)
{
if (prefixTextBox is null || suffixTextBox is null)
{
return;
}
File.WriteAllLines(fixPath, new[] { prefixTextBox.Text, suffixTextBox.Text });
}
}
-17
View File
@@ -1,17 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace ClipCMD;
internal static class NativeMethods
{
// See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspx
public const int WM_CLIPBOARDUPDATE = 0x031D;
public static readonly IntPtr HWND_MESSAGE = new IntPtr(-3);
// See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AddClipboardFormatListener(IntPtr hwnd);
}
-44
View File
@@ -1,44 +0,0 @@
using System;
using System.Diagnostics;
namespace ClipCMD;
internal static class SafeRepeat
{
public static bool Start(Action action, int repeatCount)
{
for (int i = 0; i < repeatCount; i++)
{
try
{
action.Invoke();
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
return false;
}
public static bool Start<T>(Func<T> action, int repeatCount, out T? result)
{
for (int i = 0; i < repeatCount; i++)
{
try
{
result = action.Invoke();
return true;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
result = default;
return false;
}
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

+39 -43
View File
@@ -1,52 +1,48 @@
# ClipCMD ![ClipCMD](https://socialify.git.ci/Stone-Red-Code/ClipCMD/image?description=1&font=Inter&forks=1&issues=1&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI%2BCjxyZWN0IHk9IjAuMTE2NDU1IiB3aWR0aD0iMTAwIiBoZWlnaHQ9Ijk5Ljg4MzciIHJ4PSI0OS45NDE4IiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNMTkuMjMyMiA2OC41NUMxNi45NTg5IDY4LjU1IDE0Ljg1MDYgNjguMjAxNyAxMi45MDcyIDY3LjUwNUMxMC45NjM5IDY2LjgwODMgOS4yNTg4OSA2NS43NDUgNy43OTIyMyA2NC4zMTVDNi4zMjU1NiA2Mi44NDgzIDUuMTg4ODkgNjEuMDMzMyA0LjM4MjIzIDU4Ljg3QzMuNTc1NTYgNTYuNjcgMy4xNzIyMyA1NC4wNjY3IDMuMTcyMjMgNTEuMDZDMy4xNzIyMyA0OC4zODMzIDMuNDgzODkgNDYuMDU1IDQuMTA3MjMgNDQuMDc1QzQuNzMwNTYgNDIuMDk1IDUuNTczODkgNDAuNDI2NyA2LjYzNzIzIDM5LjA3QzcuNzAwNTYgMzcuNjc2NyA4LjkxMDU2IDM2LjU3NjcgMTAuMjY3MiAzNS43N0MxMS42MjM5IDM0LjkyNjcgMTMuMDUzOSAzNC4zMjE3IDE0LjU1NzIgMzMuOTU1QzE2LjA5NzIgMzMuNTg4MyAxNy42MDA2IDMzLjQwNSAxOS4wNjcyIDMzLjQwNUMyMi4xMTA2IDMzLjQwNSAyNC42OTU2IDM0LjAxIDI2LjgyMjIgMzUuMjJDMjguOTQ4OSAzNi40MyAzMC41NDM5IDM4LjA2MTcgMzEuNjA3MiA0MC4xMTVMMjguMDg3MiA0Mi4zMTVMMjcuNTkyMiA0Mi41OUwyNy4zNzIyIDQyLjIwNUMyNy40ODIyIDQxLjkxMTcgMjcuNDYzOSA0MS42NTUgMjcuMzE3MiA0MS40MzVDMjcuMjA3MiA0MS4xNzgzIDI2Ljk4NzIgNDAuODExNyAyNi42NTcyIDQwLjMzNUMyNS41NTcyIDM5LjEyNSAyNC4zNjU2IDM4LjMxODMgMjMuMDgyMiAzNy45MTVDMjEuODM1NiAzNy41MTE3IDIwLjQ5NzIgMzcuMzEgMTkuMDY3MiAzNy4zMUMxNy41MjcyIDM3LjMxIDE2LjA3ODkgMzcuNjAzMyAxNC43MjIyIDM4LjE5QzEzLjM2NTYgMzguNzQgMTIuMTczOSAzOS41ODMzIDExLjE0NzIgNDAuNzJDMTAuMTU3MiA0MS44NTY3IDkuMzY4ODkgNDMuMjY4MyA4Ljc4MjIzIDQ0Ljk1NUM4LjIzMjIzIDQ2LjY0MTcgNy45NTcyMyA0OC41ODUgNy45NTcyMyA1MC43ODVDNy45NTcyMyA1Mi45MTE3IDguMjUwNTYgNTQuODE4MyA4LjgzNzIzIDU2LjUwNUM5LjQyMzg5IDU4LjE5MTcgMTAuMjEyMiA1OS42NCAxMS4yMDIyIDYwLjg1QzEyLjIyODkgNjIuMDIzMyAxMy40MjA2IDYyLjk0IDE0Ljc3NzIgNjMuNkMxNi4xMzM5IDY0LjIyMzMgMTcuNTgyMiA2NC41MzUgMTkuMTIyMiA2NC41MzVDMjAuMjIyMiA2NC41MzUgMjEuMzAzOSA2NC4zODgzIDIyLjM2NzIgNjQuMDk1QzIzLjQzMDYgNjMuNzY1IDI0LjQyMDYgNjMuMjg4MyAyNS4zMzcyIDYyLjY2NUMyNi4yNTM5IDYyLjA0MTcgMjcuMDA1NiA2MS4zMDgzIDI3LjU5MjIgNjAuNDY1TDMxLjA1NzIgNjIuOTRDMjkuNzAwNiA2NC44NDY3IDI4LjA2ODkgNjYuMjU4MyAyNi4xNjIyIDY3LjE3NUMyNC4yNTU2IDY4LjA5MTcgMjEuOTQ1NiA2OC41NSAxOS4yMzIyIDY4LjU1Wk0zNi4wNDA3IDY4VjMzLjczNUg0MC4xNjU3TDUwLjAxMDcgNTAuMjM1TDYwLjA3NTcgMzMuNjhINjQuMDkwN1Y2OEg1OS41MjU3VjQyLjM3TDUwLjgzNTcgNTYuMTJINDguNjkwN0w0MC41NTA3IDQyLjUzNVY2OEgzNi4wNDA3Wk02OS44NDQzIDY4LjA1NVYzMy43MzVINzkuNjg5M0M4Mi4wNzI2IDMzLjczNSA4NC4wNzA5IDMzLjkxODMgODUuNjg0MyAzNC4yODVDODcuMjk3NiAzNC42NTE3IDg4LjY3MjYgMzUuMTgzMyA4OS44MDkzIDM1Ljg4QzkwLjk4MjYgMzYuNTc2NyA5Mi4wMDkzIDM3LjQzODMgOTIuODg5MyAzOC40NjVDOTMuODA1OSAzOS40OTE3IDk0LjU3NTkgNDAuNjQ2NyA5NS4xOTkzIDQxLjkzQzk1LjgyMjYgNDMuMjEzMyA5Ni4yODA5IDQ0LjYwNjcgOTYuNTc0MyA0Ni4xMUM5Ni45MDQzIDQ3LjYxMzMgOTcuMDY5MyA0OS4yNjMzIDk3LjA2OTMgNTEuMDZDOTYuOTk1OSA1My43IDk2LjU5MjYgNTYuMDY1IDk1Ljg1OTMgNTguMTU1Qzk1LjE2MjYgNjAuMjQ1IDk0LjA5OTMgNjIuMDIzMyA5Mi42NjkzIDYzLjQ5QzkxLjIzOTMgNjQuOTU2NyA4OS4zODc2IDY2LjA5MzMgODcuMTE0MyA2Ni45Qzg0Ljg0MDkgNjcuNjcgODIuMDkwOSA2OC4wNTUgNzguODY0MyA2OC4wNTVINjkuODQ0M1pNNzQuNTE5MyA2NC4yNkg3OC42OTkzQzgxLjg1MjYgNjQuMjYgODQuNDE5MyA2My43NjUgODYuMzk5MyA2Mi43NzVDODguNDE1OSA2MS43NDgzIDg5LjkwMDkgNjAuMjYzMyA5MC44NTQzIDU4LjMyQzkxLjgwNzYgNTYuMzc2NyA5Mi4yODQzIDU0LjAzIDkyLjI4NDMgNTEuMjhDOTIuMjQ3NiA0OC40MiA5MS43ODkzIDQ1Ljk4MTcgOTAuOTA5MyA0My45NjVDOTAuMDI5MyA0MS45NDgzIDg4LjYzNTkgNDAuNDA4MyA4Ni43MjkzIDM5LjM0NUM4NC44NTkzIDM4LjI0NSA4Mi40MjA5IDM3LjY5NSA3OS40MTQzIDM3LjY5NUg3NC41MTkzVjY0LjI2WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc%2BCg%3D%3D&name=1&pattern=Floating%20Cogs&pulls=1&stargazers=1&theme=Auto)
> A simple utility program to simplify your workflow
## What is it? ## What is it?
ClipCMD is a Windows app that allows you to create macros and run them by copying them to the clipboard.\ ClipCMD is an app that allows you to create commands and run them by copying them to the clipboard.\
You write a macro anywhere, copy it to your clipboard, and it will be automatically replaced by the output of the specified macro script.\ You can write a command anywhere, copy it to your clipboard, and it will be automatically replaced by the output of the specified command script.\
ClipCMD uses [PowerShell](https://learn.microsoft.com/en-us/powershell/scripting) as scripting language. ClipCMD uses [PowerShell](https://learn.microsoft.com/en-us/powershell/scripting) as the scripting language.
### Example
> Prefix: `_`\
> Suffix: `_`\
> Macro name: `email`\
> Macro script: `Write-Output [email protected]`\
> Macro script (alternative): `"[email protected]"`
> Input: `_email_`\
> Output: `[email protected]`
## Usage ## Usage
1. Download one of the [releases](https://github.com/Stone-Red-Code/ClipCMD/releases) 1. Download & install the latest release
1. Start `setup.exe` - Microsoft Store: [Store Page](https://www.microsoft.com/store/productId/9NZ7PCLGPBW5)
1. (Optional) Set the prefix and suffix for your commands - GitHub: [Releases](https://github.com/Stone-Red-Code/ClipCMD/releases)
1. Specify some commands in the built-in text field 1. (Optional) Put a shortcut to the `ClipCMD.Desktop.exe` file in the installation directory into the `shell:startup` directory.
- Format: 1. Start the app and add a new command.
``` 1. Press the script button to edit the command script.
[<command name(s) (separated by comma)>] 1. Open an editor and type `<prefix><commandName><suffix>`.
<scriptText> 1. Copy the command to the clipboard.
<scriptText> 1. Whatever the script outputs should now be pasted into the editor.
<scriptText>
... ## Follow the development
[<command name(s) (separated by comma)>]
<scriptText> [![Twitter(X)](http://img.shields.io/badge/Twitter-black.svg?&logo=x&style=for-the-badge&logoColor=white)](https://x.com/search?q=from%3A%40StoneRedCode%20%23ClipCMD)
<scriptText>
<scriptText> ## Example
...
``` > Prefix: `#`\
- Strings between square brackets define macros. > Suffix: `+`\
- You can define macro aliases by separating them by a comma `[quit, exit, q]` > Command name: `email`\
- Lines between a macro definition and the next macro (or the end of the file) is PowerShell code. > Command script: `Write-Output [email protected]`\
- Everything you write to the output stream replaces the input macro. > Command script (alternative): `"[email protected]"`
- You can pass parameters to the scripts by separating the parameters by space after the macro: `_combine hi nope_`
- You can access the parameters by accessing the `$args` array. > Input: `#email+`\
1. There is one prebuilt macro named `list`. This lists all of your macros. > Output: `[email protected]`
1. Write `[suffix][macroName][preffix]` somewhere, and then select it and press `CTRL+C`
## Preview ## Preview
<img width="591" alt="image" src="https://user-images.githubusercontent.com/56473591/226146460-d9d2e8fc-3754-44c7-bc43-2e32f1d07847.png"> https://github.com/user-attachments/assets/a0665d6d-e6ce-4d78-88d0-e9c35214219d
![ClipCMD-Preview_1](https://github.com/user-attachments/assets/6f136f65-ecf1-4426-a865-ecabd50689a2)
![ClipCMD-Preview_2](https://github.com/user-attachments/assets/91274468-bb52-4b39-90a3-5fb623edf8a2)
## Third party licences
- [Avalonia](https://github.com/AvaloniaUI/Avalonia) - [MIT](https://github.com/AvaloniaUI/Avalonia/blob/master/licence.md)
- [Icons.Avalonia](https://github.com/Projektanker/Icons.Avalonia) - [MIT](https://github.com/Projektanker/Icons.Avalonia/blob/main/LICENSE)
- [Semi.Avalonia](https://github.com/irihitech/Semi.Avalonia) - [MIT](https://github.com/irihitech/Semi.Avalonia/blob/main/LICENSE)
- [SharpHook](https://github.com/TolikPylypchuk/SharpHook) - [MIT](https://github.com/TolikPylypchuk/SharpHook/blob/main/LICENSE)
Binary file not shown.
+51
View File
@@ -0,0 +1,51 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#expr Exec('cmd.exe /C', 'dotnet build -o "' + SourcePath + '\publish" -c Release ' + SourcePath + '..\src\ClipCMD.Desktop\')
#define MyAppName "ClipCMD"
#define MyAppVersion GetVersionNumbersString("/publish/ClipCmd.Desktop.exe")
#define MyAppPublisher "Stone_Red"
#define MyAppExeName "ClipCmd.Desktop.exe"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId=68d780d4-b946-4154-8815-e4632e5ec5d8
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName}
DisableProgramGroupPage=yes
; The [Icons] "quicklaunchicon" entry uses {userappdata} but its [Tasks] entry has a proper IsAdminInstallMode Check.
UsedUserAreasWarning=no
; Remove the following line to run in administrative install mode (install for all users.)
PrivilegesRequired=lowest
PrivilegesRequiredOverridesAllowed=dialog
OutputBaseFilename={#MyAppName}-Installer
OutputDir=.
Compression=lzma
SolidCompression=yes
WizardStyle=modern
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 6.1; Check: not IsAdminInstallMode
[Files]
Source: "publish\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
+108
View File
@@ -0,0 +1,108 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32811.315
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClipCmd", "ClipCmd\ClipCmd.csproj", "{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClipCmd.Desktop", "ClipCmd.Desktop\ClipCmd.Desktop.csproj", "{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{3DA99C4E-89E3-4049-9C22-0A7EC60D83D8}"
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "MsixPackaging", "MsixPackaging\MsixPackaging.wapproj", "{CBF43E7F-27D3-4106-96E6-3750D1734990}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|ARM.ActiveCfg = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|ARM.Build.0 = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|ARM64.Build.0 = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|x64.ActiveCfg = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|x64.Build.0 = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|x86.ActiveCfg = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Debug|x86.Build.0 = Debug|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|Any CPU.Build.0 = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|ARM.ActiveCfg = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|ARM.Build.0 = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|ARM64.ActiveCfg = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|ARM64.Build.0 = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|x64.ActiveCfg = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|x64.Build.0 = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|x86.ActiveCfg = Release|Any CPU
{EBFA8512-1EA5-4D8C-B4AC-AB5B48A6D568}.Release|x86.Build.0 = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|ARM.ActiveCfg = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|ARM.Build.0 = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|ARM64.Build.0 = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|x64.ActiveCfg = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|x64.Build.0 = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|x86.ActiveCfg = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Debug|x86.Build.0 = Debug|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|Any CPU.Build.0 = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|ARM.ActiveCfg = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|ARM.Build.0 = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|ARM64.ActiveCfg = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|ARM64.Build.0 = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|x64.ActiveCfg = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|x64.Build.0 = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|x86.ActiveCfg = Release|Any CPU
{ABC31E74-02FF-46EB-B3B2-4E6AE43B456C}.Release|x86.Build.0 = Release|Any CPU
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|ARM.ActiveCfg = Debug|ARM
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|ARM.Build.0 = Debug|ARM
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|ARM.Deploy.0 = Debug|ARM
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|ARM64.ActiveCfg = Debug|ARM64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|ARM64.Build.0 = Debug|ARM64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|ARM64.Deploy.0 = Debug|ARM64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|x64.ActiveCfg = Debug|x64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|x64.Build.0 = Debug|x64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|x64.Deploy.0 = Debug|x64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|x86.ActiveCfg = Debug|x86
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|x86.Build.0 = Debug|x86
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Debug|x86.Deploy.0 = Debug|x86
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|Any CPU.Build.0 = Release|Any CPU
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|Any CPU.Deploy.0 = Release|Any CPU
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|ARM.ActiveCfg = Release|ARM
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|ARM.Build.0 = Release|ARM
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|ARM.Deploy.0 = Release|ARM
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|ARM64.ActiveCfg = Release|ARM64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|ARM64.Build.0 = Release|ARM64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|ARM64.Deploy.0 = Release|ARM64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|x64.ActiveCfg = Release|x64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|x64.Build.0 = Release|x64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|x64.Deploy.0 = Release|x64
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|x86.ActiveCfg = Release|x86
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|x86.Build.0 = Release|x86
{CBF43E7F-27D3-4106-96E6-3750D1734990}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {83CB65B8-011F-4ED7-BCD3-A6CFA935EF7E}
EndGlobalSection
EndGlobal
+35
View File
@@ -0,0 +1,35 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
xmlns:local="using:ClipCmd"
x:Class="ClipCmd.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.DataTemplates>
<local:ViewLocator />
</Application.DataTemplates>
<Application.Resources>
<x:Double x:Key="ControlContentThemeFontSize">12</x:Double>
<FontFamily x:Key="ContentControlThemeFontFamily">Microsoft YaHei</FontFamily>
</Application.Resources>
<Application.Styles>
<FluentTheme />
<dialogHostAvalonia:DialogHostStyles />
<StyleInclude Source="avares://AvaloniaEdit/Themes/Fluent/AvaloniaEdit.xaml" />
</Application.Styles>
<TrayIcon.Icons>
<TrayIcons>
<TrayIcon Icon="/Assets/logo.ico" ToolTipText="ClipCMD" Clicked="TrayIcon_Clicked">
<TrayIcon.Menu>
<NativeMenu>
<NativeMenuItem Header="Quit" Click="NativeMenuItem_Click_Quit" />
</NativeMenu>
</TrayIcon.Menu>
</TrayIcon>
</TrayIcons>
</TrayIcon.Icons>
</Application>
+82
View File
@@ -0,0 +1,82 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using ClipCmd.Models;
using ClipCmd.Utilities;
using ClipCmd.ViewModels;
using ClipCmd.Views;
using Projektanker.Icons.Avalonia;
using Projektanker.Icons.Avalonia.FontAwesome;
using Projektanker.Icons.Avalonia.MaterialDesign;
using System;
using System.IO;
namespace ClipCmd;
public partial class App : Application
{
public override void Initialize()
{
_ = IconProvider.Current
.Register<FontAwesomeIconProvider>()
.Register<MaterialDesignIconProvider>();
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (!Directory.Exists(Configuration.ApplicationDataPath))
{
_ = Directory.CreateDirectory(Configuration.ApplicationDataPath);
}
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow();
ClipCmdCommandHandler clipCmdCommandHandler = new ClipCmdCommandHandler(desktop.MainWindow);
ImportExportService importExportService = new ImportExportService(desktop.MainWindow, clipCmdCommandHandler);
desktop.MainWindow.DataContext = new MainViewModel(clipCmdCommandHandler, importExportService);
desktop.MainWindow.Closing += (sender, e) =>
{
e.Cancel = true;
desktop.MainWindow.Hide();
Settings.SaveSettings();
clipCmdCommandHandler.SaveCommands();
};
clipCmdCommandHandler.Start();
}
else
{
throw new PlatformNotSupportedException();
}
base.OnFrameworkInitializationCompleted();
}
private void TrayIcon_Clicked(object? sender, EventArgs e)
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && desktop.MainWindow is not null)
{
desktop.MainWindow.WindowState = Avalonia.Controls.WindowState.Normal;
desktop.MainWindow.Show();
desktop.MainWindow.Activate();
}
}
private void NativeMenuItem_Click_Quit(object? sender, EventArgs e)
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
Settings.SaveSettings();
desktop.Shutdown();
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

+46
View File
@@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<Version>1.0.0.0</Version>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\logo.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.1" />
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.1.0" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.1" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1" />
<PackageReference Include="Avalonia.ReactiveUI" Version="11.2.1" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.1" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.1.0" />
<PackageReference Include="DialogHost.Avalonia" Version="0.8.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.11.0" />
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.4.6" />
<PackageReference Include="Projektanker.Icons.Avalonia" Version="9.4.3" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.3" />
<PackageReference Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.3" />
<PackageReference Include="Semi.Avalonia" Version="11.2.1" />
<PackageReference Include="SharpHook" Version="5.3.8" />
<PackageReference Include="Speckle.Material.Icons.Avalonia" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Views\InputDialogView.axaml.cs">
<DependentUpon>InputDialogView.axaml</DependentUpon>
</Compile>
</ItemGroup>
</Project>
+7
View File
@@ -0,0 +1,7 @@
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "<Pending>")]
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
+6
View File
@@ -0,0 +1,6 @@
namespace ClipCmd.Models;
public class ClipCmdCommand(string script)
{
public string Script { get; set; } = script;
}
+7
View File
@@ -0,0 +1,7 @@
namespace ClipCmd.Models;
public enum ClipCmdMode
{
Clipboard,
AutoType
}
+55
View File
@@ -0,0 +1,55 @@
using ClipCmd.Utilities;
using System;
using System.Diagnostics;
using System.IO;
using System.Text.Json;
namespace ClipCmd.Models;
public class Settings
{
public static Settings Current { get; } = LoadSettings();
public bool AutoPaste { get; set; } = true;
public int AutoTypeDelay { get; set; } = 100;
public ClipCmdMode Mode { get; set; }
public string Prefix { get; set; } = "#";
public string Suffix { get; set; } = "";
public string CommandArgsSeperator { get; set; } = ":";
public static void SaveSettings()
{
if (!Directory.Exists(Configuration.ApplicationDataPath))
{
_ = Directory.CreateDirectory(Configuration.ApplicationDataPath);
}
File.WriteAllText(Configuration.SettingsFilePath, JsonSerializer.Serialize(Current));
}
private static Settings LoadSettings()
{
if (File.Exists(Configuration.SettingsFilePath))
{
try
{
return JsonSerializer.Deserialize<Settings>(File.ReadAllText(Configuration.SettingsFilePath)) ?? new Settings();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return new Settings();
}
}
else
{
return new Settings();
}
}
}
@@ -0,0 +1,259 @@
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Input.Platform;
using ClipCmd.Models;
using SharpHook;
using SharpHook.Native;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Text.Json;
using System.Threading.Tasks;
namespace ClipCmd.Utilities;
public class ClipCmdCommandHandler(Window window)
{
private readonly IClipboard clipboard = window.Clipboard!;
private readonly EventSimulator simulator = new EventSimulator();
private string lastText = string.Empty;
public AvaloniaDictionary<string, ClipCmdCommand> Commands { get; } = [];
public void Start()
{
_ = new TaskFactory().StartNew(async () =>
{
LoadCommands();
while (true)
{
await Run();
await Task.Delay(100);
}
}, TaskCreationOptions.LongRunning);
}
public void ClearCommands()
{
Commands.Clear();
}
public void SaveCommands()
{
string json = JsonSerializer.Serialize(Commands);
File.WriteAllText(Configuration.CommandsPath, json);
}
public void LoadCommands()
{
if (!File.Exists(Configuration.CommandsPath))
{
return;
}
string json = File.ReadAllText(Configuration.CommandsPath);
Commands.Clear();
foreach (KeyValuePair<string, ClipCmdCommand> command in JsonSerializer.Deserialize<ConcurrentDictionary<string, ClipCmdCommand>>(json) ?? new())
{
Commands[command.Key] = command.Value;
}
}
private async Task Run()
{
string? text = await clipboard.GetTextAsync();
if (text is null || text == lastText)
{
return;
}
lastText = text;
if (!text.StartsWith(Settings.Current.Prefix) || !text.EndsWith(Settings.Current.Suffix))
{
return;
}
string input = text[Settings.Current.Prefix.Length..^Settings.Current.Suffix.Length].Replace(Settings.Current.CommandArgsSeperator + Settings.Current.CommandArgsSeperator, "\0");
string[] parts = input.Split(Settings.Current.CommandArgsSeperator);
string commandName = parts[0].Replace("\0", Settings.Current.CommandArgsSeperator);
string[] parameters = parts.Skip(1).Select(p => p.Replace("\0", Settings.Current.CommandArgsSeperator)).ToArray();
if (Commands.TryGetValue(commandName, out ClipCmdCommand? command))
{
PowerShell powerShell = PowerShell.Create();
_ = powerShell.AddScript(command.Script);
_ = powerShell.AddParameters(parameters);
PSDataCollection<PSObject> commandResults = await powerShell.InvokeAsync();
foreach (PSObject commandResult in commandResults)
{
// check if commandResult is string
if (commandResult.TypeNames.Contains("System.String"))
{
await Output(commandResult.ToString());
}
else if (commandResult.BaseObject is Hashtable hashtable)
{
await ProcessActions(hashtable);
}
}
}
else if (string.IsNullOrWhiteSpace(commandName) || string.IsNullOrEmpty(Settings.Current.Suffix + Settings.Current.Prefix))
{
return;
}
else if (commandName == "list")
{
await Output($"Commands: {string.Join(", ", Commands.Keys)}");
}
else
{
await Output("Command not found!");
}
if (Settings.Current.Mode != ClipCmdMode.Clipboard || Settings.Current.AutoPaste)
{
await clipboard.ClearAsync();
}
lastText = string.Empty;
}
private async Task ProcessActions(Hashtable hashtable)
{
if (!hashtable.ContainsKey("Action") || hashtable["Action"] is not string action)
{
return;
}
if (action == "Paste")
{
if (!hashtable.ContainsKey("Text") || hashtable["Text"] is not string text)
{
return;
}
bool autoPaste = Settings.Current.AutoPaste;
if (hashtable.ContainsKey("AutoPaste") && hashtable["AutoPaste"] is bool autoPasteOverwrite)
{
autoPaste = autoPasteOverwrite;
}
await Paste(text, autoPaste);
}
else if (action == "Type")
{
if (!hashtable.ContainsKey("Text") || hashtable["Text"] is not string text)
{
return;
}
int delay = Settings.Current.AutoTypeDelay;
if (hashtable.ContainsKey("Delay") && hashtable["Delay"] is int delayOverwrite)
{
delay = delayOverwrite;
}
await Type(text, delay);
}
else if (action == "KeyPress")
{
if (!hashtable.ContainsKey("Key") || !Enum.TryParse(hashtable["Key"]?.ToString(), out KeyCode key))
{
return;
}
_ = simulator.SimulateKeyPress(key);
}
else if (action == "KeyRelease")
{
if (!hashtable.ContainsKey("Key") || !Enum.TryParse(hashtable["Key"]?.ToString(), out KeyCode key))
{
return;
}
_ = simulator.SimulateKeyRelease(key);
}
else if (action == "KeyStroke")
{
if (!hashtable.ContainsKey("Key") || !Enum.TryParse(hashtable["Key"]?.ToString(), out KeyCode key))
{
return;
}
_ = simulator.SimulateKeyPress(key);
_ = simulator.SimulateKeyRelease(key);
}
else if (action == "Delay")
{
if (!hashtable.ContainsKey("Delay") || hashtable["Delay"] is not int delay)
{
return;
}
await Task.Delay(delay);
}
}
private async Task Output(string text)
{
if (Settings.Current.Mode == ClipCmdMode.Clipboard)
{
await Paste(text, Settings.Current.AutoPaste);
}
else
{
await Type(text, Settings.Current.AutoTypeDelay);
}
}
private async Task Paste(string text, bool autoPaste)
{
await clipboard.SetTextAsync(text);
if (autoPaste)
{
await Task.Delay(10);
_ = simulator.SimulateKeyPress(KeyCode.VcLeftControl);
_ = simulator.SimulateKeyPress(KeyCode.VcV);
_ = simulator.SimulateKeyRelease(KeyCode.VcLeftControl);
_ = simulator.SimulateKeyRelease(KeyCode.VcV);
await Task.Delay(10);
}
}
private async Task Type(string text, int delay)
{
_ = simulator.SimulateKeyRelease(KeyCode.VcLeftControl);
_ = simulator.SimulateKeyRelease(KeyCode.VcRightControl);
_ = simulator.SimulateKeyRelease(KeyCode.VcLeftAlt);
_ = simulator.SimulateKeyRelease(KeyCode.VcRightAlt);
foreach (char c in text)
{
await Task.Delay(delay);
if (c == '\n')
{
_ = simulator.SimulateKeyPress(KeyCode.VcEnter);
continue;
}
_ = simulator.SimulateTextEntry(c.ToString());
}
}
}
+26
View File
@@ -0,0 +1,26 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace ClipCmd.Utilities;
internal static class Configuration
{
public static string ApplicationDataPath
{
get
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "StoneRed", "ClipCMD");
}
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StoneRed", "ClipCMD");
}
}
public static string SettingsFilePath => Path.Combine(ApplicationDataPath, "settings.json");
public static string LogFilePath => Path.Combine(ApplicationDataPath, $"ClipCMD.log");
public static string CommandsPath => Path.Combine(ApplicationDataPath, "commands.json");
}
@@ -0,0 +1,79 @@
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using ClipCmd.Models;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
namespace ClipCmd.Utilities;
public class ImportExportService(Window window, ClipCmdCommandHandler clipCmdCommandHandler)
{
private readonly TopLevel topLevel = window;
public async Task Import()
{
// Start async operation to open the dialog.
IReadOnlyList<IStorageFile> files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{
Title = "Import ClipCMD commands",
AllowMultiple = false,
FileTypeFilter = [new FilePickerFileType("ccmd")
{
Patterns = ["*.ccmd"]
}]
});
if (files.Count < 1)
{
return;
}
await using Stream stream = await files[0].OpenReadAsync();
using StreamReader streamReader = new StreamReader(stream);
string json = await streamReader.ReadToEndAsync();
clipCmdCommandHandler.ClearCommands();
Dictionary<string, ClipCmdCommand>? commands = JsonSerializer.Deserialize<Dictionary<string, ClipCmdCommand>>(json);
if (commands is null)
{
return;
}
foreach (KeyValuePair<string, ClipCmdCommand> command in commands)
{
clipCmdCommandHandler.Commands.Add(command.Key, command.Value);
}
}
public async Task Export()
{
// Start async operation to open the dialog.
IStorageFile? file = await topLevel.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
{
Title = "Export ClipCMD commands",
SuggestedFileName = "export.ccmd",
FileTypeChoices = [new FilePickerFileType("ccmd")
{
Patterns = ["*.ccmd"]
}]
});
if (file is null)
{
return;
}
string json = JsonSerializer.Serialize(clipCmdCommandHandler.Commands);
await using Stream stream = await file.OpenWriteAsync();
using StreamWriter streamWriter = new StreamWriter(stream);
await streamWriter.WriteAsync(json);
}
}
+31
View File
@@ -0,0 +1,31 @@
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using ClipCmd.ViewModels;
using System;
namespace ClipCmd;
public class ViewLocator : IDataTemplate
{
public Control? Build(object? data)
{
if (data is null)
return null;
var name = data.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}
@@ -0,0 +1,73 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using ClipCmd.Models;
using ClipCmd.Utilities;
using ClipCmd.Views;
using DialogHostAvalonia;
using ReactiveUI;
using System.Collections.Generic;
using System.Windows.Input;
namespace ClipCmd.ViewModels;
public class ClipCmdCommandItemViewModel(string name, ClipCmdCommandHandler clipCmdCommandHandler)
{
public string Name { get; } = name;
public ICommand RemoveCommand => ReactiveCommand.Create(Remove);
public ICommand RenameCommand => ReactiveCommand.Create(Rename);
public ICommand EditCommand => ReactiveCommand.Create(Edit);
private void Remove()
{
_ = clipCmdCommandHandler.Commands.Remove(Name);
clipCmdCommandHandler.SaveCommands();
}
private async void Rename()
{
string? newName = await DialogHost.Show(new InputDialogViewModel("Edit command name:", Name)) as string;
newName = newName?.Trim();
if (!clipCmdCommandHandler.Commands.Remove(Name, out ClipCmdCommand? clipCmdCommand))
{
return;
}
if (string.IsNullOrWhiteSpace(newName))
{
clipCmdCommandHandler.Commands.Add(Name, clipCmdCommand);
return;
}
int counter = 0;
string originalName = newName;
while (clipCmdCommandHandler.Commands.ContainsKey(newName))
{
newName = $"{originalName} ({++counter})";
}
clipCmdCommandHandler.Commands.Add(newName, clipCmdCommand);
clipCmdCommandHandler.SaveCommands();
}
private async void Edit()
{
Avalonia.Controls.Window? mainWindow = Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop ? desktop.MainWindow : null;
EditorWindow editorWindow = new EditorWindow
{
DataContext = new EditorViewModel(Name, clipCmdCommandHandler)
};
await editorWindow.ShowDialog(mainWindow!);
clipCmdCommandHandler.SaveCommands();
}
}
@@ -0,0 +1,10 @@
using Avalonia.Media;
namespace ClipCmd.ViewModels;
internal class EditorMessageViewModel(string message, IBrush color)
{
public string Message { get; } = message;
public IBrush Color { get; } = color;
}
+35
View File
@@ -0,0 +1,35 @@
using ClipCmd.Utilities;
using System.Collections.ObjectModel;
namespace ClipCmd.ViewModels;
internal class EditorViewModel : ViewModelBase
{
private readonly ClipCmdCommandHandler clipCmdCommandHandler;
public new string Title => $"{base.Title} - Editing {Name}";
public string Name { get; }
public string Script
{
get => clipCmdCommandHandler.Commands[Name].Script;
set => clipCmdCommandHandler.Commands[Name].Script = value;
}
public ObservableCollection<EditorMessageViewModel> Messages { get; } = [];
public EditorViewModel(string name, ClipCmdCommandHandler clipCmdCommandHandler)
{
Name = name;
this.clipCmdCommandHandler = clipCmdCommandHandler;
}
// Only used for the designer
public EditorViewModel()
{
Name = "Test";
clipCmdCommandHandler = new ClipCmdCommandHandler(new());
}
}
@@ -0,0 +1,18 @@
using DialogHostAvalonia;
using ReactiveUI;
using System.Windows.Input;
namespace ClipCmd.ViewModels;
internal class InputDialogViewModel(string title, string defaultValue = "") : ViewModelBase
{
public new string Title { get; set; } = title;
public string Value { get; set; } = defaultValue;
public ICommand OkCommand => ReactiveCommand.Create(() => DialogHost.GetDialogSession(null)!.Close(Value));
public ICommand CancelCommand => ReactiveCommand.Create(() => DialogHost.GetDialogSession(null)!.Close(null));
}
+150
View File
@@ -0,0 +1,150 @@
using ClipCmd.Models;
using ClipCmd.Utilities;
using DialogHostAvalonia;
using ReactiveUI;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
namespace ClipCmd.ViewModels;
public class MainViewModel : ViewModelBase
{
private readonly ClipCmdCommandHandler clipCmdCommandHandler;
private readonly ImportExportService importExportService;
public List<ClipCmdCommandItemViewModel> Commands => [.. clipCmdCommandHandler.Commands.Keys.Select(x => new ClipCmdCommandItemViewModel(x, clipCmdCommandHandler))];
public bool AutoTypeModeEnabled
{
get => Settings.Current.Mode == ClipCmdMode.AutoType;
set
{
Settings.Current.Mode = value ? ClipCmdMode.AutoType : ClipCmdMode.Clipboard;
this.RaisePropertyChanged();
this.RaisePropertyChanged(nameof(ClipboardModeEnabled));
}
}
public bool ClipboardModeEnabled
{
get => Settings.Current.Mode == ClipCmdMode.Clipboard;
set
{
Settings.Current.Mode = value ? ClipCmdMode.Clipboard : ClipCmdMode.AutoType;
this.RaisePropertyChanged();
this.RaisePropertyChanged(nameof(AutoTypeModeEnabled));
}
}
public int? AutoTypeDelay
{
get => Settings.Current.AutoTypeDelay;
set
{
Settings.Current.AutoTypeDelay = value ?? 1;
this.RaisePropertyChanged();
}
}
public bool AutoPaste
{
get => Settings.Current.AutoPaste;
set
{
Settings.Current.AutoPaste = value;
this.RaisePropertyChanged();
}
}
public string Prefix
{
get => Settings.Current.Prefix;
set
{
Settings.Current.Prefix = value;
this.RaisePropertyChanged();
}
}
public string Suffix
{
get => Settings.Current.Suffix;
set
{
Settings.Current.Suffix = value;
this.RaisePropertyChanged();
}
}
public string CommandArgsSeparator
{
get => Settings.Current.CommandArgsSeperator;
set
{
value = value.Replace(Settings.Current.CommandArgsSeperator, string.Empty);
if (string.IsNullOrWhiteSpace(value))
{
value = Settings.Current.CommandArgsSeperator;
}
if (value.Length > 1)
{
value = value[..1];
}
Settings.Current.CommandArgsSeperator = value;
this.RaisePropertyChanged();
}
}
public ICommand AddCommand => ReactiveCommand.Create(Add);
public ICommand ExportCommand => ReactiveCommand.Create(importExportService.Export);
public ICommand ImportCommand => ReactiveCommand.Create(importExportService.Import);
public MainViewModel(ClipCmdCommandHandler clipCmdCommandHandler, ImportExportService importExportService)
{
this.clipCmdCommandHandler = clipCmdCommandHandler;
this.importExportService = importExportService;
clipCmdCommandHandler.Commands.CollectionChanged += (sender, e) =>
{
this.RaisePropertyChanged(nameof(Commands));
};
}
// Only used for the designer
public MainViewModel()
{
clipCmdCommandHandler = new ClipCmdCommandHandler(new());
importExportService = new(new(), clipCmdCommandHandler);
}
private async void Add()
{
string? name = await DialogHost.Show(new InputDialogViewModel("Enter command name:")) as string;
name = name?.Trim();
if (string.IsNullOrWhiteSpace(name))
{
return;
}
int counter = 0;
string originalName = name;
while (clipCmdCommandHandler.Commands.ContainsKey(name))
{
name = $"{originalName} ({++counter})";
}
clipCmdCommandHandler.Commands.Add(name, new ClipCmdCommand(@$"Write-Output ""{name} command"""));
clipCmdCommandHandler.SaveCommands();
}
}
+26
View File
@@ -0,0 +1,26 @@
using ReactiveUI;
using System.Diagnostics;
using System.Reflection;
namespace ClipCmd.ViewModels;
public class ViewModelBase : ReactiveObject
{
public string Title
{
get
{
string title = "ClipCMD";
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
string? version = fileVersionInfo.ProductVersion;
#if DEBUG
return $"{title} - Dev {version}";
#else
return $"{title} - {version}";
#endif
}
}
}
+28
View File
@@ -0,0 +1,28 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:ClipCmd.ViewModels"
xmlns:AvaloniaEdit="clr-namespace:AvaloniaEdit;assembly=AvaloniaEdit"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ClipCmd.Views.EditorWindow"
x:DataType="vm:EditorViewModel"
Title="{Binding Title}"
Icon="/Assets/logo.ico"
Width="800" Height="450"
WindowStartupLocation="CenterScreen"
Loaded="Window_Loaded">
<Grid RowDefinitions="3* Auto 1*">
<AvaloniaEdit:TextEditor Name="Editor" ShowLineNumbers="True" FontFamily="Cascadia Code,Consolas,Menlo,Monospace" />
<Separator Grid.Row="1" Margin="0" />
<ScrollViewer Grid.Row="2">
<ItemsControl ItemsSource="{Binding Messages}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Message}" Foreground="{Binding Color}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Window>
+71
View File
@@ -0,0 +1,71 @@
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Styling;
using AvaloniaEdit;
using AvaloniaEdit.TextMate;
using ClipCmd.ViewModels;
using System;
using System.Management.Automation.Language;
using TextMateSharp.Grammars;
namespace ClipCmd.Views;
public partial class EditorWindow : Window
{
public EditorWindow()
{
InitializeComponent();
}
private static void CheckScript(EditorViewModel editorViewModel)
{
_ = Parser.ParseInput(editorViewModel.Script, out _, out ParseError[] parseErrors);
editorViewModel.Messages.Clear();
if (parseErrors.Length > 0)
{
foreach (ParseError parseError in parseErrors)
{
editorViewModel.Messages.Add(new($"Error: {parseError.Message} at line {parseError.Extent.StartLineNumber} and column {parseError.Extent.StartColumnNumber}", Brushes.Red));
}
}
else
{
editorViewModel.Messages.Add(new("No errors", Brushes.Green));
}
}
private void Window_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
EditorViewModel editorViewModel = DataContext as EditorViewModel ?? throw new InvalidOperationException("DataContext is not EditorViewModel");
TextEditor textEditor = this.FindControl<TextEditor>("Editor")!;
textEditor.Text = editorViewModel.Script;
textEditor.TextChanged += (s, e) =>
{
editorViewModel.Script = textEditor.Text;
CheckScript(editorViewModel);
};
ThemeName editorTheme = ThemeName.DarkPlus;
if (Avalonia.Application.Current?.ActualThemeVariant == ThemeVariant.Light)
{
editorTheme = ThemeName.LightPlus;
}
RegistryOptions registryOptions = new RegistryOptions(editorTheme);
TextMate.Installation _textMateInstallation = textEditor.InstallTextMate(registryOptions);
_textMateInstallation.SetGrammar(registryOptions.GetScopeByLanguageId(registryOptions.GetLanguageByExtension(".ps1").Id));
CheckScript(editorViewModel);
}
}
+26
View File
@@ -0,0 +1,26 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:ClipCmd.ViewModels"
xmlns:i="https://github.com/projektanker/icons.avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ClipCmd.Views.InputDialogView"
x:DataType="vm:InputDialogViewModel"
MinWidth="300"
MinHeight="100"
Background="{DynamicResource SemiColorBackground0}">
<UserControl.Styles>
<StyleInclude Source="avares://Semi.Avalonia/Themes/Index.axaml" />
</UserControl.Styles>
<StackPanel Spacing="10">
<Label Content="{Binding Title}" />
<TextBox VerticalContentAlignment="Center" Text="{Binding Value}" />
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="Ok" Width="80" HorizontalContentAlignment="Center" Command="{Binding OkCommand}" />
<Button Content="Cancel" Width="80" HorizontalContentAlignment="Center" Command="{Binding CancelCommand}" />
</StackPanel>
</StackPanel>
</UserControl>
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace ClipCmd.Views;
public partial class InputDialogView : UserControl
{
public InputDialogView()
{
InitializeComponent();
}
}
+103
View File
@@ -0,0 +1,103 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:ClipCmd.ViewModels"
xmlns:i="https://github.com/projektanker/icons.avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
x:Class="ClipCmd.Views.MainView"
x:DataType="vm:MainViewModel"
Background="{DynamicResource SemiColorBackground0}">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainViewModel />
</Design.DataContext>
<UserControl.Styles>
<StyleInclude Source="avares://Semi.Avalonia/Themes/Index.axaml" />
</UserControl.Styles>
<dialogHost:DialogHost CloseOnClickAway="False" DisableOpeningAnimation="True" Background="{DynamicResource SemiColorBackground0}">
<dialogHost:DialogHost.DialogContent>
<!-- put your dialog content here-->
</dialogHost:DialogHost.DialogContent>
<Grid RowDefinitions="Auto Auto Auto *" ColumnDefinitions="Auto * Auto" Margin="10">
<Grid RowDefinitions="Auto * Auto * Auto" VerticalAlignment="Stretch">
<TextBox Grid.Row="0" MaxLength="5" InnerLeftContent="Prefix:" Watermark="none" Text="{Binding Prefix}" />
<TextBox Grid.Row="2" MaxLength="5" InnerLeftContent="Suffix:" Watermark="none" Text="{Binding Suffix}" />
<TextBox Grid.Row="4" MaxLength="2" InnerLeftContent="Args separator:" Text="{Binding CommandArgsSeparator}" />
</Grid>
<Label Grid.Column="1" Content="ClipCMD" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30" />
<Grid RowDefinitions="Auto Auto Auto Auto Auto" ColumnDefinitions="100 20 100" Grid.Column="2">
<Label Content="Mode" />
<RadioButton Grid.Row="1" VerticalAlignment="Center" Content="Clipboard" IsChecked="{Binding ClipboardModeEnabled}" />
<CheckBox Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Content="Auto Paste" IsEnabled="{Binding ClipboardModeEnabled}" IsChecked="{Binding AutoPaste}" />
<Separator Grid.Row="2" Grid.ColumnSpan="3" VerticalAlignment="Center" />
<RadioButton Grid.Row="3" VerticalAlignment="Center" Content="Auto Type" IsChecked="{Binding AutoTypeModeEnabled}" />
<NumericUpDown Grid.Row="3" Grid.Column="2" Increment="1" Minimum="1" Maximum="1000" VerticalAlignment="Center" IsEnabled="{Binding AutoTypeModeEnabled}" Value="{Binding AutoTypeDelay, FallbackValue=1, TargetNullValue=1}" />
</Grid>
<Separator Grid.Row="1" Grid.ColumnSpan="3" VerticalAlignment="Center" Margin="0 10" />
<Button Grid.Column="0" Grid.Row="2" Command="{Binding AddCommand}">
<StackPanel Spacing="4" Orientation="Horizontal">
<i:Icon Value="fa-plus" />
<TextBlock>Add Command</TextBlock>
</StackPanel>
</Button>
<Grid ColumnDefinitions="* 20 *" Grid.Column="2" Grid.Row="2">
<Button Command="{Binding ImportCommand}">
<StackPanel Spacing="4" Orientation="Horizontal">
<i:Icon Value="fa-file-upload" />
<TextBlock>Import</TextBlock>
</StackPanel>
</Button>
<Button Grid.Column="2" Command="{Binding ExportCommand}">
<StackPanel Orientation="Horizontal">
<i:Icon Value="fa-file-download" />
<TextBlock>Export</TextBlock>
</StackPanel>
</Button>
</Grid>
<ScrollViewer Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="3" VerticalScrollBarVisibility="Auto" Margin="0 20 0 0" Theme="{DynamicResource StaticScrollViewer}">
<ItemsControl ItemsSource="{Binding Commands}">
<!--Use a StackPanel to display all the modules-->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Spacing="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!--This defines the layout for each item (i.e. each module)-->
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border CornerRadius="3" Background="{DynamicResource SemiColorBackground1}" Padding="10 10">
<Grid ColumnDefinitions="* 45 10 45 10 45">
<Label Content="{Binding Name}" VerticalAlignment="Center" />
<Button Grid.Column="1" Command="{Binding RenameCommand}" HorizontalAlignment="Stretch">
<i:Icon Value="fa-edit" />
</Button>
<Button Grid.Column="3" Command="{Binding EditCommand}" HorizontalAlignment="Stretch">
<i:Icon Value="fa-code" />
</Button>
<Button Grid.Column="5" Command="{Binding RemoveCommand}" HorizontalAlignment="Stretch">
<i:Icon Value="fa-trash" />
</Button>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</dialogHost:DialogHost>
</UserControl>
+11
View File
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace ClipCmd.Views;
public partial class MainView : UserControl
{
public MainView()
{
InitializeComponent();
}
}
+15
View File
@@ -0,0 +1,15 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:ClipCmd.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
xmlns:views="clr-namespace:ClipCmd.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ClipCmd.Views.MainWindow"
x:DataType="vm:ViewModelBase"
Icon="/Assets/logo.ico"
Title="{Binding Title}" Width="800" Height="450">
<views:MainView />
</Window>
+11
View File
@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace ClipCmd.Views;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<!--If you are willing to use Windows/MacOS native APIs you will need to create 3 projects.
One for Windows with net8.0-windows TFM, one for MacOS with net8.0-macos and one with net8.0 TFM for Linux.-->
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AssemblyName></AssemblyName>
<Version>1.0.0.0</Version>
<ApplicationIcon>logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Content Include="logo.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Desktop" Version="11.2.1" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.2.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.11.0" />
<PackageReference Include="Microsoft.CodeAnalysis.Scripting.Common" Version="4.11.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ClipCmd\ClipCmd.csproj" />
</ItemGroup>
</Project>
+29
View File
@@ -0,0 +1,29 @@
using Avalonia;
using Avalonia.ReactiveUI;
using System;
namespace ClipCmd.Desktop;
internal static class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args)
{
_ = BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
}
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
{
return AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace()
.UseReactiveUI();
}
}
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="ClipCmd.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>
Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

+6
View File
@@ -0,0 +1,6 @@
<Project>
<PropertyGroup>
<Nullable>enable</Nullable>
<AvaloniaVersion>11.0.10</AvaloniaVersion>
</PropertyGroup>
</Project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

+164
View File
@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0'">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|AnyCPU">
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|AnyCPU">
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup>
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>cbf43e7f-27d3-4106-96e6-3750d1734990</ProjectGuid>
<TargetPlatformVersion>10.0.22621.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.14393.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
<NoWarn>$(NoWarn);NU1702</NoWarn>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
<EntryPointProjectUniqueName>..\ClipCmd.Desktop\ClipCmd.Desktop.csproj</EntryPointProjectUniqueName>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundlePlatforms>x86</AppxBundlePlatforms>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Images\LargeTile.scale-100.png" />
<Content Include="Images\LargeTile.scale-125.png" />
<Content Include="Images\LargeTile.scale-150.png" />
<Content Include="Images\LargeTile.scale-200.png" />
<Content Include="Images\LargeTile.scale-400.png" />
<Content Include="Images\SmallTile.scale-100.png" />
<Content Include="Images\SmallTile.scale-125.png" />
<Content Include="Images\SmallTile.scale-150.png" />
<Content Include="Images\SmallTile.scale-200.png" />
<Content Include="Images\SmallTile.scale-400.png" />
<Content Include="Images\SplashScreen.scale-100.png" />
<Content Include="Images\SplashScreen.scale-125.png" />
<Content Include="Images\SplashScreen.scale-150.png" />
<Content Include="Images\SplashScreen.scale-200.png" />
<Content Include="Images\LockScreenLogo.scale-200.png" />
<Content Include="Images\SplashScreen.scale-400.png" />
<Content Include="Images\Square150x150Logo.scale-100.png" />
<Content Include="Images\Square150x150Logo.scale-125.png" />
<Content Include="Images\Square150x150Logo.scale-150.png" />
<Content Include="Images\Square150x150Logo.scale-200.png" />
<Content Include="Images\Square150x150Logo.scale-400.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-16.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-24.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-256.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-32.png" />
<Content Include="Images\Square44x44Logo.altform-lightunplated_targetsize-48.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-16.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-256.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-32.png" />
<Content Include="Images\Square44x44Logo.altform-unplated_targetsize-48.png" />
<Content Include="Images\Square44x44Logo.scale-100.png" />
<Content Include="Images\Square44x44Logo.scale-125.png" />
<Content Include="Images\Square44x44Logo.scale-150.png" />
<Content Include="Images\Square44x44Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.scale-400.png" />
<Content Include="Images\Square44x44Logo.targetsize-16.png" />
<Content Include="Images\Square44x44Logo.targetsize-24.png" />
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Images\Square44x44Logo.targetsize-256.png" />
<Content Include="Images\Square44x44Logo.targetsize-32.png" />
<Content Include="Images\Square44x44Logo.targetsize-48.png" />
<Content Include="Images\StoreLogo.scale-100.png" />
<Content Include="Images\StoreLogo.scale-125.png" />
<Content Include="Images\StoreLogo.scale-150.png" />
<Content Include="Images\StoreLogo.scale-200.png" />
<Content Include="Images\StoreLogo.scale-400.png" />
<Content Include="Images\Wide310x150Logo.scale-100.png" />
<Content Include="Images\Wide310x150Logo.scale-125.png" />
<Content Include="Images\Wide310x150Logo.scale-150.png" />
<Content Include="Images\Wide310x150Logo.scale-200.png" />
<Content Include="Images\Wide310x150Logo.scale-400.png" />
<None Include="Package.StoreAssociation.xml" />
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.3233" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ClipCmd.Desktop\ClipCmd.Desktop.csproj" />
</ItemGroup>
</Project>

Some files were not shown because too many files have changed in this diff Show More