diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
index df5c3871f..88b876eba 100644
--- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
@@ -751,7 +751,11 @@ namespace Terminal.Gui {
if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
clipboard = new MacOSXClipboard ();
} else {
- clipboard = new CursesClipboard ();
+ if (Is_WSL_Platform ()) {
+ clipboard = new WSLClipboard ();
+ } else {
+ clipboard = new CursesClipboard ();
+ }
}
Curses.raw ();
@@ -844,6 +848,15 @@ namespace Terminal.Gui {
}
}
+ public static bool Is_WSL_Platform ()
+ {
+ var result = BashRunner.Run ("uname -a");
+ if (result.Contains ("microsoft") && result.Contains ("WSL")) {
+ return true;
+ }
+ return false;
+ }
+
static int MapColor (Color color)
{
switch (color) {
@@ -1056,67 +1069,102 @@ namespace Terminal.Gui {
}
}
- class CursesClipboard : IClipboard {
- public string GetClipboardData ()
+ class CursesClipboard : ClipboardBase {
+ public override bool IsSupported => CheckSupport ();
+
+ bool CheckSupport ()
+ {
+ try {
+ var result = BashRunner.Run ("which xclip");
+ return BashRunner.FileExists (result);
+ } catch (Exception) {
+ // Permissions issue.
+ return false;
+ }
+ }
+
+ protected override string GetClipboardDataImpl ()
{
var tempFileName = System.IO.Path.GetTempFileName ();
try {
// BashRunner.Run ($"xsel -o --clipboard > {tempFileName}");
- BashRunner.Run ($"xclip -o > {tempFileName}");
+ BashRunner.Run ($"xclip -selection clipboard -o > {tempFileName}");
return System.IO.File.ReadAllText (tempFileName);
} finally {
System.IO.File.Delete (tempFileName);
}
}
- public void SetClipboardData (string text)
+ protected override void SetClipboardDataImpl (string text)
{
- var tempFileName = System.IO.Path.GetTempFileName ();
- System.IO.File.WriteAllText (tempFileName, text);
- try {
- // BashRunner.Run ($"cat {tempFileName} | xsel -i --clipboard");
- BashRunner.Run ($"cat {tempFileName} | xclip -selection clipboard");
- } finally {
- System.IO.File.Delete (tempFileName);
- }
+ // var tempFileName = System.IO.Path.GetTempFileName ();
+ // System.IO.File.WriteAllText (tempFileName, text);
+ // try {
+ // // BashRunner.Run ($"cat {tempFileName} | xsel -i --clipboard");
+ // BashRunner.Run ($"cat {tempFileName} | xclip -selection clipboard");
+ // } finally {
+ // System.IO.File.Delete (tempFileName);
+ // }
+
+ BashRunner.Run ("xclip -selection clipboard -i", false, text);
}
}
static class BashRunner {
- public static string Run (string commandLine)
+ public static string Run (string commandLine, bool output = true, string inputText = "")
{
- var errorBuilder = new System.Text.StringBuilder ();
- var outputBuilder = new System.Text.StringBuilder ();
var arguments = $"-c \"{commandLine}\"";
- using (var process = new System.Diagnostics.Process {
- StartInfo = new System.Diagnostics.ProcessStartInfo {
- FileName = "bash",
- Arguments = arguments,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- UseShellExecute = false,
- CreateNoWindow = false,
- }
- }) {
- process.Start ();
- process.OutputDataReceived += (sender, args) => { outputBuilder.AppendLine (args.Data); };
- process.BeginOutputReadLine ();
- process.ErrorDataReceived += (sender, args) => { errorBuilder.AppendLine (args.Data); };
- process.BeginErrorReadLine ();
- if (!process.DoubleWaitForExit ()) {
- var timeoutError = $@"Process timed out. Command line: bash {arguments}.
+
+ if (output) {
+ var errorBuilder = new System.Text.StringBuilder ();
+ var outputBuilder = new System.Text.StringBuilder ();
+
+ using (var process = new System.Diagnostics.Process {
+ StartInfo = new System.Diagnostics.ProcessStartInfo {
+ FileName = "bash",
+ Arguments = arguments,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = false,
+ }
+ }) {
+ process.Start ();
+ process.OutputDataReceived += (sender, args) => { outputBuilder.AppendLine (args.Data); };
+ process.BeginOutputReadLine ();
+ process.ErrorDataReceived += (sender, args) => { errorBuilder.AppendLine (args.Data); };
+ process.BeginErrorReadLine ();
+ if (!process.DoubleWaitForExit ()) {
+ var timeoutError = $@"Process timed out. Command line: bash {arguments}.
+ Output: {outputBuilder}
+ Error: {errorBuilder}";
+ throw new Exception (timeoutError);
+ }
+ if (process.ExitCode == 0) {
+ return outputBuilder.ToString ();
+ }
+
+ var error = $@"Could not execute process. Command line: bash {arguments}.
Output: {outputBuilder}
Error: {errorBuilder}";
- throw new Exception (timeoutError);
+ throw new Exception (error);
}
- if (process.ExitCode == 0) {
- return outputBuilder.ToString ();
+ } else {
+ using (var process = new System.Diagnostics.Process {
+ StartInfo = new System.Diagnostics.ProcessStartInfo {
+ FileName = "bash",
+ Arguments = arguments,
+ RedirectStandardInput = true,
+ UseShellExecute = false,
+ CreateNoWindow = false
+ }
+ }) {
+ process.Start ();
+ process.StandardInput.Write (inputText);
+ process.StandardInput.Close ();
+ process.WaitForExit ();
+ return inputText;
}
-
- var error = $@"Could not execute process. Command line: bash {arguments}.
- Output: {outputBuilder}
- Error: {errorBuilder}";
- throw new Exception (error);
}
}
@@ -1128,9 +1176,14 @@ namespace Terminal.Gui {
}
return result;
}
+
+ public static bool FileExists (string value)
+ {
+ return !string.IsNullOrEmpty (value) && !value.Contains ("not found");
+ }
}
- class MacOSXClipboard : IClipboard {
+ class MacOSXClipboard : ClipboardBase {
IntPtr nsString = objc_getClass ("NSString");
IntPtr nsPasteboard = objc_getClass ("NSPasteboard");
IntPtr utfTextType;
@@ -1144,6 +1197,18 @@ namespace Terminal.Gui {
IntPtr generalPasteboardRegister = sel_registerName ("generalPasteboard");
IntPtr clearContentsRegister = sel_registerName ("clearContents");
+ public override bool IsSupported => CheckSupport ();
+
+ bool CheckSupport ()
+ {
+ var result = BashRunner.Run ("which pbcopy");
+ if (!BashRunner.FileExists (result)) {
+ return false;
+ }
+ result = BashRunner.Run ("which pbpaste");
+ return BashRunner.FileExists (result);
+ }
+
public MacOSXClipboard ()
{
utfTextType = objc_msgSend (objc_msgSend (nsString, allocRegister), initWithUtf8Register, "public.utf8-plain-text");
@@ -1151,14 +1216,14 @@ namespace Terminal.Gui {
generalPasteboard = objc_msgSend (nsPasteboard, generalPasteboardRegister);
}
- public string GetClipboardData ()
+ protected override string GetClipboardDataImpl ()
{
var ptr = objc_msgSend (generalPasteboard, stringForTypeRegister, nsStringPboardType);
var charArray = objc_msgSend (ptr, utf8Register);
return Marshal.PtrToStringAnsi (charArray);
}
- public void SetClipboardData (string text)
+ protected override void SetClipboardDataImpl (string text)
{
IntPtr str = default;
try {
@@ -1190,4 +1255,63 @@ namespace Terminal.Gui {
[DllImport ("/System/Library/Frameworks/AppKit.framework/AppKit")]
static extern IntPtr sel_registerName (string selectorName);
}
+
+ class WSLClipboard : ClipboardBase {
+ public override bool IsSupported => CheckSupport ();
+
+ bool CheckSupport ()
+ {
+ var result = BashRunner.Run ("which powershell.exe");
+ return BashRunner.FileExists (result);
+
+ //var result = BashRunner.Run ("which powershell.exe");
+ //if (!BashRunner.FileExists (result)) {
+ // return false;
+ //}
+ //result = BashRunner.Run ("which clip.exe");
+ //return BashRunner.FileExists (result);
+ }
+
+ protected override string GetClipboardDataImpl ()
+ {
+ using (var powershell = new System.Diagnostics.Process {
+ StartInfo = new System.Diagnostics.ProcessStartInfo {
+ RedirectStandardOutput = true,
+ FileName = "powershell.exe",
+ Arguments = "-noprofile -command \"Get-Clipboard\""
+ }
+ }) {
+ powershell.Start ();
+ var result = powershell.StandardOutput.ReadToEnd ();
+ powershell.StandardOutput.Close ();
+ powershell.WaitForExit ();
+ return result.TrimEnd ();
+ }
+ }
+
+ protected override void SetClipboardDataImpl (string text)
+ {
+ using (var powershell = new System.Diagnostics.Process {
+ StartInfo = new System.Diagnostics.ProcessStartInfo {
+ FileName = "powershell.exe",
+ Arguments = $"-noprofile -command \"Set-Clipboard -Value \\\"{text}\\\"\""
+ }
+ }) {
+ powershell.Start ();
+ powershell.WaitForExit ();
+ }
+
+ //using (var clipExe = new System.Diagnostics.Process {
+ // StartInfo = new System.Diagnostics.ProcessStartInfo {
+ // FileName = "clip.exe",
+ // RedirectStandardInput = true
+ // }
+ //}) {
+ // clipExe.Start ();
+ // clipExe.StandardInput.Write (text);
+ // clipExe.StandardInput.Close ();
+ // clipExe.WaitForExit ();
+ //}
+ }
+ }
}
diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs
index feccf6126..96087cce8 100644
--- a/Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs
+++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs
@@ -116,7 +116,7 @@ namespace Terminal.Gui {
this.mainLoop = mainLoop;
pipe (wakeupPipes);
AddWatch (wakeupPipes [0], Condition.PollIn, ml => {
- read (wakeupPipes [0], ignore, (IntPtr)1);
+ read (wakeupPipes [0], ignore, (IntPtr)0);
return true;
});
}
diff --git a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
index 246f5af5d..0aa48539f 100644
--- a/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
@@ -64,7 +64,11 @@ namespace Terminal.Gui {
} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
Clipboard = new MacOSXClipboard ();
} else {
- Clipboard = new CursesClipboard ();
+ if (CursesDriver.Is_WSL_Platform ()) {
+ Clipboard = new WSLClipboard ();
+ } else {
+ Clipboard = new CursesClipboard ();
+ }
}
}
diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs
index 3cf2b1765..e70151fd1 100644
--- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs
@@ -1102,7 +1102,11 @@ namespace Terminal.Gui {
} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
Clipboard = new MacOSXClipboard ();
} else {
- Clipboard = new CursesClipboard ();
+ if (CursesDriver.Is_WSL_Platform ()) {
+ Clipboard = new WSLClipboard ();
+ }else{
+ Clipboard = new CursesClipboard ();
+ }
}
}
diff --git a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
index bddf89f14..c08a18768 100644
--- a/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
+++ b/Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
@@ -1640,11 +1640,13 @@ namespace Terminal.Gui {
}
}
- class WindowsClipboard : IClipboard {
- public string GetClipboardData ()
+ class WindowsClipboard : ClipboardBase {
+ public override bool IsSupported => IsClipboardFormatAvailable (cfUnicodeText) ? true : false;
+
+ protected override string GetClipboardDataImpl ()
{
- if (!IsClipboardFormatAvailable (cfUnicodeText))
- return null;
+ //if (!IsClipboardFormatAvailable (cfUnicodeText))
+ // return null;
try {
if (!OpenClipboard (IntPtr.Zero))
@@ -1678,7 +1680,7 @@ namespace Terminal.Gui {
}
}
- public void SetClipboardData (string text)
+ protected override void SetClipboardDataImpl (string text)
{
OpenClipboard ();
diff --git a/Terminal.Gui/Core/Clipboard.cs b/Terminal.Gui/Core/Clipboard.cs
deleted file mode 100644
index 5e029fe29..000000000
--- a/Terminal.Gui/Core/Clipboard.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using NStack;
-using System;
-
-namespace Terminal.Gui {
- ///
- /// Provides cut, copy, and paste support for the clipboard with OS interaction.
- ///
- public static class Clipboard {
- static ustring contents;
-
- ///
- /// Get or sets the operation system clipboard, otherwise the contents field.
- ///
- public static ustring Contents {
- get {
- try {
- return Application.Driver.Clipboard.GetClipboardData ();
- } catch (Exception) {
- return contents;
- }
- }
- set {
- try {
- Application.Driver.Clipboard.SetClipboardData (value.ToString ());
- contents = value;
- } catch (Exception) {
- contents = value;
- }
- }
- }
- }
-}
diff --git a/Terminal.Gui/Core/Clipboard/Clipboard.cs b/Terminal.Gui/Core/Clipboard/Clipboard.cs
new file mode 100644
index 000000000..e7d570074
--- /dev/null
+++ b/Terminal.Gui/Core/Clipboard/Clipboard.cs
@@ -0,0 +1,67 @@
+using NStack;
+using System;
+
+namespace Terminal.Gui {
+ ///
+ /// Provides cut, copy, and paste support for the clipboard with OS interaction.
+ ///
+ public static class Clipboard {
+ static ustring contents;
+
+ ///
+ /// Get or sets the operation system clipboard, otherwise the contents field.
+ ///
+ public static ustring Contents {
+ get {
+ try {
+ return Application.Driver.Clipboard.GetClipboardData ();
+ } catch (Exception) {
+ return contents;
+ }
+ }
+ set {
+ try {
+ Application.Driver.Clipboard.SetClipboardData (value.ToString ());
+ contents = value;
+ } catch (Exception) {
+ contents = value;
+ }
+ }
+ }
+
+ ///
+ /// Returns true if the environmental dependencies are in place to interact with the OS clipboard.
+ ///
+ public static bool IsSupported { get; } = Application.Driver.Clipboard.IsSupported;
+
+ ///
+ /// Gets the operation system clipboard if possible.
+ ///
+ /// Clipboard contents read
+ /// true if it was possible to read the OS clipboard.
+ public static bool TryGetClipboardData (out string result)
+ {
+ if (Application.Driver.Clipboard.TryGetClipboardData (out result)) {
+ if (contents != result) {
+ contents = result;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// Sets the operation system clipboard if possible.
+ ///
+ ///
+ /// True if the clipboard content was set successfully.
+ public static bool TrySetClipboardData (string text)
+ {
+ if (Application.Driver.Clipboard.TrySetClipboardData (text)) {
+ contents = text;
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/Terminal.Gui/Core/Clipboard/ClipboardBase.cs b/Terminal.Gui/Core/Clipboard/ClipboardBase.cs
new file mode 100644
index 000000000..db61af80f
--- /dev/null
+++ b/Terminal.Gui/Core/Clipboard/ClipboardBase.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Terminal.Gui {
+ ///
+ /// Shared abstract class to enforce rules from the implementation of the interface.
+ ///
+ public abstract class ClipboardBase : IClipboard {
+ ///
+ /// Returns true if the environmental dependencies are in place to interact with the OS clipboard
+ ///
+ public abstract bool IsSupported { get; }
+
+ ///
+ /// Get the operation system clipboard.
+ ///
+ /// Thrown if it was not possible to read the clipboard contents
+ public string GetClipboardData ()
+ {
+ try {
+ return GetClipboardDataImpl ();
+ } catch (Exception ex) {
+ throw new NotSupportedException ("Failed to read clipboard.", ex);
+ }
+ }
+
+ ///
+ /// Get the operation system clipboard.
+ ///
+ protected abstract string GetClipboardDataImpl ();
+
+ ///
+ /// Sets the operation system clipboard.
+ ///
+ ///
+ /// Thrown if it was not possible to set the clipboard contents
+ public void SetClipboardData (string text)
+ {
+ try {
+ SetClipboardDataImpl (text);
+ } catch (Exception ex) {
+ throw new NotSupportedException ("Failed to write to clipboard.", ex);
+ }
+ }
+
+ ///
+ /// Sets the operation system clipboard.
+ ///
+ ///
+ protected abstract void SetClipboardDataImpl (string text);
+
+ ///
+ /// Gets the operation system clipboard if possible.
+ ///
+ /// Clipboard contents read
+ /// true if it was possible to read the OS clipboard.
+ public bool TryGetClipboardData (out string result)
+ {
+ // Don't even try to read because environment is not set up.
+ if (!IsSupported) {
+ result = null;
+ return false;
+ }
+
+ try {
+ result = GetClipboardDataImpl ();
+ while (result == null) {
+ result = GetClipboardDataImpl ();
+ }
+ return true;
+ } catch (Exception) {
+ result = null;
+ return false;
+ }
+ }
+
+ ///
+ /// Sets the operation system clipboard if possible.
+ ///
+ ///
+ /// True if the clipboard content was set successfully
+ public bool TrySetClipboardData (string text)
+ {
+ // Don't even try to set because environment is not set up
+ if (!IsSupported) {
+ return false;
+ }
+
+ try {
+ SetClipboardDataImpl (text);
+ return true;
+ } catch (Exception) {
+ return false;
+ }
+ }
+ }
+}
diff --git a/Terminal.Gui/Core/Clipboard/IClipboard.cs b/Terminal.Gui/Core/Clipboard/IClipboard.cs
new file mode 100644
index 000000000..9619d8125
--- /dev/null
+++ b/Terminal.Gui/Core/Clipboard/IClipboard.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Terminal.Gui {
+ ///
+ /// Definition to interact with the OS clipboard.
+ ///
+ public interface IClipboard {
+ ///
+ /// Returns true if the environmental dependencies are in place to interact with the OS clipboard.
+ ///
+ bool IsSupported { get; }
+
+ ///
+ /// Get the operation system clipboard.
+ ///
+ /// Thrown if it was not possible to read the clipboard contents.
+ string GetClipboardData ();
+
+ ///
+ /// Gets the operation system clipboard if possible.
+ ///
+ /// Clipboard contents read
+ /// true if it was possible to read the OS clipboard.
+ bool TryGetClipboardData (out string result);
+
+ ///
+ /// Sets the operation system clipboard.
+ ///
+ ///
+ /// Thrown if it was not possible to set the clipboard contents.
+ void SetClipboardData (string text);
+
+ ///
+ /// Sets the operation system clipboard if possible.
+ ///
+ ///
+ /// True if the clipboard content was set successfully.
+ bool TrySetClipboardData (string text);
+ }
+}
diff --git a/Terminal.Gui/Core/ConsoleDriver.cs b/Terminal.Gui/Core/ConsoleDriver.cs
index 9f7594443..86fc62a6f 100644
--- a/Terminal.Gui/Core/ConsoleDriver.cs
+++ b/Terminal.Gui/Core/ConsoleDriver.cs
@@ -1178,20 +1178,4 @@ namespace Terminal.Gui {
/// The current attribute.
public abstract Attribute GetAttribute ();
}
-
- ///
- /// Definition to interact with the OS clipboard.
- ///
- public interface IClipboard {
- ///
- /// Sets the operation system clipboard.
- ///
- ///
- void SetClipboardData (string text);
- ///
- /// Get the operation system clipboard.
- ///
- ///
- string GetClipboardData ();
- }
}
diff --git a/UICatalog/UICatalog.cs b/UICatalog/UICatalog.cs
index 33a1fc725..66f20e687 100644
--- a/UICatalog/UICatalog.cs
+++ b/UICatalog/UICatalog.cs
@@ -635,19 +635,27 @@ namespace UICatalog {
private static void OpenUrl (string url)
{
try {
- Process.Start (url);
- } catch {
- // hack because of this: https://github.com/dotnet/corefx/issues/10361
if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
url = url.Replace ("&", "^&");
Process.Start (new ProcessStartInfo ("cmd", $"/c start {url}") { CreateNoWindow = true });
} else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
- Process.Start ("xdg-open", url);
+ using (var process = new Process {
+ StartInfo = new ProcessStartInfo {
+ FileName = "xdg-open",
+ Arguments = url,
+ RedirectStandardError = true,
+ RedirectStandardOutput = true,
+ CreateNoWindow = true,
+ UseShellExecute = false
+ }
+ }) {
+ process.Start ();
+ }
} else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
Process.Start ("open", url);
- } else {
- throw;
}
+ } catch {
+ throw;
}
}
}
diff --git a/UnitTests/ClipboardTests.cs b/UnitTests/ClipboardTests.cs
index 3ee4fc3c9..d12aa852a 100644
--- a/UnitTests/ClipboardTests.cs
+++ b/UnitTests/ClipboardTests.cs
@@ -1,4 +1,6 @@
-using Xunit;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Xunit;
namespace Terminal.Gui.Core {
public class ClipboardTests {
@@ -9,9 +11,321 @@ namespace Terminal.Gui.Core {
var clipText = "This is a clipboard unit test.";
Clipboard.Contents = clipText;
+
+ Application.Iteration += () => Application.RequestStop ();
+
+ Application.Run ();
+
Assert.Equal (clipText, Clipboard.Contents);
Application.Shutdown ();
}
+
+ [Fact]
+ public void IsSupported_Get ()
+ {
+ Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+ if (Clipboard.IsSupported) {
+ Assert.True (Clipboard.IsSupported);
+ } else {
+ Assert.False (Clipboard.IsSupported);
+ }
+
+ Application.Shutdown ();
+ }
+
+ [Fact]
+ public void TryGetClipboardData_Gets_From_OS_Clipboard ()
+ {
+ Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+ var clipText = "Trying to get from the OS clipboard.";
+ Clipboard.Contents = clipText;
+
+ Application.Iteration += () => Application.RequestStop ();
+
+ Application.Run ();
+
+ if (Clipboard.IsSupported) {
+ Assert.True (Clipboard.TryGetClipboardData (out string result));
+ Assert.Equal (clipText, result);
+ } else {
+ Assert.False (Clipboard.TryGetClipboardData (out string result));
+ Assert.NotEqual (clipText, result);
+ }
+
+ Application.Shutdown ();
+ }
+
+ [Fact]
+ public void TrySetClipboardData_Sets_The_OS_Clipboard ()
+ {
+ Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+ var clipText = "Trying to set the OS clipboard.";
+ if (Clipboard.IsSupported) {
+ Assert.True (Clipboard.TrySetClipboardData (clipText));
+ } else {
+ Assert.False (Clipboard.TrySetClipboardData (clipText));
+ }
+
+ Application.Iteration += () => Application.RequestStop ();
+
+ Application.Run ();
+
+ if (Clipboard.IsSupported) {
+ Assert.Equal (clipText, Clipboard.Contents);
+ } else {
+ Assert.NotEqual (clipText, Clipboard.Contents);
+ }
+
+ Application.Shutdown ();
+ }
+
+ [Fact]
+ public void Contents_Gets_From_OS_Clipboard ()
+ {
+ Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+ var clipText = "This is a clipboard unit test to get clipboard from OS.";
+ var exit = false;
+
+ Application.Iteration += () => {
+ if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
+ // using (Process clipExe = new Process {
+ // StartInfo = new ProcessStartInfo {
+ // RedirectStandardInput = true,
+ // FileName = "clip"
+ // }
+ // }) {
+ // clipExe.Start ();
+ // clipExe.StandardInput.Write (clipText);
+ // clipExe.StandardInput.Close ();
+ // var result = clipExe.WaitForExit (500);
+ // if (result) {
+ // clipExe.WaitForExit ();
+ // }
+ // }
+
+ using (Process pwsh = new Process {
+ StartInfo = new ProcessStartInfo {
+ FileName = "powershell",
+ Arguments = $"-command \"Set-Clipboard -Value \\\"{clipText}\\\"\""
+ }
+ }) {
+ pwsh.Start ();
+ pwsh.WaitForExit ();
+ }
+ } else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
+ using (Process copy = new Process {
+ StartInfo = new ProcessStartInfo {
+ RedirectStandardInput = true,
+ FileName = "pbcopy"
+ }
+ }) {
+ copy.Start ();
+ copy.StandardInput.Write (clipText);
+ copy.StandardInput.Close ();
+ copy.WaitForExit ();
+ }
+ } else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
+ if (Is_WSL_Platform ()) {
+ try {
+ using (Process bash = new Process {
+ StartInfo = new ProcessStartInfo {
+ FileName = "powershell.exe",
+ Arguments = $"-noprofile -command \"Set-Clipboard -Value \\\"{clipText}\\\"\""
+ }
+ }) {
+ bash.Start ();
+ bash.WaitForExit ();
+ }
+
+ //using (Process clipExe = new Process {
+ // StartInfo = new ProcessStartInfo {
+ // RedirectStandardInput = true,
+ // FileName = "clip.exe"
+ // }
+ //}) {
+ // clipExe.Start ();
+ // clipExe.StandardInput.Write (clipText);
+ // clipExe.StandardInput.Close ();
+ // clipExe.WaitForExit ();
+ // //var result = clipExe.WaitForExit (500);
+ // //if (result) {
+ // // clipExe.WaitForExit ();
+ // //}
+ //}
+ } catch {
+ exit = true;
+ }
+ Application.RequestStop ();
+ return;
+ }
+ if (exit = xclipExists () == false) {
+ // xclip doesn't exist then exit.
+ Application.RequestStop ();
+ return;
+ }
+
+ using (Process bash = new Process {
+ StartInfo = new ProcessStartInfo {
+ FileName = "bash",
+ Arguments = $"-c \"xclip -sel clip -i\"",
+ RedirectStandardInput = true,
+ }
+ }) {
+ bash.Start ();
+ bash.StandardInput.Write (clipText);
+ bash.StandardInput.Close ();
+ bash.WaitForExit ();
+ }
+ }
+
+ Application.RequestStop ();
+ };
+
+ Application.Run ();
+
+ if (!exit) {
+ Assert.Equal (clipText, Clipboard.Contents);
+ }
+
+ Application.Shutdown ();
+ }
+
+ [Fact]
+ public void Contents_Sets_The_OS_Clipboard ()
+ {
+ Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
+ var clipText = "This is a clipboard unit test to set the OS clipboard.";
+ var clipReadText = "";
+ var exit = false;
+
+ Application.Iteration += () => {
+ Clipboard.Contents = clipText;
+
+ if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
+ using (Process pwsh = new Process {
+ StartInfo = new ProcessStartInfo {
+ RedirectStandardOutput = true,
+ FileName = "powershell.exe",
+ Arguments = "-noprofile -command \"Get-Clipboard\""
+ }
+ }) {
+ pwsh.Start ();
+ clipReadText = pwsh.StandardOutput.ReadToEnd ().TrimEnd ();
+ pwsh.StandardOutput.Close ();
+ pwsh.WaitForExit ();
+ }
+ } else if (RuntimeInformation.IsOSPlatform (OSPlatform.OSX)) {
+ using (Process paste = new Process {
+ StartInfo = new ProcessStartInfo {
+ RedirectStandardOutput = true,
+ FileName = "pbpaste"
+ }
+ }) {
+ paste.Start ();
+ clipReadText = paste.StandardOutput.ReadToEnd ();
+ paste.StandardOutput.Close ();
+ paste.WaitForExit ();
+ }
+ } else if (RuntimeInformation.IsOSPlatform (OSPlatform.Linux)) {
+ if (Is_WSL_Platform ()) {
+ try {
+ using (Process bash = new Process {
+ StartInfo = new ProcessStartInfo {
+ RedirectStandardOutput = true,
+ FileName = "powershell.exe",
+ Arguments = "-noprofile -command \"Get-Clipboard\""
+ }
+ }) {
+ bash.Start ();
+ clipReadText = bash.StandardOutput.ReadToEnd ();
+ bash.StandardOutput.Close ();
+ bash.WaitForExit ();
+ }
+ } catch {
+ exit = true;
+ }
+ Application.RequestStop ();
+ }
+ if (exit = xclipExists () == false) {
+ // xclip doesn't exist then exit.
+ Application.RequestStop ();
+ }
+
+ using (Process bash = new Process {
+ StartInfo = new ProcessStartInfo {
+ RedirectStandardOutput = true,
+ FileName = "bash",
+ Arguments = $"-c \"xclip -sel clip -o\""
+ }
+ }) {
+ bash.Start ();
+ clipReadText = bash.StandardOutput.ReadToEnd ();
+ bash.StandardOutput.Close ();
+ bash.WaitForExit ();
+ }
+ }
+
+ Application.RequestStop ();
+ };
+
+ Application.Run ();
+
+ if (!exit) {
+ Assert.Equal (clipText, clipReadText);
+ }
+
+ Application.Shutdown ();
+ }
+
+ bool Is_WSL_Platform ()
+ {
+ using (Process bash = new Process {
+ StartInfo = new ProcessStartInfo {
+ FileName = "bash",
+ Arguments = $"-c \"uname -a\"",
+ RedirectStandardOutput = true,
+ }
+ }) {
+ bash.Start ();
+ var result = bash.StandardOutput.ReadToEnd ();
+ var isWSL = false;
+ if (result.Contains ("microsoft") && result.Contains ("WSL")) {
+ isWSL = true;
+ }
+ bash.StandardOutput.Close ();
+ bash.WaitForExit ();
+ return isWSL;
+ }
+ }
+
+ bool xclipExists ()
+ {
+ try {
+ using (Process bash = new Process {
+ StartInfo = new ProcessStartInfo {
+ FileName = "bash",
+ Arguments = $"-c \"which xclip\"",
+ RedirectStandardOutput = true,
+ }
+ }) {
+ bash.Start ();
+ bool exist = bash.StandardOutput.ReadToEnd ().TrimEnd () != "";
+ bash.StandardOutput.Close ();
+ bash.WaitForExit ();
+ if (exist) {
+ return true;
+ }
+ }
+ return false;
+ } catch (System.Exception) {
+ return false;
+ }
+ }
}
}