|
- // Copyright 2013 @atotto. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
-
- // +build windows
-
- package clipboard
-
- import (
- "syscall"
- "time"
- "unsafe"
- )
-
- const (
- cfUnicodetext = 13
- gmemMoveable = 0x0002
- )
-
- var (
- user32 = syscall.MustLoadDLL("user32")
- openClipboard = user32.MustFindProc("OpenClipboard")
- closeClipboard = user32.MustFindProc("CloseClipboard")
- emptyClipboard = user32.MustFindProc("EmptyClipboard")
- getClipboardData = user32.MustFindProc("GetClipboardData")
- setClipboardData = user32.MustFindProc("SetClipboardData")
-
- kernel32 = syscall.NewLazyDLL("kernel32")
- globalAlloc = kernel32.NewProc("GlobalAlloc")
- globalFree = kernel32.NewProc("GlobalFree")
- globalLock = kernel32.NewProc("GlobalLock")
- globalUnlock = kernel32.NewProc("GlobalUnlock")
- lstrcpy = kernel32.NewProc("lstrcpyW")
- )
-
- // waitOpenClipboard opens the clipboard, waiting for up to a second to do so.
- func waitOpenClipboard() error {
- started := time.Now()
- limit := started.Add(time.Second)
- var r uintptr
- var err error
- for time.Now().Before(limit) {
- r, _, err = openClipboard.Call(0)
- if r != 0 {
- return nil
- }
- time.Sleep(time.Millisecond)
- }
- return err
- }
-
- func readAll() (string, error) {
- err := waitOpenClipboard()
- if err != nil {
- return "", err
- }
- defer closeClipboard.Call()
-
- h, _, err := getClipboardData.Call(cfUnicodetext)
- if h == 0 {
- return "", err
- }
-
- l, _, err := globalLock.Call(h)
- if l == 0 {
- return "", err
- }
-
- text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:])
-
- r, _, err := globalUnlock.Call(h)
- if r == 0 {
- return "", err
- }
-
- return text, nil
- }
-
- func writeAll(text string) error {
- err := waitOpenClipboard()
- if err != nil {
- return err
- }
- defer closeClipboard.Call()
-
- r, _, err := emptyClipboard.Call(0)
- if r == 0 {
- return err
- }
-
- data := syscall.StringToUTF16(text)
-
- // "If the hMem parameter identifies a memory object, the object must have
- // been allocated using the function with the GMEM_MOVEABLE flag."
- h, _, err := globalAlloc.Call(gmemMoveable, uintptr(len(data)*int(unsafe.Sizeof(data[0]))))
- if h == 0 {
- return err
- }
- defer func() {
- if h != 0 {
- globalFree.Call(h)
- }
- }()
-
- l, _, err := globalLock.Call(h)
- if l == 0 {
- return err
- }
-
- r, _, err = lstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0])))
- if r == 0 {
- return err
- }
-
- r, _, err = globalUnlock.Call(h)
- if r == 0 {
- if err.(syscall.Errno) != 0 {
- return err
- }
- }
-
- r, _, err = setClipboardData.Call(cfUnicodetext, h)
- if r == 0 {
- return err
- }
- h = 0 // suppress deferred cleanup
- return nil
- }
|