mirror of
https://github.com/ZiuChen/ClipboardManager.git
synced 2025-06-06 21:34:08 +08:00
refactor: 改善剪贴板监听性能 修复大图卡顿与CPU高占用的问题
This commit is contained in:
parent
ba841b67a8
commit
f78b87783b
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
/node_modules
|
||||||
/dist
|
/dist
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"build": "vue-cli-service build"
|
"build": "vue-cli-service build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"clipboard-event": "^1.6.0",
|
||||||
"core-js": "^3.6.4",
|
"core-js": "^3.6.4",
|
||||||
"crypto": "^1.0.1",
|
"crypto": "^1.0.1",
|
||||||
"less": "^4.1.3",
|
"less": "^4.1.3",
|
||||||
|
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
@ -2,10 +2,10 @@ lockfileVersion: 5.4
|
|||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
'@vue/cli-service': ^5.0.8
|
'@vue/cli-service': ^5.0.8
|
||||||
|
clipboard-event: ^1.6.0
|
||||||
copy-webpack-plugin: ^6.0.2
|
copy-webpack-plugin: ^6.0.2
|
||||||
core-js: ^3.6.4
|
core-js: ^3.6.4
|
||||||
crypto: ^1.0.1
|
crypto: ^1.0.1
|
||||||
deepmerge: ^4.2.2
|
|
||||||
less: ^4.1.3
|
less: ^4.1.3
|
||||||
less-loader: ^11.0.0
|
less-loader: ^11.0.0
|
||||||
licia: ^1.23.0
|
licia: ^1.23.0
|
||||||
@ -15,6 +15,7 @@ specifiers:
|
|||||||
webpack: 4.37.0
|
webpack: 4.37.0
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
clipboard-event: registry.npmmirror.com/clipboard-event/1.6.0
|
||||||
core-js: registry.npmmirror.com/core-js/3.24.1
|
core-js: registry.npmmirror.com/core-js/3.24.1
|
||||||
crypto: registry.npmmirror.com/crypto/1.0.1
|
crypto: registry.npmmirror.com/crypto/1.0.1
|
||||||
less: registry.npmmirror.com/less/4.1.3
|
less: registry.npmmirror.com/less/4.1.3
|
||||||
@ -25,7 +26,6 @@ dependencies:
|
|||||||
devDependencies:
|
devDependencies:
|
||||||
'@vue/cli-service': registry.npmmirror.com/@vue/cli-service/5.0.8_rd7zcyopzq3edztmqqbboasfsu
|
'@vue/cli-service': registry.npmmirror.com/@vue/cli-service/5.0.8_rd7zcyopzq3edztmqqbboasfsu
|
||||||
copy-webpack-plugin: registry.npmmirror.com/copy-webpack-plugin/6.4.1_webpack@4.37.0
|
copy-webpack-plugin: registry.npmmirror.com/copy-webpack-plugin/6.4.1_webpack@4.37.0
|
||||||
deepmerge: registry.npmmirror.com/deepmerge/4.2.2
|
|
||||||
less-loader: registry.npmmirror.com/less-loader/11.0.0_less@4.1.3+webpack@4.37.0
|
less-loader: registry.npmmirror.com/less-loader/11.0.0_less@4.1.3+webpack@4.37.0
|
||||||
uglifyjs-webpack-plugin: registry.npmmirror.com/uglifyjs-webpack-plugin/2.2.0_webpack@4.37.0
|
uglifyjs-webpack-plugin: registry.npmmirror.com/uglifyjs-webpack-plugin/2.2.0_webpack@4.37.0
|
||||||
vue-template-compiler: registry.npmmirror.com/vue-template-compiler/2.7.8
|
vue-template-compiler: registry.npmmirror.com/vue-template-compiler/2.7.8
|
||||||
@ -2056,6 +2056,12 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
registry.npmmirror.com/clipboard-event/1.6.0:
|
||||||
|
resolution: {integrity: sha512-a69QYimd43xM+5hcHkucs0V/QoiZz1fqEFRTnewOITVQOtypRLbCx76Q91Djn6h7O24817dQw44sFUxRYWIuYA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/clipboard-event/-/clipboard-event-1.6.0.tgz}
|
||||||
|
name: clipboard-event
|
||||||
|
version: 1.6.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.npmmirror.com/clipboardy/2.3.0:
|
registry.npmmirror.com/clipboardy/2.3.0:
|
||||||
resolution: {integrity: sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/clipboardy/-/clipboardy-2.3.0.tgz}
|
resolution: {integrity: sha512-mKhiIL2DrQIsuXMgBgnfEHOZOryC7kY7YO//TN6c63wlEm3NG5tz+YgY5rVi29KCmq/QQjKYvM7a19+MDOTHOQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/clipboardy/-/clipboardy-2.3.0.tgz}
|
||||||
name: clipboardy
|
name: clipboardy
|
||||||
@ -2849,13 +2855,6 @@ packages:
|
|||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
registry.npmmirror.com/deepmerge/4.2.2:
|
|
||||||
resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/deepmerge/-/deepmerge-4.2.2.tgz}
|
|
||||||
name: deepmerge
|
|
||||||
version: 4.2.2
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
registry.npmmirror.com/default-gateway/6.0.3:
|
registry.npmmirror.com/default-gateway/6.0.3:
|
||||||
resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/default-gateway/-/default-gateway-6.0.3.tgz}
|
resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/default-gateway/-/default-gateway-6.0.3.tgz}
|
||||||
name: default-gateway
|
name: default-gateway
|
||||||
|
21
public/node_modules/clipboard-event/LICENSE
generated
vendored
Normal file
21
public/node_modules/clipboard-event/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Sudhakar R
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
29
public/node_modules/clipboard-event/index.js
generated
vendored
Normal file
29
public/node_modules/clipboard-event/index.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
const { EventEmitter } = require('events');
|
||||||
|
const path = require('path');
|
||||||
|
const { execFile } = require('child_process');
|
||||||
|
|
||||||
|
class ClipboardEventListener extends EventEmitter {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.child = null;
|
||||||
|
}
|
||||||
|
startListening() {
|
||||||
|
const { platform } = process;
|
||||||
|
const file = `platform/clipboard-event-handler-${platform}${platform === 'win32' ? '.exe' : ''}`
|
||||||
|
if(platform !== 'win32' && platform !== 'darwin' && platform !== 'linux') {
|
||||||
|
throw new Error(`ClipboardEventListener is not supported on ${platform}`);
|
||||||
|
}
|
||||||
|
this.child = execFile(path.join(__dirname, file));
|
||||||
|
this.child.stdout.on('data', (data) => {
|
||||||
|
if (data.trim() === 'CLIPBOARD_CHANGE') {
|
||||||
|
this.emit('change');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
stopListening() {
|
||||||
|
const res = this.child.kill();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new ClipboardEventListener();
|
BIN
public/node_modules/clipboard-event/platform/clipboard-event-handler-darwin
generated
vendored
Normal file
BIN
public/node_modules/clipboard-event/platform/clipboard-event-handler-darwin
generated
vendored
Normal file
Binary file not shown.
BIN
public/node_modules/clipboard-event/platform/clipboard-event-handler-linux
generated
vendored
Normal file
BIN
public/node_modules/clipboard-event/platform/clipboard-event-handler-linux
generated
vendored
Normal file
Binary file not shown.
BIN
public/node_modules/clipboard-event/platform/clipboard-event-handler-win32.exe
generated
vendored
Normal file
BIN
public/node_modules/clipboard-event/platform/clipboard-event-handler-win32.exe
generated
vendored
Normal file
Binary file not shown.
@ -6,19 +6,13 @@
|
|||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
|
const listener = require('clipboard-event')
|
||||||
const { clipboard } = require('electron')
|
const { clipboard } = require('electron')
|
||||||
const time = require('./time')
|
|
||||||
|
|
||||||
const homePath = utools.getPath('home')
|
const sep = utools.isWindows() ? '\\' : '/'
|
||||||
const userDataPath = utools.getPath('userData')
|
const DBPath = `${
|
||||||
const dbName = '_utools_clipboard_manager_storage'
|
utools.isMacOs() ? utools.getPath('userData') : utools.getPath('home')
|
||||||
|
}${sep}_utools_clipboard_manager_storage`
|
||||||
const isMacOs = utools.isMacOs()
|
|
||||||
const isWindows = utools.isWindows()
|
|
||||||
const sep = isWindows ? '\\' : '/'
|
|
||||||
const DBPath = `${isMacOs ? userDataPath : homePath}${sep}${dbName}`
|
|
||||||
|
|
||||||
let globalImageOversize = false
|
|
||||||
|
|
||||||
class DB {
|
class DB {
|
||||||
constructor(path) {
|
constructor(path) {
|
||||||
@ -133,7 +127,6 @@ const pbpaste = () => {
|
|||||||
// image
|
// image
|
||||||
const image = clipboard.readImage() // 大图卡顿来源
|
const image = clipboard.readImage() // 大图卡顿来源
|
||||||
const data = image.toDataURL()
|
const data = image.toDataURL()
|
||||||
globalImageOversize = data.length > 3e5
|
|
||||||
if (!image.isEmpty()) {
|
if (!image.isEmpty()) {
|
||||||
return {
|
return {
|
||||||
type: 'image',
|
type: 'image',
|
||||||
@ -142,24 +135,6 @@ const pbpaste = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const watchClipboard = async (db, fn) => {
|
|
||||||
let prev = db.dataBase.data[0] || {}
|
|
||||||
function loop() {
|
|
||||||
time.sleep(250).then(loop)
|
|
||||||
const item = pbpaste()
|
|
||||||
if (!item) return
|
|
||||||
item.id = crypto.createHash('md5').update(item.data).digest('hex')
|
|
||||||
if (item && prev.id != item.id) {
|
|
||||||
// 剪切板元素 与最近一次复制内容不同
|
|
||||||
prev = item
|
|
||||||
fn(item)
|
|
||||||
} else {
|
|
||||||
// 剪切板元素 与上次复制内容相同
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loop()
|
|
||||||
}
|
|
||||||
|
|
||||||
const copy = (item, isHideMainWindow = true) => {
|
const copy = (item, isHideMainWindow = true) => {
|
||||||
switch (item.type) {
|
switch (item.type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
@ -221,9 +196,12 @@ const focus = (isBlur = false) => {
|
|||||||
const toTop = () => (document.scrollingElement.scrollTop = 0)
|
const toTop = () => (document.scrollingElement.scrollTop = 0)
|
||||||
const resetNav = () => document.querySelectorAll('.clip-switch-item')[0]?.click()
|
const resetNav = () => document.querySelectorAll('.clip-switch-item')[0]?.click()
|
||||||
|
|
||||||
watchClipboard(db, (item) => {
|
listener.startListening()
|
||||||
// 此函数不断执行
|
|
||||||
|
listener.on('change', () => {
|
||||||
|
const item = pbpaste()
|
||||||
if (!item) return
|
if (!item) return
|
||||||
|
item.id = crypto.createHash('md5').update(item.data).digest('hex')
|
||||||
if (db.updateItemViaId(item.id)) {
|
if (db.updateItemViaId(item.id)) {
|
||||||
// 在库中 由 updateItemViaId 更新 updateTime
|
// 在库中 由 updateItemViaId 更新 updateTime
|
||||||
return
|
return
|
||||||
@ -235,10 +213,6 @@ watchClipboard(db, (item) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
utools.onPluginEnter(() => {
|
utools.onPluginEnter(() => {
|
||||||
if (globalImageOversize) {
|
|
||||||
utools.copyText('ImageOverSized')
|
|
||||||
globalImageOversize = false
|
|
||||||
}
|
|
||||||
toTop()
|
toTop()
|
||||||
resetNav()
|
resetNav()
|
||||||
})
|
})
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
// time.js author: inu1255
|
|
||||||
const path=require("path");function newPromise(fn){let a,b;var tmp={resolve(x){if(this.pending){a(x);this.resolved=true;this.pending=false}},reject(e){if(this.pending){b(e);this.rejectd=true;this.pending=false}},pending:true,resolved:false,rejected:false};var pms=new Promise(function(resolve,reject){a=resolve;b=reject;if(fn)fn(tmp.resolve,tmp.reject)});return Object.assign(pms,tmp)}let cbIdx=1;const cbMap=new Map;function getWorker(){if(getWorker.worker)return getWorker.worker;const worker=new Worker(path.join(__dirname,"time.worker.js"));getWorker.worker=worker;worker.onmessage=e=>{if(e.data&&cbMap.has(e.data.cb)){cbMap.get(e.data.cb).apply(null,e.data.args)}};return worker}function call(method,args){const cb=cbIdx++;let pms=newPromise();cbMap.set(cb,function(err,data){if(err)pms.reject(err);else pms.resolve(data)});getWorker().postMessage({method:method,args:args,cb:cb});return pms}function sleep(ms){return call("sleep",[ms])}exports.sleep=sleep;
|
|
@ -1,2 +0,0 @@
|
|||||||
// time.worker.js author: inu1255
|
|
||||||
const apis={sleep(ms){return new Promise(resolve=>setTimeout(resolve,ms))}};onmessage=event=>{const data=event.data;if(!data)return;const{cb,method,args}=data;if(!apis[method]){postMessage({cb:cb,err:"no such method"});return}apis[method].apply(null,args).then(res=>postMessage({cb:cb,data:res}),err=>postMessage({cb:cb,err:err}))};
|
|
Loading…
x
Reference in New Issue
Block a user