diff --git a/public/listener.js b/public/listener.js new file mode 100644 index 0000000..36c51bb --- /dev/null +++ b/public/listener.js @@ -0,0 +1,56 @@ +const { chmodSync, existsSync } = require('fs') +const { EventEmitter } = require('events') +const path = require('path') +const { execFile } = require('child_process') + +class ClipboardEventListener extends EventEmitter { + constructor() { + super() + this.child = null + this.listening = false + } + startListening(dbPath) { + const targetMap = { + win32: 'clipboard-event-handler-win32.exe', + linux: 'clipboard-event-handler-linux' + } + const { platform } = process + const target = path.resolve( + dbPath.split('_utools_clipboard_manager_storage')[0], + targetMap[platform] + ) + if (!existsSync(target)) { + this.emit('error', '剪贴板监听程序不存在') + return + } + if (platform === 'win32') { + this.child = execFile(target) + } else if (platform === 'linux') { + chmodSync(target, 0o755) + this.child = execFile(target) + } else { + throw 'Not yet supported' + } + this.child.stdout.on('data', (data) => { + if (data.trim() === 'CLIPBOARD_CHANGE') { + this.emit('change') + } + }) + this.child.stdout.on('close', () => { + this.emit('close') + this.listening = false + }) + this.child.stdout.on('exit', () => { + this.emit('exit') + this.listening = false + }) + this.listening = true + } + stopListening() { + const res = this.child.kill() + this.listening = false + return res + } +} + +module.exports = new ClipboardEventListener() diff --git a/public/plugin.json b/public/plugin.json index 510ac34..2bb953f 100644 --- a/public/plugin.json +++ b/public/plugin.json @@ -1,5 +1,5 @@ { - "version": "1.4.2", + "version": "1.4.3", "pluginName": "超级剪贴板", "description": "强大的剪贴板管理工具", "author": "ZiuChen", diff --git a/public/preload.js b/public/preload.js index 60a18b2..31cec88 100644 --- a/public/preload.js +++ b/public/preload.js @@ -1,5 +1,6 @@ const { existsSync, readFileSync, writeFileSync, mkdirSync } = require('fs') const crypto = require('crypto') +const listener = require('./listener') const { clipboard } = require('electron') const time = require('./time') @@ -11,5 +12,6 @@ window.exports = { mkdirSync, crypto, clipboard, - time + time, + Buffer } diff --git a/src/App.vue b/src/App.vue index 338f6e9..72fca0c 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,8 +1,8 @@ diff --git a/src/cpns/ClipItemList.vue b/src/cpns/ClipItemList.vue index 457081d..d0050f8 100644 --- a/src/cpns/ClipItemList.vue +++ b/src/cpns/ClipItemList.vue @@ -80,9 +80,18 @@ const props = defineProps({ currentActiveTab: { type: String, required: true + }, + isSearchPanelExpand: { + type: Boolean, + required: true } }) -const emit = defineEmits(['onDataChange', 'onDataRemove', 'onSelectItemAdd', 'onMultiCopyExecute']) +const emit = defineEmits([ + 'onDataChange', + 'onDataRemove', + 'onMultiCopyExecute', + 'toggleMultiSelect' +]) const isOverSizedContent = (item) => { const { type, data } = item if (type === 'text') { @@ -111,6 +120,7 @@ const handleItemClick = (ev, item) => { if (props.isMultiple === true) { const i = selectItemList.value.indexOf(item) // 在已选中列表中的位置 const index = props.showList.indexOf(item) // 在全部列表中的位置 + activeIndex.value = index if (selectItemList.value.length !== 0 && isShiftDown.value) { // 列表不为空 且 Shift按下 多选 // 找到selectList的最高位与最低位 @@ -159,8 +169,6 @@ const handleItemClick = (ev, item) => { selectItemList.value.push(item) // 添加到已选列表中 } } - - emit('onSelectItemAdd') } else { const { button } = ev if (button === 0) { @@ -178,7 +186,11 @@ const handleItemClick = (ev, item) => { } } const activeIndex = ref(0) -const handleMouseOver = (index) => (activeIndex.value = index) +const handleMouseOver = (index) => { + if (!props.isMultiple) { + activeIndex.value = index + } +} // 父组件中改变了引用类型的地址 故要用 getter返回 watch( () => props.showList, @@ -194,25 +206,23 @@ onMounted(() => { const isCopy = (ctrlKey || metaKey) && (key === 'C' || key === 'c') const isNumber = parseInt(key) <= 9 && parseInt(key) >= 0 const isShift = key === 'Shift' + const isSpace = key === ' ' + const activeNode = !props.isMultiple + ? document.querySelector('.clip-item.active' + (isArrowDown ? '+.clip-item' : '')) + : document.querySelector('.clip-item.multi-active' + (isArrowDown ? '+.clip-item' : '')) if (isArrowUp) { + if (activeIndex.value === 1) window.toTop() if (activeIndex.value > 0) { activeIndex.value-- - const activeNode = document.querySelector('.clip-item.active') - if (activeIndex.value === 1) { - window.toTop() - } else { - activeNode?.previousElementSibling?.previousElementSibling?.scrollIntoView({ - block: 'nearest', - inline: 'nearest' - }) - } + activeNode.previousElementSibling.previousElementSibling.scrollIntoView({ + block: 'nearest', + inline: 'nearest' + }) } } else if (isArrowDown) { if (activeIndex.value < props.showList.length - 1) { activeIndex.value++ - document - .querySelector('.clip-item.active+.clip-item') - ?.scrollIntoView({ block: 'nearest', inline: 'nearest' }) + activeNode.scrollIntoView({ block: 'nearest', inline: 'nearest' }) } } else if (isCopy) { if (!props.fullData.data) { @@ -246,6 +256,25 @@ onMounted(() => { if (props.isMultiple) { isShiftDown.value = true } + } else if (isSpace) { + if (props.isSearchPanelExpand) { + // 搜索栏展开状态 不进入多选 + return + } + if (!props.isMultiple) { + emit('toggleMultiSelect') // 如果不是多选状态 则切换到多选状态 + } + e.preventDefault() + const i = selectItemList.value.findIndex((item) => item === props.showList[activeIndex.value]) + if (i !== -1) { + selectItemList.value.splice(i, 1) // 如果已选中 则取消选中 + } else { + selectItemList.value.push(props.showList[activeIndex.value]) // 如果未选中 则选中 + activeIndex.value++ + document + .querySelector('.clip-item.multi-active+.clip-item') + .scrollIntoView({ block: 'nearest', inline: 'nearest' }) + } } }) document.addEventListener('keyup', (e) => { diff --git a/src/cpns/ClipSwitch.vue b/src/cpns/ClipSwitch.vue index 9e38a94..a5882f9 100644 --- a/src/cpns/ClipSwitch.vue +++ b/src/cpns/ClipSwitch.vue @@ -4,7 +4,7 @@