ref: 优化 取色和截屏

This commit is contained in:
muwoo
2021-07-16 16:10:19 +08:00
parent de6e33c126
commit d824f503e6
42 changed files with 564 additions and 2438 deletions

View File

@@ -1,103 +0,0 @@
const { BrowserWindow, ipcMain, globalShortcut } = require("electron");
const os = require('os')
const path = require('path')
module.exports = () => {
let captureWins = []
let init = () => {
if (captureWins.length) {
return
}
createWindow();
};
let createWindow = () => {
const { screen } = require('electron');
let displays = screen.getAllDisplays();
captureWins = displays.map((display) => {
let captureWin = new BrowserWindow({
// window 使用 fullscreen, mac 设置为 undefined, 不可为 false
fullscreen: os.platform() === 'win32' || undefined,
width: display.bounds.width,
height: display.bounds.height,
x: display.bounds.x,
y: display.bounds.y,
transparent: true,
frame: false,
movable: false,
resizable: false,
enableLargerThanScreen: true,
hasShadow: false,
show: false,
title: 'capture',
webPreferences: {
enableRemoteModule: true,
nodeIntegration: true,
webSecurity: false,
devTools: false,
}
})
captureWin.setAlwaysOnTop(true, 'screen-saver')
captureWin.setFullScreenable(false)
captureWin.loadFile(`${__static}/plugins/capture/index.html`);
let { x, y } = screen.getCursorScreenPoint()
if (x >= display.bounds.x && x <= display.bounds.x + display.bounds.width && y >= display.bounds.y && y <= display.bounds.y + display.bounds.height) {
captureWin.focus()
} else {
captureWin.blur()
}
captureWin.on("closed", () => {
captureWin = undefined;
});
captureWin.once('ready-to-show', () => captureWin.show());
return captureWin
});
};
let getWindow = () => captureWins;
const close = () => {
const wins = BrowserWindow.getAllWindows();
wins.forEach((win) => {
if (win.title === 'capture') win.close();
captureWins = [];
})
}
ipcMain.on('capture-screen', (e, { type = 'start', screenId, winId, x, y } = {}) => {
if (type === 'start') {
init()
} else if (type === 'complete') {
if (captureWins) {
captureWins.forEach(win => win.close())
captureWins = []
}
// nothing
} else if (type === 'select') {
captureWins.forEach(win => win.webContents.send('capture-screen', { type: 'select', screenId }))
} else if (type === 'getAllDisplays') {
const { screen } = require('electron');
let displays = screen.getAllDisplays();
const currentScreen = displays.filter(d => d.bounds.x === x && d.bounds.y === y)[0];
e.sender.send('getAllDisplays', {
screen: {
scaleFactor: currentScreen.scaleFactor,
id: currentScreen.id,
bounds: currentScreen.bounds,
},
winId,
});
}
});
return {
init: init,
getWindow: getWindow,
close,
};
};

View File

@@ -1,7 +1,6 @@
module.exports = () => ({
picker: require("./picker")(),
separator: require("./separate")(),
capture: require("./capture")(),
superPanel: require("./superPanel")(),
main: require("./main")(),
});

View File

