add more feature
This commit is contained in:
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() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
2
go.mod
2
go.mod
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
2
go.sum
2
go.sum
@ -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))
|
1
writehandle_windows.go
Normal file
1
writehandle_windows.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package clipboard
|
Loading…
x
Reference in New Issue
Block a user