mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 17:05:38 +00:00
app/internal/window,app/internal/windows: implement Windows clipboard access
Update gio#31 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -6,12 +6,14 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
syscall "golang.org/x/sys/windows"
|
||||
@@ -378,6 +380,84 @@ func (w *window) NewContext() (Context, error) {
|
||||
return nil, errors.New("NewContext: no available backends")
|
||||
}
|
||||
|
||||
func (w *window) ReadClipboard() {
|
||||
w.readClipboard()
|
||||
}
|
||||
|
||||
func (w *window) readClipboard() error {
|
||||
if err := windows.OpenClipboard(w.hwnd); err != nil {
|
||||
return err
|
||||
}
|
||||
defer windows.CloseClipboard()
|
||||
mem, err := windows.GetClipboardData(windows.CF_UNICODETEXT)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr, err := windows.GlobalLock(mem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer windows.GlobalUnlock(mem)
|
||||
// Look for terminating null character.
|
||||
n := 0
|
||||
for {
|
||||
ch := *(*uint16)(unsafe.Pointer(ptr + uintptr(n)*2))
|
||||
if ch == 0 {
|
||||
break
|
||||
}
|
||||
n++
|
||||
}
|
||||
var u16 []uint16
|
||||
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&u16))
|
||||
hdr.Data = ptr
|
||||
hdr.Cap = n
|
||||
hdr.Len = n
|
||||
content := string(utf16.Decode(u16))
|
||||
go func() {
|
||||
w.w.Event(system.ClipboardEvent{Text: content})
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *window) WriteClipboard(s string) {
|
||||
w.writeClipboard(s)
|
||||
}
|
||||
|
||||
func (w *window) writeClipboard(s string) error {
|
||||
u16 := utf16.Encode([]rune(s))
|
||||
// Data must be null terminated.
|
||||
u16 = append(u16, 0)
|
||||
if err := windows.OpenClipboard(w.hwnd); err != nil {
|
||||
return err
|
||||
}
|
||||
defer windows.CloseClipboard()
|
||||
if err := windows.EmptyClipboard(); err != nil {
|
||||
return err
|
||||
}
|
||||
n := len(u16) * int(unsafe.Sizeof(u16[0]))
|
||||
mem, err := windows.GlobalAlloc(n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ptr, err := windows.GlobalLock(mem)
|
||||
if err != nil {
|
||||
windows.GlobalFree(mem)
|
||||
return err
|
||||
}
|
||||
var u16v []uint16
|
||||
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&u16v))
|
||||
hdr.Data = ptr
|
||||
hdr.Cap = len(u16)
|
||||
hdr.Len = len(u16)
|
||||
copy(u16v, u16)
|
||||
windows.GlobalUnlock(mem)
|
||||
if err := windows.SetClipboardData(windows.CF_UNICODETEXT, mem); err != nil {
|
||||
windows.GlobalFree(mem)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *window) ShowTextInput(show bool) {}
|
||||
|
||||
func (w *window) HDC() syscall.Handle {
|
||||
|
||||
@@ -171,20 +171,31 @@ const (
|
||||
|
||||
PM_REMOVE = 0x0001
|
||||
PM_NOREMOVE = 0x0000
|
||||
|
||||
GHND = 0x0042
|
||||
|
||||
CF_UNICODETEXT = 13
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazySystemDLL("kernel32.dll")
|
||||
_GetModuleHandleW = kernel32.NewProc("GetModuleHandleW")
|
||||
_GlobalAlloc = kernel32.NewProc("GlobalAlloc")
|
||||
_GlobalFree = kernel32.NewProc("GlobalFree")
|
||||
_GlobalLock = kernel32.NewProc("GlobalLock")
|
||||
_GlobalUnlock = kernel32.NewProc("GlobalUnlock")
|
||||
|
||||
user32 = syscall.NewLazySystemDLL("user32.dll")
|
||||
_AdjustWindowRectEx = user32.NewProc("AdjustWindowRectEx")
|
||||
_CallMsgFilter = user32.NewProc("CallMsgFilterW")
|
||||
_CloseClipboard = user32.NewProc("CloseClipboard")
|
||||
_CreateWindowEx = user32.NewProc("CreateWindowExW")
|
||||
_DefWindowProc = user32.NewProc("DefWindowProcW")
|
||||
_DestroyWindow = user32.NewProc("DestroyWindow")
|
||||
_DispatchMessage = user32.NewProc("DispatchMessageW")
|
||||
_EmptyClipboard = user32.NewProc("EmptyClipboard")
|
||||
_GetClientRect = user32.NewProc("GetClientRect")
|
||||
_GetClipboardData = user32.NewProc("GetClipboardData")
|
||||
_GetDC = user32.NewProc("GetDC")
|
||||
_GetKeyState = user32.NewProc("GetKeyState")
|
||||
_GetMessage = user32.NewProc("GetMessageW")
|
||||
@@ -193,6 +204,7 @@ var (
|
||||
_LoadCursor = user32.NewProc("LoadCursorW")
|
||||
_MonitorFromPoint = user32.NewProc("MonitorFromPoint")
|
||||
_MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx")
|
||||
_OpenClipboard = user32.NewProc("OpenClipboard")
|
||||
_PeekMessage = user32.NewProc("PeekMessageW")
|
||||
_PostMessage = user32.NewProc("PostMessageW")
|
||||
_PostQuitMessage = user32.NewProc("PostQuitMessage")
|
||||
@@ -202,6 +214,7 @@ var (
|
||||
_ScreenToClient = user32.NewProc("ScreenToClient")
|
||||
_ShowWindow = user32.NewProc("ShowWindow")
|
||||
_SetCapture = user32.NewProc("SetCapture")
|
||||
_SetClipboardData = user32.NewProc("SetClipboardData")
|
||||
_SetForegroundWindow = user32.NewProc("SetForegroundWindow")
|
||||
_SetFocus = user32.NewProc("SetFocus")
|
||||
_SetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
|
||||
@@ -217,14 +230,6 @@ var (
|
||||
_GetDeviceCaps = gdi32.NewProc("GetDeviceCaps")
|
||||
)
|
||||
|
||||
func GetModuleHandle() (syscall.Handle, error) {
|
||||
h, _, err := _GetModuleHandleW.Call(uintptr(0))
|
||||
if h == 0 {
|
||||
return 0, fmt.Errorf("GetModuleHandleW failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(h), nil
|
||||
}
|
||||
|
||||
func AdjustWindowRectEx(r *Rect, dwStyle uint32, bMenu int, dwExStyle uint32) {
|
||||
_AdjustWindowRectEx.Call(uintptr(unsafe.Pointer(r)), uintptr(dwStyle), uintptr(bMenu), uintptr(dwExStyle))
|
||||
issue34474KeepAlive(r)
|
||||
@@ -236,6 +241,14 @@ func CallMsgFilter(m *Msg, nCode uintptr) bool {
|
||||
return r != 0
|
||||
}
|
||||
|
||||
func CloseClipboard() error {
|
||||
r, _, err := _CloseClipboard.Call()
|
||||
if r == 0 {
|
||||
return fmt.Errorf("CloseClipboard: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateWindowEx(dwExStyle uint32, lpClassName uint16, lpWindowName string, dwStyle uint32, x, y, w, h int32, hWndParent, hMenu, hInstance syscall.Handle, lpParam uintptr) (syscall.Handle, error) {
|
||||
wname := syscall.StringToUTF16Ptr(lpWindowName)
|
||||
hwnd, _, err := _CreateWindowEx.Call(
|
||||
@@ -270,11 +283,27 @@ func DispatchMessage(m *Msg) {
|
||||
issue34474KeepAlive(m)
|
||||
}
|
||||
|
||||
func EmptyClipboard() error {
|
||||
r, _, err := _EmptyClipboard.Call()
|
||||
if r == 0 {
|
||||
return fmt.Errorf("EmptyClipboard: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetClientRect(hwnd syscall.Handle, r *Rect) {
|
||||
_GetClientRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(r)))
|
||||
issue34474KeepAlive(r)
|
||||
}
|
||||
|
||||
func GetClipboardData(format uint32) (syscall.Handle, error) {
|
||||
r, _, err := _GetClipboardData.Call(uintptr(format))
|
||||
if r == 0 {
|
||||
return 0, fmt.Errorf("GetClipboardData: %v", err)
|
||||
}
|
||||
return syscall.Handle(r), nil
|
||||
}
|
||||
|
||||
func GetDC(hwnd syscall.Handle) (syscall.Handle, error) {
|
||||
hdc, _, err := _GetDC.Call(uintptr(hwnd))
|
||||
if hdc == 0 {
|
||||
@@ -283,6 +312,14 @@ func GetDC(hwnd syscall.Handle) (syscall.Handle, error) {
|
||||
return syscall.Handle(hdc), nil
|
||||
}
|
||||
|
||||
func GetModuleHandle() (syscall.Handle, error) {
|
||||
h, _, err := _GetModuleHandleW.Call(uintptr(0))
|
||||
if h == 0 {
|
||||
return 0, fmt.Errorf("GetModuleHandleW failed: %v", err)
|
||||
}
|
||||
return syscall.Handle(h), nil
|
||||
}
|
||||
|
||||
func getDeviceCaps(hdc syscall.Handle, index int32) int {
|
||||
c, _, _ := _GetDeviceCaps.Call(uintptr(hdc), uintptr(index))
|
||||
return int(c)
|
||||
@@ -330,6 +367,30 @@ func GetMessageTime() time.Duration {
|
||||
return time.Duration(r) * time.Millisecond
|
||||
}
|
||||
|
||||
func GlobalAlloc(size int) (syscall.Handle, error) {
|
||||
r, _, err := _GlobalAlloc.Call(GHND, uintptr(size))
|
||||
if r == 0 {
|
||||
return 0, fmt.Errorf("GlobalAlloc: %v", err)
|
||||
}
|
||||
return syscall.Handle(r), nil
|
||||
}
|
||||
|
||||
func GlobalFree(h syscall.Handle) {
|
||||
_GlobalFree.Call(uintptr(h))
|
||||
}
|
||||
|
||||
func GlobalLock(h syscall.Handle) (uintptr, error) {
|
||||
r, _, err := _GlobalLock.Call(uintptr(h))
|
||||
if r == 0 {
|
||||
return 0, fmt.Errorf("GlobalLock: %v", err)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func GlobalUnlock(h syscall.Handle) {
|
||||
_GlobalUnlock.Call(uintptr(h))
|
||||
}
|
||||
|
||||
func KillTimer(hwnd syscall.Handle, nIDEvent uintptr) error {
|
||||
r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), 0, 0)
|
||||
if r == 0 {
|
||||
@@ -360,6 +421,14 @@ func MsgWaitForMultipleObjectsEx(nCount uint32, pHandles uintptr, millis, mask,
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func OpenClipboard(hwnd syscall.Handle) error {
|
||||
r, _, err := _OpenClipboard.Call(uintptr(hwnd))
|
||||
if r == 0 {
|
||||
return fmt.Errorf("OpenClipboard: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func PeekMessage(m *Msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool {
|
||||
r, _, _ := _PeekMessage.Call(uintptr(unsafe.Pointer(m)), uintptr(hwnd), uintptr(wMsgFilterMin), uintptr(wMsgFilterMax), uintptr(wRemoveMsg))
|
||||
issue34474KeepAlive(m)
|
||||
@@ -413,6 +482,14 @@ func SetCapture(hwnd syscall.Handle) syscall.Handle {
|
||||
return syscall.Handle(r)
|
||||
}
|
||||
|
||||
func SetClipboardData(format uint32, mem syscall.Handle) error {
|
||||
r, _, err := _SetClipboardData.Call(uintptr(format), uintptr(mem))
|
||||
if r == 0 {
|
||||
return fmt.Errorf("SetClipboardData: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error {
|
||||
r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc)
|
||||
if r == 0 {
|
||||
|
||||
Reference in New Issue
Block a user