163 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			V
		
	
	
module clipboard
 | 
						|
 | 
						|
import time
 | 
						|
 | 
						|
struct WndClassEx {
 | 
						|
	cbSize u32
 | 
						|
    style u32
 | 
						|
    lpfnWndProc voidptr
 | 
						|
    cbClsExtra int
 | 
						|
    cbWndExtra int
 | 
						|
  	hInstance C.HINSTANCE
 | 
						|
    hIcon C.HICON
 | 
						|
    hCursor C.HCURSOR
 | 
						|
    hbrBackground C.HBRUSH
 | 
						|
    lpszMenuName &u16 // LPCWSTR
 | 
						|
    lpszClassName &u16
 | 
						|
    hIconSm &u16
 | 
						|
}
 | 
						|
 | 
						|
fn C.RegisterClassEx(class WndClassEx) int
 | 
						|
fn C.GetClipboardOwner() &C.HWND
 | 
						|
fn C.CreateWindowEx(dwExStyle i64, lpClassName &u16, lpWindowName &u16, dwStyle i64, x int, y int, nWidth int, nHeight int, hWndParent i64, hMenu voidptr, hInstance voidptr, lpParam voidptr) &C.HWND
 | 
						|
//fn C.MultiByteToWideChar(CodePage u32, dwFlags u16, lpMultiByteStr byteptr, cbMultiByte int, lpWideCharStr u16, cchWideChar int) int
 | 
						|
fn C.EmptyClipboard()
 | 
						|
fn C.CloseClipboard()
 | 
						|
fn C.GlobalAlloc(uFlag u32, size i64) C.HGLOBAL
 | 
						|
fn C.GlobalFree(buf C.HGLOBAL)
 | 
						|
fn C.GlobalLock(buf C.HGLOBAL)
 | 
						|
fn C.GlobalUnlock(buf C.HGLOBAL)
 | 
						|
fn C.SetClipboardData(uFormat u32, data voidptr) C.HANDLE
 | 
						|
fn C.GetClipboardData(uFormat u32) C.HANDLE
 | 
						|
fn C.DefWindowProc(hwnd C.HWND, msg u32, wParam C.WPARAM, lParam C.LPARAM) C.LRESULT
 | 
						|
fn C.SetLastError(error i64)
 | 
						|
fn C.OpenClipboard(hwnd C.HWND) int
 | 
						|
fn C.DestroyWindow(hwnd C.HWND)
 | 
						|
 | 
						|
struct Clipboard {
 | 
						|
    max_retries int
 | 
						|
    retry_delay int
 | 
						|
    mut:
 | 
						|
    hwnd C.HWND
 | 
						|
    foo int // TODO remove
 | 
						|
}
 | 
						|
 | 
						|
fn (cb &Clipboard) get_clipboard_lock() bool {
 | 
						|
	mut retries := cb.max_retries
 | 
						|
	mut last_error := u32(0)
 | 
						|
 | 
						|
	for {
 | 
						|
		retries--
 | 
						|
		if retries < 0 {
 | 
						|
			break
 | 
						|
		}
 | 
						|
        last_error = C.GetLastError()
 | 
						|
        if C.OpenClipboard(cb.hwnd) > 0 {
 | 
						|
            return true
 | 
						|
        } else if last_error != u32(C.ERROR_ACCESS_DENIED) {
 | 
						|
            return false
 | 
						|
        }
 | 
						|
 | 
						|
		time.sleep(cb.retry_delay)
 | 
						|
	}
 | 
						|
    C.SetLastError(last_error)
 | 
						|
    return false
 | 
						|
}
 | 
						|
 | 
						|
fn new_clipboard() &Clipboard {
 | 
						|
    mut cb := &Clipboard {
 | 
						|
        max_retries: 5
 | 
						|
        retry_delay: 5
 | 
						|
    }
 | 
						|
	class_name := "clipboard"
 | 
						|
    wndclass := WndClassEx {
 | 
						|
        cbSize: sizeof(WndClassEx)
 | 
						|
        lpfnWndProc: voidptr(&C.DefWindowProc)
 | 
						|
        lpszClassName: class_name.to_wide()
 | 
						|
		lpszMenuName: 0
 | 
						|
		hIconSm: 0
 | 
						|
    }
 | 
						|
    if C.RegisterClassEx(&wndclass) == 0 && C.GetLastError() != u32(C.ERROR_CLASS_ALREADY_EXISTS) {
 | 
						|
        println("Failed registering class.")
 | 
						|
    }
 | 
						|
    hwnd := C.CreateWindowEx(0, wndclass.lpszClassName, wndclass.lpszClassName, 0, 0, 0, 0, 0, C.HWND_MESSAGE, C.NULL, C.NULL, C.NULL)
 | 
						|
    if hwnd == C.NULL {
 | 
						|
        println("Error creating window!")
 | 
						|
    }
 | 
						|
    cb.hwnd = hwnd
 | 
						|
    return cb
 | 
						|
}
 | 
						|
 | 
						|
