Send IPC message from main process to renderer process Electron - javascript

Currently I have an Electron menu with a save button on it. When this save button is pressed I wish to send an event to the renderer process, for the renderer to handle the event.
Here is what I have attempted:
Menu Source
const menuTemplate = [
{
label: "File",
submenu: [
{
label: "Save",
accelerator: "Ctrl+S",
click: () => {
BrowserWindow.getFocusedWindow().webContents.send("save");
}
},
]
},
]
Renderer Source
ipc.on("save", () => {
console.log("save");
})
Preload source
import { contextBridge, ipcRenderer } from "electron";
contextBridge.exposeInMainWorld("ipc", { on: ipcRenderer.on });
When trying this I get no output whatsoever when pressing the save button, including no errors. I can confirm that the correct menu is being utilised by Electron and that the click() function is executing. I can also confirm that ipc.on is indeed defined in the renderer.
How can I get this working? Thanks in advance.

Try setting the this manually in the on function.
contextBridge.exposeInMainWorld("ipc", { on: ipcRenderer.on.bind(ipcRenderer) });
or make a new function that passes the args:
contextBridge.exposeInMainWorld("ipc", { on(event, fn) { ipcRenderer.on(event, fn) } });

Related

Is there a way to let the program remember which URL was open when the user closed the program?

