You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
3.2 KiB
Go
157 lines
3.2 KiB
Go
package clipboard
|
|
|
|
import (
|
|
"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(onlyMeta bool) (<-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 {
|
|
if !onlyMeta {
|
|
cb, err := Get()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if atomic.LoadUint32(&isListening) == 1 {
|
|
res <- cb
|
|
continue
|
|
}
|
|
} else {
|
|
cb, err := GetMeta()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if atomic.LoadUint32(&isListening) == 1 {
|
|
res <- cb
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}()
|
|
return res, nil
|
|
}
|