fn (cb &Clipboard) check_availability() bool {
 | 
						|
	return cb.hwnd != C.HWND(C.NULL)
 | 
						|
}
 | 
						|
 | 
						|
fn (cb &Clipboard) has_ownership() bool {
 | 
						|
    return C.GetClipboardOwner() == cb.hwnd
 | 
						|
}
 | 
						|
 | 
						|
fn (cb mut Clipboard) clear() {
 | 
						|
    if !cb.get_clipboard_lock() {return}
 | 
						|
    C.EmptyClipboard()
 | 
						|
    C.CloseClipboard()
 | 
						|
	cb.foo = 0
 | 
						|
}
 | 
						|
 | 
						|
fn (cb mut Clipboard) free(){
 | 
						|
    C.DestroyWindow(cb.hwnd)
 | 
						|
	cb.foo = 0
 | 
						|
}
 | 
						|
 | 
						|
// the string.to_wide doesn't work with SetClipboardData, don't know why
 | 
						|
fn to_wide(text string) &C.HGLOBAL {
 | 
						|
    len_required := C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, C.NULL, 0)
 | 
						|
    buf := C.GlobalAlloc(C.GMEM_MOVEABLE, sizeof(u16) * len_required)
 | 
						|
    if buf != C.HGLOBAL(C.NULL) {
 | 
						|
        mut locked := &u16(C.GlobalLock(buf))
 | 
						|
        C.MultiByteToWideChar(C.CP_UTF8, C.MB_ERR_INVALID_CHARS, text.str, text.len + 1, locked, len_required)
 | 
						|
        locked[len_required - 1] = u16(0)
 | 
						|
        C.GlobalUnlock(buf)
 | 
						|
    }
 | 
						|
    return buf
 | 
						|
}
 | 
						|
 | 
						|
fn (cb mut Clipboard) set_text(text string) bool {
 | 
						|
	cb.foo = 0
 | 
						|
    buf := to_wide(text)
 | 
						|
    if !cb.get_clipboard_lock() {
 | 
						|
        C.GlobalFree(buf)
 | 
						|
        return false
 | 
						|
    } else {
 | 
						|
        // EmptyClipboard must be called to properly update clipboard ownership
 | 
						|
        C.EmptyClipboard()
 | 
						|
        if C.SetClipboardData(C.CF_UNICODETEXT, buf) == C.HANDLE(C.NULL) {
 | 
						|
            println("SetClipboardData: Failed.")
 | 
						|
            C.CloseClipboard()
 | 
						|
            C.GlobalFree(buf)
 | 
						|
            return false
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // CloseClipboard appears to change the sequence number...
 | 
						|
    C.CloseClipboard()
 | 
						|
    return true
 | 
						|
}
 | 
						|
 | 
						|
fn (cb mut Clipboard) get_text() string {
 | 
						|
	cb.foo = 0
 | 
						|
    if !cb.get_clipboard_lock() {
 | 
						|
        return ""
 | 
						|
    }
 | 
						|
    h_data := C.GetClipboardData(C.CF_UNICODETEXT)
 | 
						|
    if h_data == C.HANDLE(C.NULL) {
 | 
						|
        C.CloseClipboard()
 | 
						|
        return ""
 | 
						|
    }
 | 
						|
    str := string_from_wide(&u16(C.GlobalLock(h_data)))
 | 
						|
    C.GlobalUnlock(h_data)
 | 
						|
    return str
 | 
						|
}
 | 
						|
 | 
						|
pub fn new_primary() &Clipboard {
 | 
						|
	panic('Primary clipboard is not supported on non-Linux systems.')
 | 
						|
}
 |