Is there a way to let the program remember which URL was open when the user closed the program? For example if the user closes the application, the last URL gets added to the loadURL. The program is being used for users that only can interact with touchscreen and cant leave the specific site. I am using windows 10 and the newest version of electron.
// Modules to control application life and create native browser window.
const { app, BrowserWindow, Menu } = require("electron");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
frame: false,
webPreferences: {
preload: `${__dirname}/preload.js`
}
});
// The loadURL that loads if you start up the application.
mainWindow.loadURL("https://google.com");
// Emitted when the window is closed.
mainWindow.on("closed", function() {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
// The toggleFullScreen function stated in the createMainMenu function.
function toggleFullscreen() {
if (mainWindow.isFullScreen()) {
mainWindow.setFullScreen(false);
} else {
mainWindow.setFullScreen(true);
}
}
function createMainMenu() {
const template = [
{
label: "Options",
submenu:
[
{
label: "Quit",
accelerator: "CmdOrCtrl+Q",
click() {
app.quit();
}
},
{
label: 'Toggle full screen',
accelerator: 'CmdOrCtrl+F',
click: () => {
toggleFullscreen();
}
},
{
label: 'Toggle developer tools',
accelerator: 'CmdOrCtrl+I',
click(item, focusedWindow){
focusedWindow.toggleDevTools();
}
}
]
}
];
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", () => {
createWindow();
createMainMenu();
});
// Quit when all windows are closed.
app.on("window-all-closed", function() {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q.
if (process.platform !== "darwin") {
app.quit();
}
});
app.on("activate", function() {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
You have two options.
First, each time the URL changes, use LocalStorage in the renderer process. It will work just like in a web app.
Second, each the URL changes, have it send a message back to the main process, and have it write that to a local file. getPath('appData') can be used to get the OS-specific directory of where settings files can be written.

Are there events for when an Electron app is shown and hidden?

I have been looking for Electron app events for when the application is shown or hidden. I see in the docs that there is 'browser-window-blur' and 'browser-window-focus' but those do not do what I want.
I would like to know when the user has switched to another application or switched back to my app. The above events get triggered if the user switches between browser windows – including the "developer's tools" window.
The code in main.js
app.on('browser-window-focus', () => {
if (mainWindow) {
console.log('browser-window-focus');
mainWindow.webContents.send('projectMsg', { "event": "focus" });
}
});
app.on('browser-window-blur', () => {
console.log('browser-window-blur');
if (mainWindow) {
mainWindow.webContents.send('projectMsg', { "event": "blur" });
}
});
It seems to me that it works exactly as you described, so maybe the requirements are different.
This code
const {app, BrowserWindow} = require('electron')
app.on('browser-window-focus', (event, win) => {
console.log('browser-window-focus', win.webContents.id)
})
app.on('browser-window-blur', (event, win) => {
if (win.webContents.isDevToolsFocused()) {
console.log('Ignore this case')
} else {
console.log('browser-window-blur', win.webContents.id)
}
})
app.once('ready', () => {
new BrowserWindow()
new BrowserWindow().webContents.openDevTools({detach: true})
})
works the following way (in 3.0.3) given that nothing is focused initially:
Clicking on window 1 prints browser-window-focus 1
Clicking on window 2 prints browser-window-blur 1 browser-window-focus 2
Clicking on devtools window prints browser-window-blur 2 Ignore this case
So as far as I see devtool is not included in these events, windows are getting blurred for any other window focused (including devtool)
There is also show and hide, though you have to explicitly show/hide the app with win.show() and win.hide() to trigger these events.
Check out of these BrowserWindow's events:
Event: 'blur': Emitted when the window loses focus.
Event: 'show': Emitted when the window is shown.
For example:
app.once('ready', () => {
let mainWindow = new BrowserWindow({show: false}) //Create main window
mainWindow.on('show', () => {
//Do something
})
})
Hope this help.

Quill: How to handle keyboard events on custom blot

I've created custom inline-blot and want to handle keyboard events on it.
In constructor i wrote code like this:
class FooBlot extends Inline {
constructor(domNode, value){
super(domNode, value);
domNode.addEventListener('keydown', (event) => {this.keydown_handler(event)});
domNode.addEventListener('click', (event) => {this.click_handler(event)});
};
When i try to do something with my blot, only click event was handled, not keydown event.
You can see code example here.
Open console, click on sometext and you will see "clicked" in console.
But if you try to press some keyboard buttons, e.g. arrows, you will not see anything.
What the right way to handle keyboard events on my custom blot?
The right way to handle keyboard events is to use Keyboard Module
Simple example to handle Enter key:
const bindings = {
enter: {
key: 13,
shiftKey: null,
handler: (range, context) => {
// Handle enter
}
}
};
this.quill = new Quill('#editor-container', {
modules: {
keyboard: {
bindings
},
toolbar: '#toolbar'
},
theme: 'snow'
});
UPDATE
Another way:
quill.root.addEventListener('keydown', evt => {
// Your code goes here
});

inline keyboard click doesnt call callback_query why?

bot.onText(/(.+)$/, function (msg, match) {
const opts = {
reply_markup: {
inline_keyboard: [
[
{
text: 'Edit Text',
callback_data: 'edit'
}
]
]
}
};
bot.sendMessage(msg.from.id, 'Original Text', opts);
});
bot.on("callback_query", function(callbackQuery) {
// 'callbackQuery' is of type CallbackQuery
console.log(callbackQuery);
});
I have looking for answer to this question, tried all the resources available on call_back. Such as
Telegram bot inline keyboard via Node.JS
Telegram inline keyboard and keyboard
How can create menu for telegram bot in bot father?
How about trying this like that?
bot.on('callback_query', function onCallbackQuery(callbackQuery) {
const action = callbackQuery.data;
const msg = callbackQuery.message;
// do your stuff
if (action === 'adress') {
// do something if callback data is "adress", you can have multiple if statements for various cases
}
});
That's how I got it working, hope it helps!

Electron global shortcut to toggle show/hide of menubar

I am trying to add a global shortcut to my Electron app that will toggle showing/hiding it. My app is a menubar app built using maxogden/menubar and React.
I have the following code. I've left a couple of bits out just for brevity but this is how I have setup the global shortcuts.
I think it's important to note one of the tips on the maxogden/menubar Readme too:
Use mb.on('after-create-window', callback) to run things after your
app has loaded
const { globalShortcut } = require('electron');
const keyboardShortcuts = {
open: 'CommandOrControl+Shift+g',
close: 'CommandOrControl+Shift+g'
}
menu.on('after-create-window', () => {
globalShortcut.register(keyboardShortcuts.open, () => {
menu.window.show();
});
});
menu.on('after-show', () => {
globalShortcut.unregister(keyboardShortcuts.open);
globalShortcut.register(keyboardShortcuts.close, () => {
menu.window.hide();
});
});
menu.on('focus-lost', () => {
globalShortcut.unregister(keyboardShortcuts.close);
globalShortcut.register(keyboardShortcuts.open, () => {
menu.window.show();
});
});
Once the menubar has first been opened, my shortcut is registered and will work to show the app. However, the code I've implemented to unregister the shortcut, and re-register it to hide the app (when showing), doesn't seem to work.
I'm not sure if my code to reregister the shortcut is setup within the right event handler i.e after-show and focus-lost. I have a feeling that these event handlers I'm working within are related directly to my menu rather than menu.window. This would explain why the reregistration of the shortcut isn't happening, but I'm not sure.
Does anyone have any idea how I would sensibly set up a global shortcut toggle to open/close my menubar app?
From the menubar docs (https://github.com/maxogden/menubar) the menubar instance exposes the following methods:
{
app: the electron require('app') instance,
window: the electron require('browser-window') instance,
tray: the electron require('tray') instance,
positioner: the electron-positioner instance,
setOption(option, value): change an option after menubar is created,
getOption(option): get an menubar option,
showWindow(): show the menubar window,
hideWindow(): hide the menubar window
}
Using menu.showWindow() & menu.hideWindow() instead of menu.window.show() & menu.window.hide() will work.
I would further suggest that you use the built in events to manage your state, simplifying your code and implementation:
const { globalShortcut } = require('electron');
let isShown = false;
menu
.on('after-show', () => { isShown = true })
.on('after-hide', () => { isShown = false })
.on('focus-lost', () => { isShown = false });
globalShortcut.register('CommandOrControl+Shift+g', () => {
isShown ? menu.hideWindow() : menu.showWindow()
});

Categories

Resources