@crosscopy/clipboard 0.1.0-beta → 0.1.0-beta-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/go-clipboard/.idea/go-clipboard.iml +0 -9
- package/go-clipboard/.idea/modules.xml +0 -8
- package/go-clipboard/.idea/vcs.xml +0 -6
- package/go-clipboard/Makefile +0 -8
- package/go-clipboard/example/README.md +0 -11
- package/go-clipboard/example/cb-ops.js +0 -34
- package/go-clipboard/example/client.go +0 -131
- package/go-clipboard/example/server.js +0 -48
- package/go-clipboard/main.go +0 -131
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crosscopy/clipboard",
|
|
3
|
-
"version": "0.1.0-beta",
|
|
3
|
+
"version": "0.1.0-beta-1",
|
|
4
4
|
"description": "Cross Platform Clipboard listener that detects both text and image update in clipboard",
|
|
5
5
|
"source": "index.ts",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
43
|
"dist",
|
|
44
|
-
"go-clipboard",
|
|
44
|
+
"go-clipboard/binaries",
|
|
45
45
|
"README.md"
|
|
46
46
|
]
|
|
47
47
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<module type="WEB_MODULE" version="4">
|
|
3
|
-
<component name="Go" enabled="true" />
|
|
4
|
-
<component name="NewModuleRootManager">
|
|
5
|
-
<content url="file://$MODULE_DIR$" />
|
|
6
|
-
<orderEntry type="inheritedJdk" />
|
|
7
|
-
<orderEntry type="sourceFolder" forTests="false" />
|
|
8
|
-
</component>
|
|
9
|
-
</module>
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/.idea/go-clipboard.iml" filepath="$PROJECT_DIR$/.idea/go-clipboard.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
package/go-clipboard/Makefile
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
build:
|
|
2
|
-
GOOS=darwin GORACH=arm64 go build -o binaries/go-clipboard-darwin-arm64
|
|
3
|
-
GOOS=darwin GORACH=amd64 go build -o binaries/go-clipboard-darwin-x64
|
|
4
|
-
GOOS=linux GORACH=386 go build -o binaries/go-clipboard-linux-386
|
|
5
|
-
GOOS=linux GORACH=arm go build -o binaries/go-clipboard-linux-arm
|
|
6
|
-
GOOS=linux GORACH=arm64 go build -o binaries/go-clipboard-linux-arm64
|
|
7
|
-
GOOS=linux GORACH=amd64 go build -o binaries/go-clipboard-linux-x64
|
|
8
|
-
GOOS=windows GORACH=amd64 go build -o binaries/go-clipboard-win32-x64.exe
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# Example for IPC between Golang and Nodejs on the context of Clipboard Update Listening
|
|
2
|
-
|
|
3
|
-
To run this example, within this folder
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
go build client.go && node server
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Then copy some text or take a screenshot and see what's printed to stdout and image saved to disk.
|
|
10
|
-
|
|
11
|
-
The screenshot image is updated for every screenshot you take.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const { execFile } = require("node:child_process");
|
|
2
|
-
const fs = require("fs");
|
|
3
|
-
|
|
4
|
-
const execPath = "./client";
|
|
5
|
-
// const childWriteText = execFile(execPath, ["WRITE_TEXT"]);
|
|
6
|
-
// childWriteText.stdin.write("huakun zui shuai")
|
|
7
|
-
// childWriteText.stdin.end()
|
|
8
|
-
// childWriteText.stdout.on('data', (d) => {
|
|
9
|
-
// console.log(d);
|
|
10
|
-
// })
|
|
11
|
-
|
|
12
|
-
const childWriteImage = execFile(execPath, ["WRITE_IMAGE"]);
|
|
13
|
-
const base64img =
|
|
14
|
-
"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";
|
|
15
|
-
childWriteImage.stdin.write(base64img);
|
|
16
|
-
childWriteImage.stdin.end();
|
|
17
|
-
|
|
18
|
-
// const childWriteImage = execFile(execPath, ["WRITE_IMAGE"]);
|
|
19
|
-
// const base64img = "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"
|
|
20
|
-
// childWriteImage.stdin.write(base64img)
|
|
21
|
-
// childWriteImage.stdin.end()
|
|
22
|
-
|
|
23
|
-
// const childtext = execFile(execPath, ["READ_TEXT"]);
|
|
24
|
-
// childtext.stdout.on("data", (data) => {
|
|
25
|
-
// console.log(Buffer.from(data, 'base64').toString());
|
|
26
|
-
// });
|
|
27
|
-
|
|
28
|
-
setTimeout(() => {
|
|
29
|
-
const childimg = execFile(execPath, ["READ_IMAGE"]);
|
|
30
|
-
childimg.stdout.on("data", (data) => {
|
|
31
|
-
const imgBuf = Buffer.from(data, "base64");
|
|
32
|
-
fs.writeFileSync("test.png", imgBuf);
|
|
33
|
-
});
|
|
34
|
-
}, 1000);
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"bufio"
|
|
5
|
-
"context"
|
|
6
|
-
"encoding/base64"
|
|
7
|
-
"fmt"
|
|
8
|
-
"log"
|
|
9
|
-
"net"
|
|
10
|
-
"os"
|
|
11
|
-
"sync"
|
|
12
|
-
|
|
13
|
-
"golang.design/x/clipboard"
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
// All possible ways to call this program
|
|
17
|
-
// 1. client (set up TCP socket client to connect to default port 8090)
|
|
18
|
-
// 2. client 9999 (set up TCP socket client to connect to custom port 9999)
|
|
19
|
-
// 3. client READ_TEXT (Read Text from clipboard and output to stdout)
|
|
20
|
-
// 4. client READ_IMAGE (Read Image from clipboard and output to stdout in base64 encoding, whoever is reading this must decode it into bytes)
|
|
21
|
-
// 5. client WRITE_TEXT (Write Text to clipboard, data passed in through stdin, in base64 format (since there may be '\n' in raw data, base64 makes sure this doesn't exist))
|
|
22
|
-
// 6. client WRITE_IMAGE (Write Image to clipboard, data passed in through stdin, read as string, in base64 format. Have to decode into buffer before saving to clipboard)
|
|
23
|
-
func main() {
|
|
24
|
-
err := clipboard.Init()
|
|
25
|
-
var port = "8090"
|
|
26
|
-
if len(os.Args) == 2 {
|
|
27
|
-
if os.Args[1] == "READ_TEXT" {
|
|
28
|
-
cbText := clipboard.Read(clipboard.FmtText)
|
|
29
|
-
fmt.Print(base64.StdEncoding.EncodeToString(cbText))
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if os.Args[1] == "READ_IMAGE" {
|
|
34
|
-
cbImage := clipboard.Read(clipboard.FmtImage)
|
|
35
|
-
fmt.Println(base64.StdEncoding.EncodeToString(cbImage))
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if os.Args[1] == "WRITE_TEXT" {
|
|
40
|
-
reader := bufio.NewReader(os.Stdin)
|
|
41
|
-
text, _ := reader.ReadString('\n')
|
|
42
|
-
clipboard.Write(clipboard.FmtText, []byte(text))
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// This works with base64 string
|
|
47
|
-
if os.Args[1] == "WRITE_IMAGE" {
|
|
48
|
-
reader := bufio.NewReader(os.Stdin)
|
|
49
|
-
data, _ := reader.ReadString('\n')
|
|
50
|
-
imgBuf, _ := base64.StdEncoding.DecodeString(data)
|
|
51
|
-
clipboard.Write(clipboard.FmtImage, imgBuf)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
// If none of the above are true, then parent process is calling me for setting up a TCP socket connection
|
|
55
|
-
// for bidirectional communication (for clipboard listening)
|
|
56
|
-
// So, the second command line arg is port
|
|
57
|
-
port = os.Args[1]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// The rest of the code is for clipboard watching
|
|
61
|
-
// connect TCP socket to server
|
|
62
|
-
address := fmt.Sprintf("localhost:%s", port)
|
|
63
|
-
// setup a long connection, but not used to transfer clipboard data, only for message notifications
|
|
64
|
-
con, err := net.Dial("tcp", address)
|
|
65
|
-
checkErr(err)
|
|
66
|
-
defer con.Close()
|
|
67
|
-
|
|
68
|
-
// since we continuously watch clipboard update, use wait group keep go routines running
|
|
69
|
-
var wg sync.WaitGroup
|
|
70
|
-
// * this is how to write send message to parent process using stdout
|
|
71
|
-
msg := "connection from go"
|
|
72
|
-
_, err = con.Write([]byte(msg))
|
|
73
|
-
checkErr(err)
|
|
74
|
-
|
|
75
|
-
textCh := clipboard.Watch(context.TODO(), clipboard.FmtText)
|
|
76
|
-
imgCh := clipboard.Watch(context.TODO(), clipboard.FmtImage)
|
|
77
|
-
|
|
78
|
-
// the text and image clipboard listeners will send message using separate socket connection
|
|
79
|
-
// because closing socket channel is required for the socket server to know when to wrap up received data
|
|
80
|
-
// large data chunks have to be sent in multiple TCP packages which have a size limit
|
|
81
|
-
// the socket server keeps getting data, accumulating data by concatenating packets received, but when to stop?
|
|
82
|
-
// socket server wraps up the data chunks received upon connection close
|
|
83
|
-
// this is why we use short socket connections to send data
|
|
84
|
-
// con (the long socket connection) is only used for sending notifications instead of data
|
|
85
|
-
wg.Add(1)
|
|
86
|
-
go func() {
|
|
87
|
-
for data := range textCh {
|
|
88
|
-
textCon, err := net.Dial("tcp", address)
|
|
89
|
-
checkErr(err)
|
|
90
|
-
// fmt.Println("TEXT_CHANGED") // write TEXT_CHANGED to stdout for parent process to detect clipboard text update
|
|
91
|
-
// cbText := clipboard.Read(clipboard.FmtText)
|
|
92
|
-
payload := "TEXT_CHANGED:" + base64.StdEncoding.EncodeToString(data)
|
|
93
|
-
textCon.Write([]byte(payload))
|
|
94
|
-
textCon.Close()
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
}()
|
|
98
|
-
wg.Add(1)
|
|
99
|
-
go func() {
|
|
100
|
-
for data := range imgCh {
|
|
101
|
-
imgCon, err := net.Dial("tcp", address)
|
|
102
|
-
checkErr(err)
|
|
103
|
-
fmt.Println("IMAGE_CHANGED") // write TEXT_CHANGED to stdout for parent process to detect clipboard text update
|
|
104
|
-
base64Img := base64.StdEncoding.EncodeToString(data)
|
|
105
|
-
payload := "IMAGE_CHANGED:" + base64Img
|
|
106
|
-
log.Println(len(payload))
|
|
107
|
-
imgCon.Write([]byte(payload))
|
|
108
|
-
imgCon.Close()
|
|
109
|
-
}
|
|
110
|
-
}()
|
|
111
|
-
|
|
112
|
-
// this is used to receive data from socket server / parent process
|
|
113
|
-
// doesn't need to be large, no massive data will be sent
|
|
114
|
-
reply := make([]byte, 1024)
|
|
115
|
-
wg.Add(1)
|
|
116
|
-
go func() {
|
|
117
|
-
for {
|
|
118
|
-
_, err = con.Read(reply)
|
|
119
|
-
checkErr(err)
|
|
120
|
-
data := string(reply)
|
|
121
|
-
fmt.Println(data)
|
|
122
|
-
}
|
|
123
|
-
}()
|
|
124
|
-
wg.Wait()
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
func checkErr(err error) {
|
|
128
|
-
if err != nil {
|
|
129
|
-
log.Fatal(err)
|
|
130
|
-
}
|
|
131
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const net = require("net");
|
|
2
|
-
const fs = require("fs");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
const { execFile } = require("node:child_process");
|
|
5
|
-
|
|
6
|
-
const server = net.createServer(function (con) {
|
|
7
|
-
// client connected
|
|
8
|
-
let data = "";
|
|
9
|
-
|
|
10
|
-
// * demo of sending message to client,
|
|
11
|
-
// con.write("close");
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Accumulate data by concatenating chunks of received data
|
|
15
|
-
*/
|
|
16
|
-
con.on("data", (packet) => {
|
|
17
|
-
data += packet.toString();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* When socket connection closes, wrap up received data
|
|
22
|
-
*/
|
|
23
|
-
con.on("close", () => {
|
|
24
|
-
const strData = data.toString();
|
|
25
|
-
const subStr = strData.substring(0, 14);
|
|
26
|
-
if (subStr.includes("TEXT_CHANGED:")) {
|
|
27
|
-
console.log(
|
|
28
|
-
`Text Changed: ${Buffer.from(
|
|
29
|
-
strData.substring(13),
|
|
30
|
-
"base64"
|
|
31
|
-
).toString()}`
|
|
32
|
-
);
|
|
33
|
-
} else if (subStr.includes("IMAGE_CHANGED:")) {
|
|
34
|
-
const imageBase64 = strData.substring(14).toString("base64");
|
|
35
|
-
console.log(`Image Changed`);
|
|
36
|
-
fs.writeFileSync('test.png', Buffer.from(imageBase64, "base64"));
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
server.listen(8090, function () {
|
|
42
|
-
console.log("server is listening");
|
|
43
|
-
const execPath = path.join(__dirname, "client");
|
|
44
|
-
const child = execFile(execPath, [server.address().port]);
|
|
45
|
-
child.stdout.on("data", (data) => {
|
|
46
|
-
console.log("Received data from client socket stdout:\n" + data);
|
|
47
|
-
});
|
|
48
|
-
});
|
package/go-clipboard/main.go
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"bufio"
|
|
5
|
-
"context"
|
|
6
|
-
"encoding/base64"
|
|
7
|
-
"fmt"
|
|
8
|
-
"log"
|
|
9
|
-
"net"
|
|
10
|
-
"os"
|
|
11
|
-
"sync"
|
|
12
|
-
|
|
13
|
-
"golang.design/x/clipboard"
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
// All possible ways to call this program
|
|
17
|
-
// 1. client (set up TCP socket client to connect to default port 8090)
|
|
18
|
-
// 2. client 9999 (set up TCP socket client to connect to custom port 9999)
|
|
19
|
-
// 3. client READ_TEXT (Read Text from clipboard and output to stdout)
|
|
20
|
-
// 4. client READ_IMAGE (Read Image from clipboard and output to stdout in base64 encoding, whoever is reading this must decode it into bytes)
|
|
21
|
-
// 5. client WRITE_TEXT (Write Text to clipboard, data passed in through stdin, in base64 format (since there may be '\n' in raw data, base64 makes sure this doesn't exist))
|
|
22
|
-
// 6. client WRITE_IMAGE (Write Image to clipboard, data passed in through stdin, read as string, in base64 format. Have to decode into buffer before saving to clipboard)
|
|
23
|
-
func main() {
|
|
24
|
-
err := clipboard.Init()
|
|
25
|
-
var port = "8090"
|
|
26
|
-
if len(os.Args) == 2 {
|
|
27
|
-
if os.Args[1] == "READ_TEXT" {
|
|
28
|
-
cbText := clipboard.Read(clipboard.FmtText)
|
|
29
|
-
fmt.Print(base64.StdEncoding.EncodeToString(cbText))
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if os.Args[1] == "READ_IMAGE" {
|
|
34
|
-
cbImage := clipboard.Read(clipboard.FmtImage)
|
|
35
|
-
fmt.Println(base64.StdEncoding.EncodeToString(cbImage))
|
|
36
|
-
return
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if os.Args[1] == "WRITE_TEXT" {
|
|
40
|
-
reader := bufio.NewReader(os.Stdin)
|
|
41
|
-
text, _ := reader.ReadString('\n')
|
|
42
|
-
clipboard.Write(clipboard.FmtText, []byte(text))
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// This works with base64 string
|
|
47
|
-
if os.Args[1] == "WRITE_IMAGE" {
|
|
48
|
-
reader := bufio.NewReader(os.Stdin)
|
|
49
|
-
data, _ := reader.ReadString('\n')
|
|
50
|
-
imgBuf, _ := base64.StdEncoding.DecodeString(data)
|
|
51
|
-
clipboard.Write(clipboard.FmtImage, imgBuf)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
// If none of the above are true, then parent process is calling me for setting up a TCP socket connection
|
|
55
|
-
// for bidirectional communication (for clipboard listening)
|
|
56
|
-
// So, the second command line arg is port
|
|
57
|
-
port = os.Args[1]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// The rest of the code is for clipboard watching
|
|
61
|
-
// connect TCP socket to server
|
|
62
|
-
address := fmt.Sprintf("localhost:%s", port)
|
|
63
|
-
// setup a long connection, but not used to transfer clipboard data, only for message notifications
|
|
64
|
-
con, err := net.Dial("tcp", address)
|
|
65
|
-
checkErr(err)
|
|
66
|
-
defer con.Close()
|
|
67
|
-
|
|
68
|
-
// since we continuously watch clipboard update, use wait group keep go routines running
|
|
69
|
-
var wg sync.WaitGroup
|
|
70
|
-
// * this is how to write send message to parent process using stdout
|
|
71
|
-
msg := "connection from go"
|
|
72
|
-
_, err = con.Write([]byte(msg))
|
|
73
|
-
checkErr(err)
|
|
74
|
-
|
|
75
|
-
textCh := clipboard.Watch(context.TODO(), clipboard.FmtText)
|
|
76
|
-
imgCh := clipboard.Watch(context.TODO(), clipboard.FmtImage)
|
|
77
|
-
|
|
78
|
-
// the text and image clipboard listeners will send message using separate socket connection
|
|
79
|
-
// because closing socket channel is required for the socket server to know when to wrap up received data
|
|
80
|
-
// large data chunks have to be sent in multiple TCP packages which have a size limit
|
|
81
|
-
// the socket server keeps getting data, accumulating data by concatenating packets received, but when to stop?
|
|
82
|
-
// socket server wraps up the data chunks received upon connection close
|
|
83
|
-
// this is why we use short socket connections to send data
|
|
84
|
-
// con (the long socket connection) is only used for sending notifications instead of data
|
|
85
|
-
wg.Add(1)
|
|
86
|
-
go func() {
|
|
87
|
-
for data := range textCh {
|
|
88
|
-
textCon, err := net.Dial("tcp", address)
|
|
89
|
-
checkErr(err)
|
|
90
|
-
// fmt.Println("TEXT_CHANGED") // write TEXT_CHANGED to stdout for parent process to detect clipboard text update
|
|
91
|
-
// cbText := clipboard.Read(clipboard.FmtText)
|
|
92
|
-
payload := "TEXT_CHANGED:" + base64.StdEncoding.EncodeToString(data)
|
|
93
|
-
textCon.Write([]byte(payload))
|
|
94
|
-
textCon.Close()
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
}()
|
|
98
|
-
wg.Add(1)
|
|
99
|
-
go func() {
|
|
100
|
-
for data := range imgCh {
|
|
101
|
-
imgCon, err := net.Dial("tcp", address)
|
|
102
|
-
checkErr(err)
|
|
103
|
-
fmt.Println("IMAGE_CHANGED") // write TEXT_CHANGED to stdout for parent process to detect clipboard text update
|
|
104
|
-
base64Img := base64.StdEncoding.EncodeToString(data)
|
|
105
|
-
payload := "IMAGE_CHANGED:" + base64Img
|
|
106
|
-
log.Println(len(payload))
|
|
107
|
-
imgCon.Write([]byte(payload))
|
|
108
|
-
imgCon.Close()
|
|
109
|
-
}
|
|
110
|
-
}()
|
|
111
|
-
|
|
112
|
-
// this is used to receive data from socket server / parent process
|
|
113
|
-
// doesn't need to be large, no massive data will be sent
|
|
114
|
-
reply := make([]byte, 1024)
|
|
115
|
-
wg.Add(1)
|
|
116
|
-
go func() {
|
|
117
|
-
for {
|
|
118
|
-
_, err = con.Read(reply)
|
|
119
|
-
checkErr(err)
|
|
120
|
-
data := string(reply)
|
|
121
|
-
fmt.Println(data)
|
|
122
|
-
}
|
|
123
|
-
}()
|
|
124
|
-
wg.Wait()
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
func checkErr(err error) {
|
|
128
|
-
if err != nil {
|
|
129
|
-
log.Fatal(err)
|
|
130
|
-
}
|
|
131
|
-
}
|