summaryrefslogtreecommitdiff
path: root/scripts/windows_input/Native.cs
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/windows_input/Native.cs')
-rw-r--r--scripts/windows_input/Native.cs63
1 files changed, 56 insertions, 7 deletions
diff --git a/scripts/windows_input/Native.cs b/scripts/windows_input/Native.cs
index 5f941f1a..42b387b1 100644
--- a/scripts/windows_input/Native.cs
+++ b/scripts/windows_input/Native.cs
@@ -115,6 +115,7 @@ namespace HerdrInputGauntlet {
[DllImport("user32.dll")] static extern bool CloseClipboard();
[DllImport("user32.dll")] static extern bool EmptyClipboard();
[DllImport("user32.dll")] static extern IntPtr SetClipboardData(uint format,IntPtr value);
+ [DllImport("user32.dll",CharSet=CharSet.Unicode)] static extern uint RegisterClipboardFormat(string format);
[DllImport("kernel32.dll")] static extern IntPtr GlobalAlloc(uint flags,UIntPtr size);
[DllImport("kernel32.dll")] static extern IntPtr GlobalLock(IntPtr memory);
[DllImport("kernel32.dll")] static extern bool GlobalUnlock(IntPtr memory);
@@ -142,6 +143,7 @@ namespace HerdrInputGauntlet {
}
public static uint SetEmptyClipboard(IntPtr owner,string text) {
+ if(owner==IntPtr.Zero) throw new Exception("Clipboard owner is required");
if(!OpenClipboard(owner)) throw new Exception("Clipboard busy; refusing replacement");
IntPtr memory=IntPtr.Zero;
try {
@@ -155,17 +157,64 @@ namespace HerdrInputGauntlet {
if(!EmptyClipboard() || SetClipboardData(13,memory)==IntPtr.Zero) throw new Exception("Clipboard write failed");
memory=IntPtr.Zero; // ownership transferred to Windows
} finally { if(memory!=IntPtr.Zero) GlobalFree(memory); CloseClipboard(); }
+ return AdoptClipboardLease(owner);
+ }
+ public static uint SetEmptyClipboardImage(IntPtr owner,string text) {
+ if(owner==IntPtr.Zero) throw new Exception("Clipboard owner is required");
+ if(!OpenClipboard(owner)) throw new Exception("Clipboard busy; refusing replacement");
+ IntPtr pngMemory=IntPtr.Zero,textMemory=IntPtr.Zero;
+ bool complete=false;
+ try {
+ if(CountClipboardFormats()!=0) throw new Exception("Clipboard changed or contains user data; refusing replacement");
+ byte[] png=Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAANSURBVBhXY/jPwPAfAAUAAf+mXJtdAAAAAElFTkSuQmCC");
+ pngMemory=GlobalAlloc(2,new UIntPtr((uint)png.Length));
+ if(pngMemory==IntPtr.Zero) throw new Exception("Clipboard allocation failed");
+ var pointer=GlobalLock(pngMemory);
+ if(pointer==IntPtr.Zero) throw new Exception("Clipboard allocation failed");
+ try { Marshal.Copy(png,0,pointer,png.Length); } finally { GlobalUnlock(pngMemory); }
+ if(!EmptyClipboard()) throw new Exception("Clipboard clear failed");
+ uint pngFormat=RegisterClipboardFormat("PNG");
+ if(pngFormat==0 || SetClipboardData(pngFormat,pngMemory)==IntPtr.Zero) throw new Exception("Clipboard image write failed");
+ pngMemory=IntPtr.Zero;
+ if(text!=null) {
+ byte[] data=Encoding.Unicode.GetBytes(text+"\0");
+ textMemory=GlobalAlloc(2,new UIntPtr((uint)data.Length));
+ if(textMemory==IntPtr.Zero) throw new Exception("Clipboard allocation failed");
+ pointer=GlobalLock(textMemory);
+ if(pointer==IntPtr.Zero) throw new Exception("Clipboard allocation failed");
+ try { Marshal.Copy(data,0,pointer,data.Length); } finally { GlobalUnlock(textMemory); }
+ if(SetClipboardData(13,textMemory)==IntPtr.Zero) throw new Exception("Clipboard text write failed");
+ textMemory=IntPtr.Zero;
+ }
+ complete=true;
+ } finally {
+ if(!complete) EmptyClipboard();
+ if(pngMemory!=IntPtr.Zero) GlobalFree(pngMemory);
+ if(textMemory!=IntPtr.Zero) GlobalFree(textMemory);
+ CloseClipboard();
+ }
+ return AdoptClipboardLease(owner);
+ }
+ static uint AdoptClipboardLease(IntPtr owner) {
// Closing can synthesize additional formats and advance the sequence.
- // Reopen before adopting it so another writer cannot become our lease.
- if(!OpenClipboard(owner)) throw new Exception("Clipboard busy; cannot establish test ownership");
+ uint sequence=GetClipboardSequenceNumber();
try {
- if(owner==IntPtr.Zero || GetClipboardOwner()!=owner) throw new Exception("Clipboard ownership changed; refusing cleanup lease");
- return GetClipboardSequenceNumber();
- } finally { CloseClipboard(); }
+ if(!OpenClipboard(owner)) throw new Exception("Clipboard busy; cannot establish test ownership");
+ try {
+ if(GetClipboardOwner()!=owner || GetClipboardSequenceNumber()!=sequence)
+ throw new Exception("Clipboard ownership changed; refusing cleanup lease");
+ return sequence;
+ } finally { CloseClipboard(); }
+ } catch(Exception error) {
+ if(!ClearOwnedClipboard(owner,sequence))
+ throw new Exception("Could not clean clipboard after ownership verification failed",error);
+ throw;
+ }
}
- public static bool ClearOwnedClipboard(uint sequence) {
+ public static bool ClearOwnedClipboard(IntPtr owner,uint sequence) {
+ if(owner==IntPtr.Zero) return false;
if(!OpenClipboard(IntPtr.Zero)) return false;
- try { return GetClipboardSequenceNumber()!=sequence || EmptyClipboard(); }
+ try { return GetClipboardSequenceNumber()!=sequence || GetClipboardOwner()!=owner || EmptyClipboard(); }
finally { CloseClipboard(); }
}
public static string Title(IntPtr hwnd) { var text=new StringBuilder(1024); GetWindowText(hwnd,text,text.Capacity); return text.ToString(); }