@crosscopy/clipboard 0.1.0-beta
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/README.md +96 -0
- package/dist/demo.d.ts +1 -0
- package/dist/demo.js +94 -0
- package/dist/demo.js.map +1 -0
- package/dist/demo.mjs +87 -0
- package/dist/demo.mjs.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +55 -0
- package/dist/index.mjs.map +1 -0
- package/go-clipboard/.idea/go-clipboard.iml +9 -0
- package/go-clipboard/.idea/modules.xml +8 -0
- package/go-clipboard/.idea/vcs.xml +6 -0
- package/go-clipboard/Makefile +8 -0
- package/go-clipboard/binaries/go-clipboard-darwin-arm64 +0 -0
- package/go-clipboard/binaries/go-clipboard-darwin-x64 +0 -0
- package/go-clipboard/binaries/go-clipboard-linux-386 +0 -0
- package/go-clipboard/binaries/go-clipboard-linux-amd64 +0 -0
- package/go-clipboard/binaries/go-clipboard-linux-arm +0 -0
- package/go-clipboard/binaries/go-clipboard-linux-arm64 +0 -0
- package/go-clipboard/binaries/go-clipboard-linux-x64 +0 -0
- package/go-clipboard/binaries/go-clipboard-win32-x64.exe +0 -0
- package/go-clipboard/example/README.md +11 -0
- package/go-clipboard/example/cb-ops.js +34 -0
- package/go-clipboard/example/client.go +131 -0
- package/go-clipboard/example/server.js +48 -0
- package/go-clipboard/main.go +131 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# General Clipboard Listener
|
|
2
|
+
|
|
3
|
+
> A Cross-Platform clipboard listener that listens for both text and image (screenshots).
|
|
4
|
+
|
|
5
|
+
npm package: https://www.npmjs.com/package/general-clipboard-listener
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
`npm i @crosscopy/clipboard`
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
It has a very easy to use event-based system.
|
|
14
|
+
|
|
15
|
+
See [demo.ts](./demo.ts) for a demo.
|
|
16
|
+
|
|
17
|
+
Run `ts-node demo.ts`.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import clipboardEventListener from "./@crosscopy/clipboard";
|
|
21
|
+
|
|
22
|
+
console.log(clipboard.readTextSync());
|
|
23
|
+
console.log(await clipboard.readText());
|
|
24
|
+
const imgBuf = clipboard.readImageSync();
|
|
25
|
+
// console.log(imgBuf.toString("base64"));
|
|
26
|
+
// console.log(clipboard.readImageBase64Sync());
|
|
27
|
+
// await clipboard.writeImage(base64img); // add fake image to clipboard
|
|
28
|
+
clipboard.writeImageSync(base64img); // add fake image to clipboard
|
|
29
|
+
console.log(""); // give some time
|
|
30
|
+
console.assert(clipboard.readImageBase64Sync() === base64img);
|
|
31
|
+
|
|
32
|
+
// * test readimage
|
|
33
|
+
clipboard.writeImageSync(base64img);
|
|
34
|
+
console.log();
|
|
35
|
+
console.assert(
|
|
36
|
+
(await clipboard.readImage()).toString("base64") === base64img
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
await clipboard.writeImage(base64img);
|
|
40
|
+
console.log();
|
|
41
|
+
console.assert((await clipboard.readImageBase64()) === base64img);
|
|
42
|
+
clipboard.on("text", (text) => {
|
|
43
|
+
console.log(text);
|
|
44
|
+
});
|
|
45
|
+
clipboard.on("image", (data) => {
|
|
46
|
+
fs.writeFileSync("test.png", data);
|
|
47
|
+
});
|
|
48
|
+
clipboard.listen();
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
clipboard.close();
|
|
51
|
+
}, 10000);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Note
|
|
55
|
+
|
|
56
|
+
This is an important note. If you write some data and read it immediately using the `sync` APIs, you may not be able to get the data.
|
|
57
|
+
It needs a tiny bit of time to process. any code between the two lines should work, such as `console.log()`.
|
|
58
|
+
|
|
59
|
+
Here I use `await sleep(1)` to make it work.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
|
63
|
+
|
|
64
|
+
cb.writeTextSync("abc");
|
|
65
|
+
await sleep(1);
|
|
66
|
+
const text = cb.readTextSync();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
If this package becomes popular some day and people requires a fix, I will fix it. For now, this implementation is good enough for CrossCopy.
|
|
70
|
+
|
|
71
|
+
I never need to write and read immediately after unless during testing.
|
|
72
|
+
|
|
73
|
+
## Explanation
|
|
74
|
+
|
|
75
|
+
It's achieved using child process + `stdout`.
|
|
76
|
+
|
|
77
|
+
I took a golang version of the listener from [golang-design/clipboard](https://github.com/golang-design/clipboard).
|
|
78
|
+
|
|
79
|
+
When a change is detected, `IMAGE_CHANGED` or `TEXT_CHANGED` is printed to `stdout`.
|
|
80
|
+
|
|
81
|
+
This library runs compiled go-version clipboard listener using child process and listen to the `stdout`.
|
|
82
|
+
|
|
83
|
+
If it sees the keywords in child process's `stdout`, an event will be emitted.
|
|
84
|
+
|
|
85
|
+
Run `npm run demo` to see a demo for 10 sec. Once started, copy some text and screenshot and check the terminal.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Supported Platforms
|
|
89
|
+
|
|
90
|
+
Format: `process.platform/process.arch`
|
|
91
|
+
|
|
92
|
+
The process here is from nodejs.
|
|
93
|
+
|
|
94
|
+
Supported platforms can be found in `go-clipboard-monitor`.
|
|
95
|
+
|
|
96
|
+
If your nodejs gives different platform or arch, it may not work.
|
package/dist/demo.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/dist/demo.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var events = require('events');
|
|
6
|
+
var child_process = require('child_process');
|
|
7
|
+
|
|
8
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
|
+
|
|
10
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
11
|
+
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
12
|
+
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __esm = (fn, res) => function __init() {
|
|
15
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
16
|
+
};
|
|
17
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
18
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
19
|
+
};
|
|
20
|
+
var ClipboardEventListener, clipboard_default;
|
|
21
|
+
var init_clipboard = __esm({
|
|
22
|
+
"index.ts"() {
|
|
23
|
+
ClipboardEventListener = class extends events.EventEmitter {
|
|
24
|
+
constructor() {
|
|
25
|
+
super();
|
|
26
|
+
this.child = void 0;
|
|
27
|
+
}
|
|
28
|
+
startListening() {
|
|
29
|
+
var _a, _b;
|
|
30
|
+
const { platform, arch } = process;
|
|
31
|
+
const pathArr = [__dirname];
|
|
32
|
+
if (path__default["default"].basename(__dirname) === "dist") {
|
|
33
|
+
pathArr.push("..");
|
|
34
|
+
}
|
|
35
|
+
let exeFilename = `go-clipboard-${platform}-${arch}`;
|
|
36
|
+
if (platform === "win32") {
|
|
37
|
+
exeFilename += ".exe";
|
|
38
|
+
}
|
|
39
|
+
pathArr.push(...["go-clipboard", "binaries", exeFilename]);
|
|
40
|
+
const exePath = path__default["default"].join(...pathArr);
|
|
41
|
+
console.log(exePath);
|
|
42
|
+
if (!fs__default["default"].existsSync(exePath)) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`Executable (${exeFilename}) not found, your platform is ${platform} ${arch} and may not be supported.`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
this.child = child_process.execFile(exePath);
|
|
48
|
+
(_a = this.child.stdout) == null ? void 0 : _a.on("data", (data) => {
|
|
49
|
+
const dataStr = data.toString();
|
|
50
|
+
if (dataStr.trim() === "TEXT_CHANGED") {
|
|
51
|
+
this.emit("text");
|
|
52
|
+
}
|
|
53
|
+
if (dataStr.trim() === "IMAGE_CHANGED") {
|
|
54
|
+
this.emit("image");
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
(_b = this.child.stderr) == null ? void 0 : _b.on("data", (data) => {
|
|
58
|
+
this.emit("open", data.toString());
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
stopListening() {
|
|
62
|
+
var _a;
|
|
63
|
+
this.emit("close");
|
|
64
|
+
const res = (_a = this.child) == null ? void 0 : _a.kill();
|
|
65
|
+
return res;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
clipboard_default = new ClipboardEventListener();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// demo.ts
|
|
73
|
+
var require_demo = __commonJS({
|
|
74
|
+
"demo.ts"() {
|
|
75
|
+
init_clipboard();
|
|
76
|
+
clipboard_default.on("text", () => {
|
|
77
|
+
console.log("Clipboard Text Updated");
|
|
78
|
+
});
|
|
79
|
+
clipboard_default.on("image", () => {
|
|
80
|
+
console.log("Clipboard Image Updated");
|
|
81
|
+
});
|
|
82
|
+
clipboard_default.on("open", (data) => {
|
|
83
|
+
console.log(data);
|
|
84
|
+
});
|
|
85
|
+
clipboard_default.startListening();
|
|
86
|
+
setTimeout(() => {
|
|
87
|
+
clipboard_default.stopListening();
|
|
88
|
+
}, 1e4);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
var demo = require_demo();
|
|
92
|
+
|
|
93
|
+
module.exports = demo;
|
|
94
|
+
//# sourceMappingURL=demo.js.map
|
package/dist/demo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts","../demo.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAC7B,SAAgB,gBAA8D;AAH9E,IAKM,wBAkDC;AAvDP;AAAA;AAAA;AAKA,IAAM,yBAAN,cAAqC,aAAa;AAAA,MAEhD,cAAc;AACZ,cAAM;AACN,aAAK,QAAQ;AAAA,MACf;AAAA,MAEA,iBAAiB;AAZnB;AAaI,cAAM,EAAE,UAAU,KAAK,IAAI;AAC3B,cAAM,UAAU,CAAC,SAAS;AAE1B,YAAI,KAAK,SAAS,SAAS,MAAM,QAAQ;AACvC,kBAAQ,KAAK,IAAI;AAAA,QACnB;AACA,YAAI,cAAc,gBAAgB,YAAY;AAC9C,YAAI,aAAa,SAAS;AACxB,yBAAe;AAAA,QACjB;AACA,gBAAQ,KAAK,GAAG,CAAC,gBAAgB,YAAY,WAAW,CAAC;AACzD,cAAM,UAAU,KAAK,KAAK,GAAG,OAAO;AACpC,gBAAQ,IAAI,OAAO;AAEnB,YAAI,CAAC,GAAG,WAAW,OAAO,GAAG;AAC3B,gBAAM,IAAI;AAAA,YACR,eAAe,4CAA4C,YAAY;AAAA,UACzE;AAAA,QACF;AACA,aAAK,QAAQ,SAAS,OAAO;AAC7B,mBAAK,MAAM,WAAX,mBAAmB,GAAG,QAAQ,CAAC,SAAiB;AAC9C,gBAAM,UAAU,KAAK,SAAS;AAC9B,cAAI,QAAQ,KAAK,MAAM,gBAAgB;AACrC,iBAAK,KAAK,MAAM;AAAA,UAClB;AACA,cAAI,QAAQ,KAAK,MAAM,iBAAiB;AACtC,iBAAK,KAAK,OAAO;AAAA,UACnB;AAAA,QACF;AAEA,mBAAK,MAAM,WAAX,mBAAmB,GAAG,QAAQ,CAAC,SAAiB;AAC9C,eAAK,KAAK,QAAQ,KAAK,SAAS,CAAC;AAAA,QACnC;AAAA,MACF;AAAA,MAEA,gBAAgB;AAhDlB;AAiDI,aAAK,KAAK,OAAO;AACjB,cAAM,OAAM,UAAK,UAAL,mBAAY;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,IAAO,oBAAQ,IAAI,uBAAuB;AAAA;AAAA;;;ACvD1C;AAAA;AAAA;AAEA,sBAAuB,GAAG,QAAQ,MAAM;AACtC,cAAQ,IAAI,wBAAwB;AAAA,IACtC,CAAC;AAED,sBAAuB,GAAG,SAAS,MAAM;AACvC,cAAQ,IAAI,yBAAyB;AAAA,IACvC,CAAC;AAED,sBAAuB,GAAG,QAAQ,CAAC,SAAS;AAC1C,cAAQ,IAAI,IAAI;AAAA,IAClB,CAAC;AAED,sBAAuB,eAAe;AAEtC,eAAW,MAAM;AACf,wBAAuB,cAAc;AAAA,IACvC,GAAG,GAAK;AAAA;AAAA","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { EventEmitter } from 'events';\nimport { spawn, execFile, ChildProcessWithoutNullStreams, ChildProcess } from 'node:child_process';\n\nclass ClipboardEventListener extends EventEmitter {\n child: ChildProcess | undefined;\n constructor() {\n super();\n this.child = undefined;\n }\n\n startListening() {\n const { platform, arch } = process;\n const pathArr = [__dirname];\n\n if (path.basename(__dirname) === 'dist') {\n pathArr.push('..');\n }\n let exeFilename = `go-clipboard-${platform}-${arch}`;\n if (platform === 'win32') {\n exeFilename += '.exe';\n }\n pathArr.push(...['go-clipboard', 'binaries', exeFilename]);\n const exePath = path.join(...pathArr);\n console.log(exePath);\n \n if (!fs.existsSync(exePath)) {\n throw new Error(\n `Executable (${exeFilename}) not found, your platform is ${platform} ${arch} and may not be supported.`\n );\n }\n this.child = execFile(exePath);\n this.child.stdout?.on('data', (data: Buffer) => {\n const dataStr = data.toString();\n if (dataStr.trim() === 'TEXT_CHANGED') {\n this.emit('text');\n }\n if (dataStr.trim() === 'IMAGE_CHANGED') {\n this.emit('image');\n }\n });\n\n this.child.stderr?.on('data', (data: Buffer) => {\n this.emit('open', data.toString());\n });\n }\n\n stopListening() {\n this.emit('close');\n const res = this.child?.kill();\n return res;\n }\n}\n\nexport default new ClipboardEventListener();\n","import clipboardEventListener from \"./index\";\n\nclipboardEventListener.on(\"text\", () => {\n console.log(\"Clipboard Text Updated\");\n});\n\nclipboardEventListener.on(\"image\", () => {\n console.log(\"Clipboard Image Updated\");\n});\n\nclipboardEventListener.on(\"open\", (data) => {\n console.log(data);\n});\n\nclipboardEventListener.startListening();\n\nsetTimeout(() => {\n clipboardEventListener.stopListening();\n}, 10000);\n"]}
|
package/dist/demo.mjs
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
import { execFile } from 'child_process';
|
|
5
|
+
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __esm = (fn, res) => function __init() {
|
|
8
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
9
|
+
};
|
|
10
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
11
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
12
|
+
};
|
|
13
|
+
var ClipboardEventListener, clipboard_default;
|
|
14
|
+
var init_clipboard = __esm({
|
|
15
|
+
"index.ts"() {
|
|
16
|
+
ClipboardEventListener = class extends EventEmitter {
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
this.child = void 0;
|
|
20
|
+
}
|
|
21
|
+
startListening() {
|
|
22
|
+
var _a, _b;
|
|
23
|
+
const { platform, arch } = process;
|
|
24
|
+
const pathArr = [__dirname];
|
|
25
|
+
if (path.basename(__dirname) === "dist") {
|
|
26
|
+
pathArr.push("..");
|
|
27
|
+
}
|
|
28
|
+
let exeFilename = `go-clipboard-${platform}-${arch}`;
|
|
29
|
+
if (platform === "win32") {
|
|
30
|
+
exeFilename += ".exe";
|
|
31
|
+
}
|
|
32
|
+
pathArr.push(...["go-clipboard", "binaries", exeFilename]);
|
|
33
|
+
const exePath = path.join(...pathArr);
|
|
34
|
+
console.log(exePath);
|
|
35
|
+
if (!fs.existsSync(exePath)) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Executable (${exeFilename}) not found, your platform is ${platform} ${arch} and may not be supported.`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
this.child = execFile(exePath);
|
|
41
|
+
(_a = this.child.stdout) == null ? void 0 : _a.on("data", (data) => {
|
|
42
|
+
const dataStr = data.toString();
|
|
43
|
+
if (dataStr.trim() === "TEXT_CHANGED") {
|
|
44
|
+
this.emit("text");
|
|
45
|
+
}
|
|
46
|
+
if (dataStr.trim() === "IMAGE_CHANGED") {
|
|
47
|
+
this.emit("image");
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
(_b = this.child.stderr) == null ? void 0 : _b.on("data", (data) => {
|
|
51
|
+
this.emit("open", data.toString());
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
stopListening() {
|
|
55
|
+
var _a;
|
|
56
|
+
this.emit("close");
|
|
57
|
+
const res = (_a = this.child) == null ? void 0 : _a.kill();
|
|
58
|
+
return res;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
clipboard_default = new ClipboardEventListener();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// demo.ts
|
|
66
|
+
var require_demo = __commonJS({
|
|
67
|
+
"demo.ts"() {
|
|
68
|
+
init_clipboard();
|
|
69
|
+
clipboard_default.on("text", () => {
|
|
70
|
+
console.log("Clipboard Text Updated");
|
|
71
|
+
});
|
|
72
|
+
clipboard_default.on("image", () => {
|
|
73
|
+
console.log("Clipboard Image Updated");
|
|
74
|
+
});
|
|
75
|
+
clipboard_default.on("open", (data) => {
|
|
76
|
+
console.log(data);
|
|
77
|
+
});
|
|
78
|
+
clipboard_default.startListening();
|
|
79
|
+
setTimeout(() => {
|
|
80
|
+
clipboard_default.stopListening();
|
|
81
|
+
}, 1e4);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
var demo = require_demo();
|
|
85
|
+
|
|
86
|
+
export { demo as default };
|
|
87
|
+
//# sourceMappingURL=demo.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts","../demo.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAC7B,SAAgB,gBAA8D;AAH9E,IAKM,wBAkDC;AAvDP;AAAA;AAAA;AAKA,IAAM,yBAAN,cAAqC,aAAa;AAAA,MAEhD,cAAc;AACZ,cAAM;AACN,aAAK,QAAQ;AAAA,MACf;AAAA,MAEA,iBAAiB;AAZnB;AAaI,cAAM,EAAE,UAAU,KAAK,IAAI;AAC3B,cAAM,UAAU,CAAC,SAAS;AAE1B,YAAI,KAAK,SAAS,SAAS,MAAM,QAAQ;AACvC,kBAAQ,KAAK,IAAI;AAAA,QACnB;AACA,YAAI,cAAc,gBAAgB,YAAY;AAC9C,YAAI,aAAa,SAAS;AACxB,yBAAe;AAAA,QACjB;AACA,gBAAQ,KAAK,GAAG,CAAC,gBAAgB,YAAY,WAAW,CAAC;AACzD,cAAM,UAAU,KAAK,KAAK,GAAG,OAAO;AACpC,gBAAQ,IAAI,OAAO;AAEnB,YAAI,CAAC,GAAG,WAAW,OAAO,GAAG;AAC3B,gBAAM,IAAI;AAAA,YACR,eAAe,4CAA4C,YAAY;AAAA,UACzE;AAAA,QACF;AACA,aAAK,QAAQ,SAAS,OAAO;AAC7B,mBAAK,MAAM,WAAX,mBAAmB,GAAG,QAAQ,CAAC,SAAiB;AAC9C,gBAAM,UAAU,KAAK,SAAS;AAC9B,cAAI,QAAQ,KAAK,MAAM,gBAAgB;AACrC,iBAAK,KAAK,MAAM;AAAA,UAClB;AACA,cAAI,QAAQ,KAAK,MAAM,iBAAiB;AACtC,iBAAK,KAAK,OAAO;AAAA,UACnB;AAAA,QACF;AAEA,mBAAK,MAAM,WAAX,mBAAmB,GAAG,QAAQ,CAAC,SAAiB;AAC9C,eAAK,KAAK,QAAQ,KAAK,SAAS,CAAC;AAAA,QACnC;AAAA,MACF;AAAA,MAEA,gBAAgB;AAhDlB;AAiDI,aAAK,KAAK,OAAO;AACjB,cAAM,OAAM,UAAK,UAAL,mBAAY;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,IAAO,oBAAQ,IAAI,uBAAuB;AAAA;AAAA;;;ACvD1C;AAAA;AAAA;AAEA,sBAAuB,GAAG,QAAQ,MAAM;AACtC,cAAQ,IAAI,wBAAwB;AAAA,IACtC,CAAC;AAED,sBAAuB,GAAG,SAAS,MAAM;AACvC,cAAQ,IAAI,yBAAyB;AAAA,IACvC,CAAC;AAED,sBAAuB,GAAG,QAAQ,CAAC,SAAS;AAC1C,cAAQ,IAAI,IAAI;AAAA,IAClB,CAAC;AAED,sBAAuB,eAAe;AAEtC,eAAW,MAAM;AACf,wBAAuB,cAAc;AAAA,IACvC,GAAG,GAAK;AAAA;AAAA","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { EventEmitter } from 'events';\nimport { spawn, execFile, ChildProcessWithoutNullStreams, ChildProcess } from 'node:child_process';\n\nclass ClipboardEventListener extends EventEmitter {\n child: ChildProcess | undefined;\n constructor() {\n super();\n this.child = undefined;\n }\n\n startListening() {\n const { platform, arch } = process;\n const pathArr = [__dirname];\n\n if (path.basename(__dirname) === 'dist') {\n pathArr.push('..');\n }\n let exeFilename = `go-clipboard-${platform}-${arch}`;\n if (platform === 'win32') {\n exeFilename += '.exe';\n }\n pathArr.push(...['go-clipboard', 'binaries', exeFilename]);\n const exePath = path.join(...pathArr);\n console.log(exePath);\n \n if (!fs.existsSync(exePath)) {\n throw new Error(\n `Executable (${exeFilename}) not found, your platform is ${platform} ${arch} and may not be supported.`\n );\n }\n this.child = execFile(exePath);\n this.child.stdout?.on('data', (data: Buffer) => {\n const dataStr = data.toString();\n if (dataStr.trim() === 'TEXT_CHANGED') {\n this.emit('text');\n }\n if (dataStr.trim() === 'IMAGE_CHANGED') {\n this.emit('image');\n }\n });\n\n this.child.stderr?.on('data', (data: Buffer) => {\n this.emit('open', data.toString());\n });\n }\n\n stopListening() {\n this.emit('close');\n const res = this.child?.kill();\n return res;\n }\n}\n\nexport default new ClipboardEventListener();\n","import clipboardEventListener from \"./index\";\n\nclipboardEventListener.on(\"text\", () => {\n console.log(\"Clipboard Text Updated\");\n});\n\nclipboardEventListener.on(\"image\", () => {\n console.log(\"Clipboard Image Updated\");\n});\n\nclipboardEventListener.on(\"open\", (data) => {\n console.log(data);\n});\n\nclipboardEventListener.startListening();\n\nsetTimeout(() => {\n clipboardEventListener.stopListening();\n}, 10000);\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { ChildProcess } from 'node:child_process';
|
|
3
|
+
|
|
4
|
+
declare class ClipboardEventListener extends EventEmitter {
|
|
5
|
+
child: ChildProcess | undefined;
|
|
6
|
+
constructor();
|
|
7
|
+
startListening(): void;
|
|
8
|
+
stopListening(): boolean | undefined;
|
|
9
|
+
}
|
|
10
|
+
declare const _default: ClipboardEventListener;
|
|
11
|
+
|
|
12
|
+
export { _default as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var events = require('events');
|
|
6
|
+
var child_process = require('child_process');
|
|
7
|
+
|
|
8
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
9
|
+
|
|
10
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
11
|
+
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
12
|
+
|
|
13
|
+
// index.ts
|
|
14
|
+
var ClipboardEventListener = class extends events.EventEmitter {
|
|
15
|
+
constructor() {
|
|
16
|
+
super();
|
|
17
|
+
this.child = void 0;
|
|
18
|
+
}
|
|
19
|
+
startListening() {
|
|
20
|
+
var _a, _b;
|
|
21
|
+
const { platform, arch } = process;
|
|
22
|
+
const pathArr = [__dirname];
|
|
23
|
+
if (path__default["default"].basename(__dirname) === "dist") {
|
|
24
|
+
pathArr.push("..");
|
|
25
|
+
}
|
|
26
|
+
let exeFilename = `go-clipboard-${platform}-${arch}`;
|
|
27
|
+
if (platform === "win32") {
|
|
28
|
+
exeFilename += ".exe";
|
|
29
|
+
}
|
|
30
|
+
pathArr.push(...["go-clipboard", "binaries", exeFilename]);
|
|
31
|
+
const exePath = path__default["default"].join(...pathArr);
|
|
32
|
+
console.log(exePath);
|
|
33
|
+
if (!fs__default["default"].existsSync(exePath)) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Executable (${exeFilename}) not found, your platform is ${platform} ${arch} and may not be supported.`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
this.child = child_process.execFile(exePath);
|
|
39
|
+
(_a = this.child.stdout) == null ? void 0 : _a.on("data", (data) => {
|
|
40
|
+
const dataStr = data.toString();
|
|
41
|
+
if (dataStr.trim() === "TEXT_CHANGED") {
|
|
42
|
+
this.emit("text");
|
|
43
|
+
}
|
|
44
|
+
if (dataStr.trim() === "IMAGE_CHANGED") {
|
|
45
|
+
this.emit("image");
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
(_b = this.child.stderr) == null ? void 0 : _b.on("data", (data) => {
|
|
49
|
+
this.emit("open", data.toString());
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
stopListening() {
|
|
53
|
+
var _a;
|
|
54
|
+
this.emit("close");
|
|
55
|
+
const res = (_a = this.child) == null ? void 0 : _a.kill();
|
|
56
|
+
return res;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
var clipboard_default = new ClipboardEventListener();
|
|
60
|
+
|
|
61
|
+
module.exports = clipboard_default;
|
|
62
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"names":[],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAC7B,SAAgB,gBAA8D;AAE9E,IAAM,yBAAN,cAAqC,aAAa;AAAA,EAEhD,cAAc;AACZ,UAAM;AACN,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,iBAAiB;AAZnB;AAaI,UAAM,EAAE,UAAU,KAAK,IAAI;AAC3B,UAAM,UAAU,CAAC,SAAS;AAE1B,QAAI,KAAK,SAAS,SAAS,MAAM,QAAQ;AACvC,cAAQ,KAAK,IAAI;AAAA,IACnB;AACA,QAAI,cAAc,gBAAgB,YAAY;AAC9C,QAAI,aAAa,SAAS;AACxB,qBAAe;AAAA,IACjB;AACA,YAAQ,KAAK,GAAG,CAAC,gBAAgB,YAAY,WAAW,CAAC;AACzD,UAAM,UAAU,KAAK,KAAK,GAAG,OAAO;AACpC,YAAQ,IAAI,OAAO;AAEnB,QAAI,CAAC,GAAG,WAAW,OAAO,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,eAAe,4CAA4C,YAAY;AAAA,MACzE;AAAA,IACF;AACA,SAAK,QAAQ,SAAS,OAAO;AAC7B,eAAK,MAAM,WAAX,mBAAmB,GAAG,QAAQ,CAAC,SAAiB;AAC9C,YAAM,UAAU,KAAK,SAAS;AAC9B,UAAI,QAAQ,KAAK,MAAM,gBAAgB;AACrC,aAAK,KAAK,MAAM;AAAA,MAClB;AACA,UAAI,QAAQ,KAAK,MAAM,iBAAiB;AACtC,aAAK,KAAK,OAAO;AAAA,MACnB;AAAA,IACF;AAEA,eAAK,MAAM,WAAX,mBAAmB,GAAG,QAAQ,CAAC,SAAiB;AAC9C,WAAK,KAAK,QAAQ,KAAK,SAAS,CAAC;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,gBAAgB;AAhDlB;AAiDI,SAAK,KAAK,OAAO;AACjB,UAAM,OAAM,UAAK,UAAL,mBAAY;AACxB,WAAO;AAAA,EACT;AACF;AAEA,IAAO,oBAAQ,IAAI,uBAAuB","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { EventEmitter } from 'events';\nimport { spawn, execFile, ChildProcessWithoutNullStreams, ChildProcess } from 'node:child_process';\n\nclass ClipboardEventListener extends EventEmitter {\n child: ChildProcess | undefined;\n constructor() {\n super();\n this.child = undefined;\n }\n\n startListening() {\n const { platform, arch } = process;\n const pathArr = [__dirname];\n\n if (path.basename(__dirname) === 'dist') {\n pathArr.push('..');\n }\n let exeFilename = `go-clipboard-${platform}-${arch}`;\n if (platform === 'win32') {\n exeFilename += '.exe';\n }\n pathArr.push(...['go-clipboard', 'binaries', exeFilename]);\n const exePath = path.join(...pathArr);\n console.log(exePath);\n \n if (!fs.existsSync(exePath)) {\n throw new Error(\n `Executable (${exeFilename}) not found, your platform is ${platform} ${arch} and may not be supported.`\n );\n }\n this.child = execFile(exePath);\n this.child.stdout?.on('data', (data: Buffer) => {\n const dataStr = data.toString();\n if (dataStr.trim() === 'TEXT_CHANGED') {\n this.emit('text');\n }\n if (dataStr.trim() === 'IMAGE_CHANGED') {\n this.emit('image');\n }\n });\n\n this.child.stderr?.on('data', (data: Buffer) => {\n this.emit('open', data.toString());\n });\n }\n\n stopListening() {\n this.emit('close');\n const res = this.child?.kill();\n return res;\n }\n}\n\nexport default new ClipboardEventListener();\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { EventEmitter } from 'events';
|
|
4
|
+
import { execFile } from 'child_process';
|
|
5
|
+
|
|
6
|
+
// index.ts
|
|
7
|
+
var ClipboardEventListener = class extends EventEmitter {
|
|
8
|
+
constructor() {
|
|
9
|
+
super();
|
|
10
|
+
this.child = void 0;
|
|
11
|
+
}
|
|
12
|
+
startListening() {
|
|
13
|
+
var _a, _b;
|
|
14
|
+
const { platform, arch } = process;
|
|
15
|
+
const pathArr = [__dirname];
|
|
16
|
+
if (path.basename(__dirname) === "dist") {
|
|
17
|
+
pathArr.push("..");
|
|
18
|
+
}
|
|
19
|
+
let exeFilename = `go-clipboard-${platform}-${arch}`;
|
|
20
|
+
if (platform === "win32") {
|
|
21
|
+
exeFilename += ".exe";
|
|
22
|
+
}
|
|
23
|
+
pathArr.push(...["go-clipboard", "binaries", exeFilename]);
|
|
24
|
+
const exePath = path.join(...pathArr);
|
|
25
|
+
console.log(exePath);
|
|
26
|
+
if (!fs.existsSync(exePath)) {
|
|
27
|
+
throw new Error(
|
|
28
|
+
`Executable (${exeFilename}) not found, your platform is ${platform} ${arch} and may not be supported.`
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
this.child = execFile(exePath);
|
|
32
|
+
(_a = this.child.stdout) == null ? void 0 : _a.on("data", (data) => {
|
|
33
|
+
const dataStr = data.toString();
|
|
34
|
+
if (dataStr.trim() === "TEXT_CHANGED") {
|
|
35
|
+
this.emit("text");
|
|
36
|
+
}
|
|
37
|
+
if (dataStr.trim() === "IMAGE_CHANGED") {
|
|
38
|
+
this.emit("image");
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
(_b = this.child.stderr) == null ? void 0 : _b.on("data", (data) => {
|
|
42
|
+
this.emit("open", data.toString());
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
stopListening() {
|
|
46
|
+
var _a;
|
|
47
|
+
this.emit("close");
|
|
48
|
+
const res = (_a = this.child) == null ? void 0 : _a.kill();
|
|
49
|
+
return res;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
var clipboard_default = new ClipboardEventListener();
|
|
53
|
+
|
|
54
|
+
export { clipboard_default as default };
|
|
55
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../index.ts"],"names":[],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,oBAAoB;AAC7B,SAAgB,gBAA8D;AAE9E,IAAM,yBAAN,cAAqC,aAAa;AAAA,EAEhD,cAAc;AACZ,UAAM;AACN,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,iBAAiB;AAZnB;AAaI,UAAM,EAAE,UAAU,KAAK,IAAI;AAC3B,UAAM,UAAU,CAAC,SAAS;AAE1B,QAAI,KAAK,SAAS,SAAS,MAAM,QAAQ;AACvC,cAAQ,KAAK,IAAI;AAAA,IACnB;AACA,QAAI,cAAc,gBAAgB,YAAY;AAC9C,QAAI,aAAa,SAAS;AACxB,qBAAe;AAAA,IACjB;AACA,YAAQ,KAAK,GAAG,CAAC,gBAAgB,YAAY,WAAW,CAAC;AACzD,UAAM,UAAU,KAAK,KAAK,GAAG,OAAO;AACpC,YAAQ,IAAI,OAAO;AAEnB,QAAI,CAAC,GAAG,WAAW,OAAO,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,eAAe,4CAA4C,YAAY;AAAA,MACzE;AAAA,IACF;AACA,SAAK,QAAQ,SAAS,OAAO;AAC7B,eAAK,MAAM,WAAX,mBAAmB,GAAG,QAAQ,CAAC,SAAiB;AAC9C,YAAM,UAAU,KAAK,SAAS;AAC9B,UAAI,QAAQ,KAAK,MAAM,gBAAgB;AACrC,aAAK,KAAK,MAAM;AAAA,MAClB;AACA,UAAI,QAAQ,KAAK,MAAM,iBAAiB;AACtC,aAAK,KAAK,OAAO;AAAA,MACnB;AAAA,IACF;AAEA,eAAK,MAAM,WAAX,mBAAmB,GAAG,QAAQ,CAAC,SAAiB;AAC9C,WAAK,KAAK,QAAQ,KAAK,SAAS,CAAC;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,gBAAgB;AAhDlB;AAiDI,SAAK,KAAK,OAAO;AACjB,UAAM,OAAM,UAAK,UAAL,mBAAY;AACxB,WAAO;AAAA,EACT;AACF;AAEA,IAAO,oBAAQ,IAAI,uBAAuB","sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { EventEmitter } from 'events';\nimport { spawn, execFile, ChildProcessWithoutNullStreams, ChildProcess } from 'node:child_process';\n\nclass ClipboardEventListener extends EventEmitter {\n child: ChildProcess | undefined;\n constructor() {\n super();\n this.child = undefined;\n }\n\n startListening() {\n const { platform, arch } = process;\n const pathArr = [__dirname];\n\n if (path.basename(__dirname) === 'dist') {\n pathArr.push('..');\n }\n let exeFilename = `go-clipboard-${platform}-${arch}`;\n if (platform === 'win32') {\n exeFilename += '.exe';\n }\n pathArr.push(...['go-clipboard', 'binaries', exeFilename]);\n const exePath = path.join(...pathArr);\n console.log(exePath);\n \n if (!fs.existsSync(exePath)) {\n throw new Error(\n `Executable (${exeFilename}) not found, your platform is ${platform} ${arch} and may not be supported.`\n );\n }\n this.child = execFile(exePath);\n this.child.stdout?.on('data', (data: Buffer) => {\n const dataStr = data.toString();\n if (dataStr.trim() === 'TEXT_CHANGED') {\n this.emit('text');\n }\n if (dataStr.trim() === 'IMAGE_CHANGED') {\n this.emit('image');\n }\n });\n\n this.child.stderr?.on('data', (data: Buffer) => {\n this.emit('open', data.toString());\n });\n }\n\n stopListening() {\n this.emit('close');\n const res = this.child?.kill();\n return res;\n }\n}\n\nexport default new ClipboardEventListener();\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
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>
|
|
@@ -0,0 +1,8 @@
|
|
|
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>
|
|
@@ -0,0 +1,8 @@
|
|
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
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.
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
"iVBORw0KGgoAAAANSUhEUgAAABIAAAAPCAYAAADphp8SAAABdWlDQ1BrQ0dDb2xvclNwYWNlRGlzcGxheVAzAAAokXWQvUvDUBTFT6tS0DqIDh0cMolD1NIKdnFoKxRFMFQFq1OafgltfCQpUnETVyn4H1jBWXCwiFRwcXAQRAcR3Zw6KbhoeN6XVNoi3sfl/Ticc7lcwBtQGSv2AijplpFMxKS11Lrke4OHnlOqZrKooiwK/v276/PR9d5PiFlNu3YQ2U9cl84ul3aeAlN//V3Vn8maGv3f1EGNGRbgkYmVbYsJ3iUeMWgp4qrgvMvHgtMunzuelWSc+JZY0gpqhrhJLKc79HwHl4plrbWD2N6f1VeXxRzqUcxhEyYYilBRgQQF4X/8044/ji1yV2BQLo8CLMpESRETssTz0KFhEjJxCEHqkLhz634PrfvJbW3vFZhtcM4v2tpCAzidoZPV29p4BBgaAG7qTDVUR+qh9uZywPsJMJgChu8os2HmwiF3e38M6Hvh/GMM8B0CdpXzryPO7RqFn4Er/QcXKWq8UwZBywAAAFZlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA5KGAAcAAAASAAAARKACAAQAAAABAAAAEqADAAQAAAABAAAADwAAAABBU0NJSQAAAFNjcmVlbnNob3QENiT0AAAB1GlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4xNTwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4xODwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgICAgICAgIDxleGlmOlVzZXJDb21tZW50PlNjcmVlbnNob3Q8L2V4aWY6VXNlckNvbW1lbnQ+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgoEMkcrAAACGUlEQVQ4Ed1T0UtTYRT/7W53qeBG2900b28hpK5J7cHtIYiCohzSQ03EMX0IlJBoeau1ct0ICnqJ6D3IZf0BxSiFHBFo2SrGnD2k2YPbozO3bm65274T96L0Vm99D+ec3++c7wfnO98xcKZ6dU9rK/z+Huxzu9HucmFz8ycOervAzmzqA97NvcXI8BASk1PENVos+La2hu5jRwkzwzHj9fnQFwzCVRPiOA53bt9iNNo7OsgX19dxduQcbHYBUvg8KpUK6hsaKKcZEpoYH4fXsx8RaRT5XA5XYzIOHT6CQqFAdU5nE4IDA5h88RzZ+XkYjSZUymVNgzwJaUxy+iUuSxcIngoEkFtZoZi1qyjfEYteIczzPIrFknaN/DYhxjQ1N1PC0mghXyoVyctj18h3eX3U/qeFLGHNGBNT07JdEGC1WnE60IszQ8PgeTPGohHk83mI4m7sbWuDUKtRFAUx+QZ21NUhGrmIwurv1pmY4fVcWjWbzZowVFVF4tlT3JSv69yDh3GaJiNY/v69u3gcj+t5FhjY+Fk7oijix8YGspnMtoKt4IDHg/ep1FZKj0lIR/8Q/PHYf6v1HwuZQoOD8PechMPpQLVaxZelJRr91+Vl/bn6QyEcP9GNXS0tyKTTeDLxCLMzM3qeBYY3HxdUtoTsos22E3bBUVvKsr79YUlCb19/7fOtYnHxM9ydnfRhL42G8SqZ1MV+AU3Pq2QW6moOAAAAAElFTkSuQmCC";
|
|
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);
|
|
@@ -0,0 +1,131 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
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
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crosscopy/clipboard",
|
|
3
|
+
"version": "0.1.0-beta",
|
|
4
|
+
"description": "Cross Platform Clipboard listener that detects both text and image update in clipboard",
|
|
5
|
+
"source": "index.ts",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.mjs",
|
|
9
|
+
"type": "commonjs",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"demo": "ts-node demo.ts",
|
|
13
|
+
"test": "jest ./__tests__"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/HuakunShen/general-clipboard-listener.git"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"clipboard"
|
|
21
|
+
],
|
|
22
|
+
"author": "Huakun Shen",
|
|
23
|
+
"license": "ISC",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/HuakunShen/general-clipboard-listener/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/HuakunShen/general-clipboard-listener#readme",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"events": "^3.3.0",
|
|
30
|
+
"execa": "^6.1.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@jest/globals": "^29.3.1",
|
|
34
|
+
"@types/jest": "^29.2.4",
|
|
35
|
+
"@types/node": "^18.11.7",
|
|
36
|
+
"jest": "^29.3.1",
|
|
37
|
+
"ts-jest": "^29.0.3",
|
|
38
|
+
"ts-node": "^10.9.1",
|
|
39
|
+
"tsup": "^6.3.0",
|
|
40
|
+
"typescript": "^4.8.4"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"go-clipboard",
|
|
45
|
+
"README.md"
|
|
46
|
+
]
|
|
47
|
+
}
|