@@ -13,14 +13,13 @@ module.exports = () => {
win = new BrowserWindow({
frame: false,
autoHideMenuBar: true,
width: 100,
height: 100,
width: 108,
height: 108,
transparent: true,
alwaysOnTop: true,
resizable: false,
focusable: true,
hasShadow: false,
// icon: nativeImage.createFromPath(`${dirname}/build/icon.png`),
webPreferences: {
nodeIntegration: true,
devTools: false,

View File

@@ -1,5 +1,4 @@
const {stringify} = require('query-string');
const { BrowserWindow, nativeImage } = require("electron");
const { BrowserWindow } = require("electron");
module.exports = () => {
let win;
@@ -10,7 +9,7 @@ module.exports = () => {
let createWindow = (opts) => {
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080/#/plugin?${stringify(opts)}`
? `http://localhost:9080/#/plugin`
: `${__dirname}/index.html`
win = new BrowserWindow({
height: 600,
@@ -27,11 +26,14 @@ module.exports = () => {
nodeIntegration: true // 在网页中集成Node
}
});
process.env.NODE_ENV === 'development' ? win.loadURL(winURL) : win.loadFile(winURL, {
hash: `#/plugin?${stringify(opts)}`,
hash: `#/plugin`,
});
win.once('ready-to-show', () => win.show());
win.webContents.executeJavaScript(`window.setPluginInfo(${opts})`).then(() => {
win.show()
});
win.on("closed", () => {
win = undefined;
});

View File

@@ -1,12 +1,8 @@
import {app, BrowserWindow, dialog} from 'electron';
import {getlocalDataFile, saveData, getData} from './utils';
import path from "path";
const puppeteer = require("puppeteer-core");
const pie = require("puppeteer-in-electron")
const appPath = path.join(getlocalDataFile());
const dbPath = path.join(appPath, './db.json');
let browser
pie.initialize(app).then(res => {
@@ -34,93 +30,6 @@ export default {
setExpendHeight({height}, mainWindow) {
mainWindow.setSize(800, height || 60);
},
db: {
put({data}) {
data._rev = '';
let dbData = getData(dbPath) || [];
let target = [];
dbData.some((d, i) => {
if (d._id === data._id) {
target = [d, i]
return true;
}
return false;
});
// 更新
if (target[0]) {
dbData[target[1]] = data;
} else {
dbData.push(data);
}
saveData(dbPath, dbData);
return {
id: data._id,
ok: true,
rev: '',
}
},
get({key}) {
const dbData = getData(dbPath) || [];
return dbData.find(d => d._id === key) || {};
},
remove({key}) {
key = typeof key === 'object' ? key._id : key;
let dbData = getData(dbPath);
let find = false;
dbData.some((d, i) => {
if (d._id === key) {
dbData.splice(i, 1);
find = true;
return true;
}
return false;
});
if (find) {
saveData(dbPath, dbData);
return {
id: key,
ok: true,
rev: '',
}
} else {
return {
id: key,
ok: false,
rev: '',
}
}
},
bulkDocs({docs}) {
const dbData = getData(dbPath);
dbData.forEach((d, i) => {
const result = docs.find(data => data._id === d._id);
if (result) {
dbData[i] = result;
}
});
saveData(dbPath, dbData);
return docs.map(d => ({
id: d._id,
success: true,
rev: '',
}))
},
allDocs({key}) {
const dbData = getData(dbPath);
if (!key) {
return dbData;
}
if (typeof key === 'string') {
return dbData.filter(d => d._id.indexOf(key) >= 0);
}
if (Array.isArray(key)) {
return dbData.filter(d => key.indexOf(d._id) >= 0);
}
return [];
}
},
ubrowser: {
goto: async ({winId}) => {

View File

@@ -1,117 +1,13 @@
import {
globalShortcut,
ipcMain,
BrowserWindow,
clipboard,
Notification,
app,
screen,
} from 'electron';
import Api from './api';
import robot from 'robotjs';
import {app} from 'electron';
import './config';
import ioHook from 'iohook';
const browsers = require("../browsers")();
const {picker, separator, superPanel, capture} = browsers;
// 需要在超级面板展示的插件
let optionPlugin = [];
let closePicker = () => {
if (picker.getWindow()) {
ipcMain.removeListener("closePicker", closePicker);
picker.getWindow().close();
}
};
function registerShortCut(mainWindow) {
const config = global.opConfig.get();
globalShortcut.unregisterAll();
// 注册偏好快捷键
globalShortcut.register(config.perf.shortCut.showAndHidden, () => {
const {x, y} = screen.getCursorScreenPoint();
const currentDisplay = screen.getDisplayNearestPoint({ x, y });
const wx = parseInt(currentDisplay.workArea.x + currentDisplay.workArea.width / 2 - 400);
const wy = parseInt(currentDisplay.workArea.y + currentDisplay.workArea.height / 2 - 200);
mainWindow.setVisibleOnAllWorkspaces(true);
mainWindow.focus();
mainWindow.setVisibleOnAllWorkspaces(false);
mainWindow.setPosition(wx, wy);
mainWindow.show();
});
globalShortcut.register(config.perf.shortCut.separate, () => {
mainWindow.webContents.send('new-window');
});
// 注册自定义全局快捷键
config.global.forEach(sc => {
if (!sc.key || !sc.value) return;
globalShortcut.register(sc.key, () => {
mainWindow.webContents.send('global-short-key', sc.value);
});
});
globalShortcut.register('Esc', () => {
capture.close();
});
}
const getSelectedText = () => {
return new Promise((resolve) => {
const lastText = clipboard.readText('clipboard');
const platform = process.platform;
if (platform === 'darwin') {
robot.keyTap('c', 'command');
} else {
robot.keyTap('c', 'control');
}
setTimeout(() => {
const text = clipboard.readText('clipboard') || ''
const fileUrl = clipboard.read('public.file-url');
clipboard.writeText(lastText);
resolve({
text,
fileUrl
})
}, 300);
})
}
import Listener from './listener';
export default function init(mainWindow) {
ipcMain.on('optionPlugin', (e, args) => {
optionPlugin = args;
});
ipcMain.on('right-down', async (e) => {
const copyResult = await getSelectedText();
let win = superPanel.getWindow();
if (win) {
win.webContents.send('trigger-super-panel', {
...copyResult,
optionPlugin: optionPlugin.plugins,
});
} else {
superPanel.init(mainWindow);
win = superPanel.getWindow();
win.once('ready-to-show', () => {
win.webContents.send('trigger-super-panel', {
...copyResult,
optionPlugin: optionPlugin.plugins,
});
});
}
const pos = robot.getMousePos();
win.setPosition(parseInt(pos.x), parseInt(pos.y));
win.show();
});
const listener = new Listener();
// 注册快捷键
registerShortCut(mainWindow);
listener.registerShortCut(mainWindow);
listener.init(mainWindow);
// 设置开机启动
const config = global.opConfig.get();
@@ -127,92 +23,11 @@ export default function init(mainWindow) {
}
});
ipcMain.on('re-register', (event, arg) => {
registerShortCut(mainWindow);
});
ipcMain.on('changeWindowSize-rubick', (event, arg) => {
mainWindow.setSize(arg.width || 800, arg.height);
});
// 打包后,失焦隐藏
mainWindow.on('blur', () => {
app.isPackaged && mainWindow.hide();
});
// 响应 preload.js 事件
ipcMain.on('msg-trigger', async (event, arg) => {
const window = arg.winId ? BrowserWindow.fromId(arg.winId) : mainWindow
const operators = arg.type.split('.');
let fn = Api;
operators.forEach((op) => {
fn = fn[op];
});
const data = await fn(arg, window);
event.sender.send(`msg-back-${arg.type}`, data);
});
// 窗口分离
ipcMain.on('new-window', (event, arg) => {
const opts = {
...arg,
searchType: 'subWindow',
}
separator.init(opts);
});
// 拾色器
ipcMain.on('start-picker', () => {
// 开启输入侦测
ioHook.start(false);
ioHook.load();
picker.init();
picker.getWindow().on('close', () => {
ioHook.stop();
ioHook.unload();
});
let pos = robot.getMousePos();
picker
.getWindow()
.setPosition(parseInt(pos.x) - 50, parseInt(pos.y) - 50);
picker
.getWindow()
.webContents.send(
"updatePicker",
robot.getPixelColor(pos.x, pos.y)
);
ipcMain.on("closePicker", closePicker);
});
ioHook.on('mousemove', e => {
let x = e.x
let y = e.y
if (!picker.getWindow()) return;
let color = "#" + robot.getPixelColor(parseInt(x), parseInt(y));
picker.getWindow().setPosition(parseInt(x) - 50, parseInt(y) - 50);
picker.getWindow().webContents.send("updatePicker", color);
})
ioHook.on('mouseup', e => {
if (e.button === 1) {
let x = e.x
let y = e.y
const color = "#" + robot.getPixelColor(parseInt(x), parseInt(y));
clipboard.writeText("#" + robot.getPixelColor(parseInt(x), parseInt(y)));
new Notification({ title: 'Rubick 通知', body: `${color} 已保存到剪切板` }).show();
closePicker();
}
});
ioHook.on('mouseup', e => {
if (e.button === 3) {
closePicker()
}
});
}

265
src/main/common/listener.js Normal file
View File

@@ -0,0 +1,265 @@
import {BrowserWindow, clipboard, globalShortcut, ipcMain, Notification, screen} from "electron";
import {exec, spawn} from "child_process";
import robot from "robotjs";
import Api from "./api";
import ioHook from 'iohook';
const browsers = require("../browsers")();
const {picker, separator, superPanel} = browsers;
class Listener {
constructor() {
this.optionPlugin = {};
}
getSelectedContent() {
return new Promise((resolve) => {
const lastText = clipboard.readText('clipboard');
// todo 缓存文件
clipboard.clear();
// 复制选中文案
const platform = process.platform;
if (platform === 'darwin') {
robot.keyTap('c', 'command');
} else {
robot.keyTap('c', 'control');
}
setTimeout(() => {
// 延时一定时间才能从剪切板内读取到内容
const text = clipboard.readText('clipboard') || ''
const fileUrl = clipboard.read('public.file-url');
// 如果之前是文案,则回填
clipboard.writeText(lastText);
resolve({
text,
fileUrl
})
}, 300);
})
}
registerShortCut(mainWindow) {
const config = global.opConfig.get();
globalShortcut.unregisterAll();
// 注册偏好快捷键
globalShortcut.register(config.perf.shortCut.showAndHidden, () => {
const {x, y} = screen.getCursorScreenPoint();
const currentDisplay = screen.getDisplayNearestPoint({ x, y });
const wx = parseInt(currentDisplay.workArea.x + currentDisplay.workArea.width / 2 - 400);
const wy = parseInt(currentDisplay.workArea.y + currentDisplay.workArea.height / 2 - 200);
mainWindow.setVisibleOnAllWorkspaces(true);
mainWindow.focus();
mainWindow.setVisibleOnAllWorkspaces(false);
mainWindow.setPosition(wx, wy);
mainWindow.show();
});
globalShortcut.register(config.perf.shortCut.separate, () => {
mainWindow.webContents.send('new-window');
});
// 注册自定义全局快捷键
config.global.forEach(sc => {
if (!sc.key || !sc.value) return;
globalShortcut.register(sc.key, () => {
mainWindow.webContents.send('global-short-key', sc.value);
});
});
}
init(mainWindow) {
this.colorPicker();
this.initPlugin();
this.lockScreen();
this.separate();
this.initCapture();
this.superPanel(mainWindow);
this.reRegisterShortCut(mainWindow);
this.changeSize(mainWindow);
this.msgTrigger(mainWindow);
}
colorPicker() {
// 拾色器
ipcMain.on('start-picker', () => {
// 开启输入侦测
ioHook.start(false);
ioHook.load();
picker.init();
picker.getWindow().on('close', () => {
ioHook.stop();
ioHook.unload();
});
let pos = robot.getMousePos();
picker
.getWindow()
.setPosition(parseInt(pos.x) + 10, parseInt(pos.y) + 10);
const img = robot.screen.capture(parseInt(pos.x) - 5, parseInt(pos.y) - 5, 9, 9);
const colors = {}
for(let i = 0; i< 9; i++) {
colors[i] = {};
for (let j = 0; j < 9; j++) {
colors[i][j] = img.colorAt(j, i);
}
}
picker
.getWindow()
.webContents.send(
"updatePicker",
colors
);
ipcMain.on("closePicker", () => {
this.closePicker();
});
});
ioHook.on('mousemove', e => {
let x = e.x
let y = e.y
if (!picker.getWindow()) return;
let color = "#" + robot.getPixelColor(parseInt(x), parseInt(y));
picker.getWindow().setPosition(parseInt(x) + 10, parseInt(y) + 10);
const img = robot.screen.capture(parseInt(x) - 5, parseInt(y) - 5, 9, 9);
const colors = {}
for(let i = 0; i< 9; i++) {
colors[i] = {};
for (let j = 0; j < 9; j++) {
colors[i][j] = img.colorAt(j, i);
}
}
picker.getWindow().webContents.send("updatePicker", colors);
})
ioHook.on('mouseup', e => {
if (e.button === 1) {
let x = e.x
let y = e.y
const color = "#" + robot.getPixelColor(parseInt(x), parseInt(y));
clipboard.writeText("#" + robot.getPixelColor(parseInt(x), parseInt(y)));
new Notification({ title: 'Rubick 通知', body: `${color} 已保存到剪切板` }).show();
this.closePicker();
}
});
ioHook.on('mouseup', e => {
if (e.button === 3) {
this.closePicker()
}
});
}
closePicker() {
if (picker.getWindow()) {
ipcMain.removeListener("closePicker", this.closePicker);
picker.getWindow().close();
}
}
initPlugin() {
ipcMain.on('optionPlugin', (e, args) => {
this.optionPlugin = args;
});
}
lockScreen() {
// 锁屏
ipcMain.on('lock-screen', () => {
const lockCommands = {
darwin: '/System/Library/CoreServices/"Menu Extras"/User.menu/Contents/Resources/CGSession -suspend',
win32: 'rundll32.exe user32.dll, LockWorkStation',
linux: '(hash gnome-screensaver-command 2>/dev/null && gnome-screensaver-command -l) || (hash dm-tool 2>/dev/null && dm-tool lock)'
};
exec(lockCommands[process.platform]);
});
}
superPanel(mainWindow) {
// 长按右击呼起超级面板
ipcMain.on('right-down', async () => {
const copyResult = await this.getSelectedContent();
let win = superPanel.getWindow();
if (win) {
win.webContents.send('trigger-super-panel', {
...copyResult,
optionPlugin: this.optionPlugin.plugins,
});
} else {
superPanel.init(mainWindow);
win = superPanel.getWindow();
win.once('ready-to-show', () => {
win.webContents.send('trigger-super-panel', {
...copyResult,
optionPlugin: this.optionPlugin.plugins,
});
});
}
const pos = robot.getMousePos();
win.setPosition(parseInt(pos.x), parseInt(pos.y));
win.show();
});
}
reRegisterShortCut(mainWindow) {
ipcMain.on('re-register', (event, arg) => {
this.registerShortCut(mainWindow);
});
}
changeSize(mainWindow) {
// 修改窗口尺寸
ipcMain.on('changeWindowSize-rubick', (event, arg) => {
mainWindow.setSize(arg.width || 800, arg.height);
});
}
msgTrigger(mainWindow) {
// 响应 preload.js 事件
ipcMain.on('msg-trigger', async (event, arg) => {
const window = arg.winId ? BrowserWindow.fromId(arg.winId) : mainWindow
const operators = arg.type.split('.');
let fn = Api;
operators.forEach((op) => {
fn = fn[op];
});
const data = await fn(arg, window);
event.sender.send(`msg-back-${arg.type}`, data);
});
}
separate() {
// 窗口分离
ipcMain.on('new-window', (event, arg) => {
const opts = {
...arg,
searchType: 'subWindow',
}
separator.init(JSON.stringify(opts));
});
}
initCapture() {
ipcMain.on('capture-screen', () => {
spawn('/usr/sbin/screencapture', ["-c", "-i", "-r"], {detached: !0});
});
}
}
export default Listener;

View File

@@ -36,7 +36,7 @@ function createTray(window) {
click() {
dialog.showMessageBox({
title: '拉比克',
message: '一站式前端开发工具箱',
message: '极简、插件化的现代桌面软件',
detail: `Version: ${pkg.version}\nAuthor: muwoo`
});
}
@@ -45,6 +45,14 @@ function createTray(window) {
id: 7,
role: 'quit',
label: '退出'
},
{
id: 7,
label: '重启',
click() {
app.relaunch();
app.exit();
}
}
]);
appIcon.on('click', () => {