From 5f78b5b97c622be180418173b7107a7ff5a6e597 Mon Sep 17 00:00:00 2001 From: Catalyn45 Date: Sun, 17 Mar 2024 01:13:11 +0200 Subject: [PATCH] First commit --- .gitignore | 10 ++ ClipboardManager.sln | 25 ++++ ClipboardManager/App.config | 6 + ClipboardManager/ClipboardManager.csproj | 62 ++++++++ ClipboardManager/Program.cs | 148 ++++++++++++++++++++ ClipboardManager/Properties/AssemblyInfo.cs | 36 +++++ README.md | 58 ++++++++ 7 files changed, 345 insertions(+) create mode 100644 .gitignore create mode 100644 ClipboardManager.sln create mode 100644 ClipboardManager/App.config create mode 100644 ClipboardManager/ClipboardManager.csproj create mode 100644 ClipboardManager/Program.cs create mode 100644 ClipboardManager/Properties/AssemblyInfo.cs create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4b86099 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.com +*.class +*.dll +*.exe +*.pdb +*.dll.config +*.cache +bin/ +obj/ +.vs/ \ No newline at end of file diff --git a/ClipboardManager.sln b/ClipboardManager.sln new file mode 100644 index 0000000..71fc736 --- /dev/null +++ b/ClipboardManager.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34701.34 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClipboardManager", "ClipboardManager\ClipboardManager.csproj", "{CBC02DE6-2154-4AD1-B9E1-C785B239D760}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CBC02DE6-2154-4AD1-B9E1-C785B239D760}.Debug|x64.ActiveCfg = Debug|x64 + {CBC02DE6-2154-4AD1-B9E1-C785B239D760}.Debug|x64.Build.0 = Debug|x64 + {CBC02DE6-2154-4AD1-B9E1-C785B239D760}.Release|x64.ActiveCfg = Release|x64 + {CBC02DE6-2154-4AD1-B9E1-C785B239D760}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B701F7F6-1E5E-4E16-9CC7-771B2EDB3EAF} + EndGlobalSection +EndGlobal diff --git a/ClipboardManager/App.config b/ClipboardManager/App.config new file mode 100644 index 0000000..56efbc7 --- /dev/null +++ b/ClipboardManager/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ClipboardManager/ClipboardManager.csproj b/ClipboardManager/ClipboardManager.csproj new file mode 100644 index 0000000..b09ce1b --- /dev/null +++ b/ClipboardManager/ClipboardManager.csproj @@ -0,0 +1,62 @@ + + + + + Debug + AnyCPU + {CBC02DE6-2154-4AD1-B9E1-C785B239D760} + Exe + ClipboardManager + ClipboardManager + v4.7.2 + 512 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + x64 + bin\x64\Debug\ + + + x64 + bin\x64\Release\ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ClipboardManager/Program.cs b/ClipboardManager/Program.cs new file mode 100644 index 0000000..d80b9b7 --- /dev/null +++ b/ClipboardManager/Program.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Windows; + +namespace ClipboardManager +{ + internal class Program + { + static string helpText = "Clipboard Manager for windows files\r\n" + + "\r\n" + + "Usage\r\n" + + $"\t$ {AppDomain.CurrentDomain.FriendlyName} [--copy | --cut | --paste | --show] [-f] []\r\n" + + "\r\n" + + "Examples\r\n" + + $"\t$ {AppDomain.CurrentDomain.FriendlyName} --copy test1.txt test2.txt\r\n" + + $"\t$ {AppDomain.CurrentDomain.FriendlyName} --paste\r\n"; + + [STAThread] + static int Main(string[] args) + { + try + { + if (args.Length == 0 || args[0] == "--help") + { + Console.WriteLine(helpText); + return 0; + } + + // Some magic bytes for the cut command, this way you can also paste with ctrl + v + byte[] moveEffect = new byte[] { 2, 0, 0, 0 }; + MemoryStream dropEffect = new MemoryStream(); + dropEffect.Write(moveEffect, 0, moveEffect.Length); + + string command = args[0]; + if (command == "--show") + { + var paths = Clipboard.GetFileDropList(); + foreach (var path in paths) + { + Console.WriteLine(path); + } + } + else if (command == "--copy") + { + if (args.Length < 2) + { + Console.WriteLine("At least one path needs to be specified"); + return -1; + } + + StringCollection paths = new StringCollection(); + for (int i = 1; i < args.Length; i++) + { + paths.Add(Path.GetFullPath(args[i])); + } + + Clipboard.Clear(); + Clipboard.SetFileDropList(paths); + } + else if (command == "--cut") + { + if (args.Length < 2) + { + Console.WriteLine("At least one path needs to be specified"); + return -1; + } + + DataObject data = new DataObject(); + StringCollection paths = new StringCollection(); + for (int i = 1; i < args.Length; i++) + { + paths.Add(Path.GetFullPath(args[i])); + } + + data.SetFileDropList(paths); + data.SetData("Preferred DropEffect", dropEffect); + + Clipboard.Clear(); + Clipboard.SetDataObject(data, true); + } + else if (command == "--paste") + { + bool force = false; + int currentArgumentIndex = 1; + if (args.Length > currentArgumentIndex && args[currentArgumentIndex] == "-f") + { + force = true; + currentArgumentIndex++; + } + + string destination = Directory.GetCurrentDirectory(); + if (args.Length > currentArgumentIndex) + { + destination = args[currentArgumentIndex]; + } + + bool isCutted = false; + + // Check the magic bytes to see if the file is cutted + var data = Clipboard.GetDataObject(); + if (data != null && + data.GetData("Preferred DropEffect") is MemoryStream setDropEffect && + setDropEffect != null && + setDropEffect.ToArray().SequenceEqual(dropEffect.ToArray())) + { + isCutted = true; + } + + var paths = Clipboard.GetFileDropList(); + foreach (var path in paths) + { + string destinationFileName = Path.Combine(destination, Path.GetFileName(path)); + + var sourceFile = new FileInfo(path); + if (isCutted) + { + // MoveTo doesn't have overwrite flag so we manually delete + if (force && File.Exists(destinationFileName)) + { + var destFileInfo = new FileInfo(destinationFileName); + destFileInfo.Delete(); + } + + sourceFile.MoveTo(destinationFileName); + } + else + { + sourceFile.CopyTo(destinationFileName, force); + } + } + } + else + { + Console.WriteLine($"Unrecognized command: {command}"); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + return -1; + } + + return 0; + } + } +} diff --git a/ClipboardManager/Properties/AssemblyInfo.cs b/ClipboardManager/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c837756 --- /dev/null +++ b/ClipboardManager/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ClipboardManager")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ClipboardManager")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cbc02de6-2154-4ad1-b9e1-c785b239d760")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/README.md b/README.md new file mode 100644 index 0000000..57f8774 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# ClipboardManager + +Very simple clipboard manager for copying/cutting and pasting files on windows from the commandline. +The code is very simple, only 150 lines long. + +This is integrated with windows ctrl+c ctrl+v, meaning that you can copy/cut a file with ctrl+c/ctrl+x and then paste/move it from the commandline. You can also copy/cut it from the commandline and paste/move it with ctrl+v. + +## Features +- Copy files +- Cut files +- Paste files +- Show clipboard content +- Integrated with windows ctrl+c ctrl+v + +## Installation +Just build the project with dotnet +```pwsh +dotnet build --configuration Release +``` + +Then but the binary some directory that you have in `PATH`. + +## Examples + +Copy multiple files +```pwsh +ClipboardManager --copy ./test1.txt ../test/test2.txt +``` +
+ +Cut multiple files +```pwsh +ClipboardManager --cut ./test1.txt ../test/test2.txt +``` +
+ +Paste/Move the copied/cut files in the current directory +```pwsh +ClipboardManager --paste +``` +
+ +Paste/Move the copied/cut files in the current directory and overwrite the existing file with the same name if exists +```pwsh +ClipboardManager --paste -f +``` +
+ +Paste/Move the copied/cut files in a specified directory +```pwsh +ClipboardManager --paste ./some_dir +``` +
+ +Show copied files from clipboard +```pwsh +ClipboardManager --show +``` \ No newline at end of file