add more feature

master
兔子 8 months ago
parent 26e0bf5bb5
commit 568dd318c3

@ -3,18 +3,26 @@ package clipboard
import ( import (
"fmt" "fmt"
"testing" "testing"
"time"
) )
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
c, err := Get() lsn, err := Listen()
if err != nil { if err != nil {
t.Error(err) t.Fatal(err)
}
for {
select {
case cb := <-lsn:
fmt.Println(cb.plateform)
fmt.Println(cb.AvailableTypes())
fmt.Println(cb.Text())
fmt.Println(cb.HTML())
case <-time.After(60 * time.Second):
fmt.Println("not get clipboard data in 60s")
StopListen()
time.Sleep(time.Second * 15)
return
}
} }
fmt.Println(c.plateform)
fmt.Println(c.winOriginTypes)
fmt.Println(c.PrimaryType())
fmt.Println(c.AvailableTypes())
fmt.Println(c.Text())
fmt.Println(c.HTML())
fmt.Println(c.FilePaths())
} }

@ -2,6 +2,8 @@ package clipboard
import ( import (
"b612.me/win32api" "b612.me/win32api"
"fmt"
"runtime"
) )
var winformat = map[win32api.DWORD]string{ var winformat = map[win32api.DWORD]string{
@ -44,17 +46,19 @@ func Get() (Clipboard, error) {
} }
func innerGetClipboard() (Clipboard, error) { func innerGetClipboard() (Clipboard, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
var c = Clipboard{ var c = Clipboard{
plateform: "windows", plateform: "windows",
} }
err := win32api.OpenClipboard(0) err := win32api.OpenClipboard(0)
if err != nil { if err != nil {
return c, err return c, fmt.Errorf("OpenClipboard error: %v", err)
} }
defer win32api.CloseClipboard() defer win32api.CloseClipboard()
formats, err := win32api.GetUpdatedClipboardFormatsAll() formats, err := win32api.GetUpdatedClipboardFormatsAll()
if err != nil { if err != nil {
return c, err return c, fmt.Errorf("GetUpdatedClipboardFormatsAll error: %v", err)
} }
var firstFormatName, secondFormatName string var firstFormatName, secondFormatName string
var firstFormat, secondFormat int = 65535, 65535 var firstFormat, secondFormat int = 65535, 65535
@ -105,7 +109,7 @@ func innerGetClipboard() (Clipboard, error) {
} }
c.primaryData, err = AutoFetcher(firstFormatName) c.primaryData, err = AutoFetcher(firstFormatName)
if err != nil { if err != nil {
return c, err return c, fmt.Errorf("AutoFetcher error: %v", err)
} }
if secondFormatName != "" { if secondFormatName != "" {
switch secondFormatName { switch secondFormatName {
@ -121,12 +125,8 @@ func innerGetClipboard() (Clipboard, error) {
c.secondaryOriType = secondFormatName c.secondaryOriType = secondFormatName
c.secondaryData, err = AutoFetcher(secondFormatName) c.secondaryData, err = AutoFetcher(secondFormatName)
if err != nil { if err != nil {
return c, err return c, fmt.Errorf("AutoFetcher error: %v", err)
} }
} }
return c, nil return c, nil
} }
func GetTopMatch() {
}

@ -3,7 +3,7 @@ module b612.me/clipboard
go 1.21.2 go 1.21.2
require ( require (
b612.me/win32api v0.0.0-20240326080749-ad19f5cd4247 b612.me/win32api v0.0.0-20240328010943-f10bafb4e804
golang.org/x/image v0.15.0 golang.org/x/image v0.15.0
) )

@ -1,5 +1,7 @@
b612.me/win32api v0.0.0-20240326080749-ad19f5cd4247 h1:fDTZ1HzVtVpEcXqlsQB9O2AbtrbqiAruaRX1Yd7M9Z8= b612.me/win32api v0.0.0-20240326080749-ad19f5cd4247 h1:fDTZ1HzVtVpEcXqlsQB9O2AbtrbqiAruaRX1Yd7M9Z8=
b612.me/win32api v0.0.0-20240326080749-ad19f5cd4247/go.mod h1:sj66sFJDKElEjOR+0YhdSW6b4kq4jsXu4T5/Hnpyot0= b612.me/win32api v0.0.0-20240326080749-ad19f5cd4247/go.mod h1:sj66sFJDKElEjOR+0YhdSW6b4kq4jsXu4T5/Hnpyot0=
b612.me/win32api v0.0.0-20240328010943-f10bafb4e804 h1:eLeVqlAmljdycU1cP7svO8cY7vklan6mAuSR/BcfHMs=
b612.me/win32api v0.0.0-20240328010943-f10bafb4e804/go.mod h1:sj66sFJDKElEjOR+0YhdSW6b4kq4jsXu4T5/Hnpyot0=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=

@ -1,5 +1,145 @@
package clipboard package clipboard
func Listen() (<-chan Clipboard, error) import (
res := make(chan Clipboard) "b612.me/win32api"
"errors"
"fmt"
"sync/atomic"
"time"
)
var stopSign chan struct{}
var isListening uint32
/*
func listenMethod2() (<-chan Clipboard, error) {
if atomic.LoadUint32(&isListening) == 1 {
return nil, errors.New("Already listening")
}
atomic.StoreUint32(&isListening, 1)
res := make(chan Clipboard, 3)
stopSign = make(chan struct{})
hWnd, err := win32api.CreateWindowEx(0,
"Message",
"B612 Clipboard Listener",
0,
0, 0, 500, 500,
0, 0, 0, nil)
if hWnd == 0 || err != nil {
return nil, fmt.Errorf("Failed to create window: %v,hWnd:%v", err, hWnd)
}
set, err := win32api.AddClipboardFormatListener(hWnd)
if !set || err != nil {
return nil, fmt.Errorf("Failed to set clipboard listener: %v", err)
}
fetcher := make(chan struct{}, 8)
go fetchListener(hWnd, fetcher)
go func() {
for {
select {
case <-stopSign:
fmt.Println("stopped")
atomic.StoreUint32(&isListening, 0)
close(res)
close(stopSign)
win32api.RemoveClipboardFormatListener(win32api.HWND(hWnd))
win32api.DestoryWindow(hWnd)
return
case <-fetcher:
cb, err := Get()
if err != nil {
fmt.Println(err)
}
if atomic.LoadUint32(&isListening) == 1 {
res <- cb
continue
}
}
}
}()
return res, nil
}
func fetchListener(hWnd win32api.HWND, res chan struct{}) {
for {
var msg win32api.MSG
_, err := win32api.GetMessage(&msg, hWnd, 0, 0)
if msg.Message == 0x0012 {
return
}
if err == nil && win32api.DWORD(msg.Message) == win32api.WM_CLIPBOARDUPDATE {
res <- struct{}{}
}
}
}
*/
func PauseListen() error {
if atomic.LoadUint32(&isListening) == 0 {
return errors.New("Not listening")
}
atomic.StoreUint32(&isListening, 2)
return nil
}
func RecoverListen() error {
if atomic.LoadUint32(&isListening) == 0 {
return errors.New("Not Listening")
}
atomic.StoreUint32(&isListening, 1)
return nil
}
func StopListen() error {
defer func() {
if r := recover(); r != nil {
fmt.Println("StopListen panic:", r)
}
}()
if atomic.LoadUint32(&isListening) == 0 {
return nil
}
stopSign <- struct{}{}
return nil
}
func Listen() (<-chan Clipboard, error) {
if atomic.LoadUint32(&isListening) != 0 {
return nil, errors.New("Already listening")
}
atomic.StoreUint32(&isListening, 1)
res := make(chan Clipboard, 3)
stopSign = make(chan struct{})
go func() {
var storeSeq win32api.DWORD
for {
select {
case <-stopSign:
atomic.StoreUint32(&isListening, 0)
close(res)
close(stopSign)
return
case <-time.After(time.Millisecond * 900):
seq, err := win32api.GetClipboardSequenceNumber()
if err != nil {
continue
}
if seq != storeSeq {
storeSeq = seq
//fmt.Println("Clipboard updated", seq, storeSeq)
if atomic.LoadUint32(&isListening) == 1 {
cb, err := Get()
if err != nil {
continue
}
if atomic.LoadUint32(&isListening) == 1 {
res <- cb
continue
}
}
}
}
}
}()
return res, nil
} }

@ -5,6 +5,7 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"golang.org/x/image/bmp" "golang.org/x/image/bmp"
"image" "image"
"image/color" "image/color"
@ -18,16 +19,16 @@ import (
func fetchClipboardData(uFormat win32api.DWORD, fn func(p unsafe.Pointer, size uint32) ([]byte, error)) ([]byte, error) { func fetchClipboardData(uFormat win32api.DWORD, fn func(p unsafe.Pointer, size uint32) ([]byte, error)) ([]byte, error) {
mem, err := win32api.GetClipboardData(uFormat) mem, err := win32api.GetClipboardData(uFormat)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("GetClipboardData failed: %v", err)
} }
p, err := win32api.GlobalLock(mem) p, err := win32api.GlobalLock(mem)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("GlobalLock failed: %v", err)
} }
defer win32api.GlobalUnlock(mem) defer win32api.GlobalUnlock(mem)
size, err := win32api.GlobalSize(mem) size, err := win32api.GlobalSize(mem)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("GlobalSize failed: %v", err)
} }
if fn == nil { if fn == nil {
return defaultFetchFn(p, uint32(size)) return defaultFetchFn(p, uint32(size))

@ -0,0 +1 @@
package clipboard
Loading…
Cancel
Save