Node webkit hotkey example not working - node.js

I'm trying to play around with node webkits hotkey example which can be viewed on their Shortcut's page here: https://github.com/nwjs/nw.js/wiki/Shortcut
Here's my code:
test.js
// Load native UI library.
var gui = window.require('nw.gui');
var option = {
key : "Ctrl+Shift+A",
active : function() {
console.log("Global desktop keyboard shortcut: " + this.key + " active.");
},
failed : function(msg) {
// :(, fail to register the |key| or couldn't parse the |key|.
console.log(msg);
}
};
// Create a shortcut with |option|.
var shortcut = new gui.Shortcut(option);
// Register global desktop shortcut, which can work without focus.
gui.App.registerGlobalHotKey(shortcut);
// If register |shortcut| successfully and user struck "Ctrl+Shift+A", |shortcut|
// will get an "active" event.
// You can also add listener to shortcut's active and failed event.
shortcut.on('active', function() {
console.log("Global desktop keyboard shortcut: " + this.key + " active.");
});
shortcut.on('failed', function(msg) {
console.log(msg);
});
// Unregister the global desktop shortcut.
gui.App.unregisterGlobalHotKey(shortcut);
index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
<script>
require("./test.js");
</script>
</head>
<body>
<h1>Hello World!</h1>
We are using node.js <script>document.write(process.version)</script>.
</body>
</html>
package.json
{
"name": "nw-demo",
"main": "index.html",
"dependencies": {
"nw": "^0.12.0"
},
"scripts": {
"start": "nw"
}
}
It breaks at this line on test.js saying undefined is not a function.
var shortcut = new gui.Shortcut(option);

Just remove this line:
gui.App.unregisterGlobalHotKey(shortcut);
In your code you register it, then delete. It working well for me (mac, nwjs 0.12)

As shaynem in (https://github.com/nwjs/nw.js/issues/3263#issuecomment-89679115) points out you should be running at least node-webkit >= 0.10.0
You should make sure your PATH (or the build tool you're using, e.g. nodebob) is not referencing any old leftover versions of node-webkit after you upgrade.
Also if you're on Ubuntu, you might stumble upon an open issue (https://github.com/nwjs/nw.js/issues/3199)

note webkit 0.13.0 has a bug where the the k is lowercase even though the method is documented with an uppercase K. Try:
registerGlobalHotkey(shortcut);
to verify this bug exists do:
var util = require('util');
console.log(util.inspect(nw.App));

Related

socket.io - multiple connections causing slow message emits to server

Note: When I delete "node_modules\uws\uws_win32_59.node" it works fine. uws is used by engine.io, which is used by socket.io.
I wrote a very basic app to demo the problem. In the below app, with 2 tabs of the index.html open in chrome, clicking "emit" emits the message from the client, but takes a significant, variable amount of time to reach the server. Anywhere from 2-15+ seconds. If I only have 1 index.html page open, it works fine, but once a second one is opened, I encounter the problem. If I delete the above uws_win32_59.node, it works fine with multiple connections.
server.js:
var io = require('socket.io')();
io.on('connection', function(socket){
console.log('connection made');
socket.on('number', function(num) {
console.log(num + ' received on server');
io.emit('number', num);
console.log(num + ' emitted from server');
});
});
io.listen(9001);
index.html:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
</head>
<body>
<button id="emit">emit</button>
<p id="nums"></p>
<script>
var socket = io('http://localhost:9001');
socket.on('number', function(num){
console.log(num + ' received on client');
document.getElementById('nums').innerHTML = num;
});
var num = 0;
document.getElementById('emit').addEventListener('click', function(){
num++;
socket.emit('number', num);
console.log(num + ' emitted from client');
});
</script>
</body>
</html>
the default "npm install socket.io" installs that uws module mentioned above, which itself is used by engine.io.
run "node server" and open 2 instances of the index.html and click emit and notice the browser developer tools console logging and the node server console logging to recreate the issue.
EDIT: looks like there is an open issue with uws on windows os: https://github.com/socketio/socket.io/issues/3100
Maybe you need npm install socket.io#1.7.4. I think version 2.0 is significantly slower

Check when WebKit context is available in NW.js

When executed in Node context (node-main),
setTimeout(function () {
console.log(nw);
}, 20);
throws
nw is not defined
because WebKit context is not ready (right from the start window is unavailable in NW.js <= 0.12, window.nw in NW.js >= 0.13). And
setTimeout(function () {
console.log(nw);
}, 200);
works just fine but setTimeout looks like a hack, setting it to safe delay value may cause undesirable lag.
How can the availability of WebKit context and nw be checked from Node context? Is there a reasonable way, like an event that could be handled?
The following achieves the same thing but does it the other way around.
In your html file:
<body onload="process.mainModule.exports.init()">
In your node-main JS file:
exports.init = function() {
console.log(nw);
}
Here, init function is only called when Webkit context/DOM is available.
You could use pollit :) ...
var pit = require("pollit");
foo = function(data) {
console.log(nw);
};
pit.nw('nw', foo);
I've tested it and it works for me :). This modularizes the solution that I give near the end of this.
The nw object does not exist until webkit is up and running ie the browser
window has been created. This happens after Node starts up which is why you're
getting this error. To use the nw api you either create events that can be
listened to or call global functions the former being preferable. The following code will demonstrate both and should give you a good idea of how Node and WebKit are interfacing with each other.
This example creates a Window, opens devtools and allows you to toggle the
screen. It also displays the mouse location in the console. It also demonstrates how to send events using the DOM ie body.onclick() and attaching events from within Node ie we're going to catch minimize events and write them to the console.
For this to work you need to be using the SDK version of NW. This is my package.json
{
"name": "hello",
"node-main": "index.js",
"main": "index.html",
"window": {
"toolbar": true,
"width": 800,
"height": 600
},
"dependencies" : {
"robotjs" : "*",
"markdown" : "*"
}
}
The two files you need are index.html
<!DOCTYPE html>
<html>
<head>
<script>
var win = nw.Window.get();
global.win = win;
global.console = console;
global.main(nw);
global.mouse();
var markdown = require('markdown').markdown;
document.write(markdown.toHTML("-->Click between the arrows to toggle full screen<---"));
</script>
</head>
<body onclick="global.mouse();">
</body>
</html>
and index.js.
var robot = require("robotjs");
global.mouse = function() {
var mouse = robot.getMousePos();
console.log("Mouse is at x:" + mouse.x + " y:" + mouse.y);
global.win.toggleFullscreen();
}
global.main = function(nw_passed_in) {
global.win.showDevTools();
console.log("Starting main");
console.log(nw_passed_in);
console.log(nw);
global.win.on('minimize', function() {
console.log('n: Window is minimized from Node');
});
}
When running this I used
nwjs --enable-logging --remote-debugging-port=1729 ./
You can then open up the browser using
http://localhost:1729/
for debugging if needed.
If you want to do something as soon as the nw object exists you can poll it. I'd use eventEmitter, if you don't want to use event emitter you can just as easily wrap this in a function and call it recursively. The following will display how many milliseconds it took before the nw object was setup. On my system this ranged between 43 - 48 milliseconds. Using a recursive function was no different. If you add this to the code above you'll see everything logged to the console.
var start = new Date().getTime();
var events = require('events');
var e = new events.EventEmitter();
var stop = 0;
e.on('foo', function() {
if(typeof nw === 'undefined') {
setTimeout(function () {
e.emit('is_nw_defined');
}, 1);
}
else {
if(stop === 0) {
stop = new Date().getTime();
}
setTimeout(function () {
console.log(stop - start);
console.log(nw);
e.emit('is_nw_defined');
}, 2000);
}
});
e.emit('is_nw_defined');
Solution 1:
You can use onload, see reference.
main.js:
var gui = require("nw.gui"),
win = gui.Window.get();
onload = function() {
console.log("loaded");
console.log(win.nw);
};
index.html:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="main.js"></script>
</head>
<body></body>
</html>
package.json:
{
"name": "Freebox",
"main": "index.html"
}
Solution 2:
(To prevent issue, but it is not necessary).
var gui = require("nw.gui"),
win = gui.Window.get();
onload = function() {
console.log("loaded");
var a = function () {
if (!win.nw) return setTimeout(a, 10);
console.log(win.nw);
};
};
The solution I've initially come up looks like
app-node.js
process.once('webkit', () => {
console.log(nw);
});
app.html
<html>
<head>
<script>
global.process.emit('webkit');
</script>
...
I would be glad to know that there is already an event to listen, so cross-platform client scripts could omit NW-related code.

I am not able to access variable 'dps' declare in index.js within index.html , using npm start

I am not able to access variable 'dps' declare in index.js within index.html , using npm start(for starting electron app)
I am able to access my sql and get data in index.js and i want to show that on index.html (used nodeJs and Electron)
'dps' refers to js object which has mysql data
//My index.js file has
var app = require('app');
var dps = [{x:1,y:2}];
// Module to create native browser window.
var BrowserWindow = require('browser-window');
var mainWindow = null;
var dps = [{x:1,y:2}];
var mysql = require('mysql');
// Quit when all windows are closed.
app.on('window-all-closed', function () {
if (process.platform != 'darwin') {
app.quit();
}
});
app.on('ready', function () {
// Create the browser window.
mainWindow = new BrowserWindow({ width: 800, height: 600 });
mainWindow.loadUrl('file://' + __dirname + '/index.html');
// Open the devtools.
// mainWindow.openDevTools();
// 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;
});
});
//My html file
<html>
<head>
<!--<script type="text/javascript" src = "index.js"/>-->
<script type="text/javascript" src="index.js"></script>
<script type="text/javascript">
alert(dps); --- not getting dps value here(/anywhere in html)
</head>
</html>
Your code in index.html runs in a different process (usually called the Renderer process) than your in index.js (which runs in the Main process). Furthermore, your index.js file is a module, therefore, even if the two were run by the same process, you'd have to export your dps variable or make it a global variable like global.dps (however, that's a bad practice!).
There are a number of ways to share date between the Main and the Renderer process; Electron provides the ipcMain, ipcRenderer and remote modules for that purpose; you can also pass data from Main to the Renderer using URL encoded parameters (but this doesn't help you if the data changes); finally, you can use any other form of IPC (e.g., send messages over a socket, use shared memory or shared files, etc.) -- but it's a good idea to start with Electron's ipc or remote modules.
Having said that, in your case, the consensus seems to be not to use the Main process for DB access only to then pass the information on to the Renderer, but rather access the DB directly from the Renderer; that way you won't have to worry about IPC at all (at least in this case).

pipe child process stdout & stdin to browser in node.js & browserify

I am attempting to pipe the stdout & stdin of a child_process to a browser & display it in an html page. I am using browserify to get node.js to run on the browser. My code for spawning the child_process is like this.
var child = require('child_process');
var myREPL = child.spawn('myshell.exe', ['args']);
// myREPL.stdout.pipe(process.stdout, { end: false });
process.stdin.resume();
process.stdin.pipe(myREPL.stdin, { end: false });
myREPL.stdin.on('end', function() {
process.stdout.write('REPL stream ended.');
});
myREPL.on('exit', function (code) {
process.exit(code);
});
myREPL.stdout.on('data', function(data) {
console.log('\n\nSTDOUT: \n');
console.log('**************************');
console.log('' + data);
console.log('==========================');
});
I created a bundle.js using browserify and my html looks like this.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<!--[if IE]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script src="bundle.js"></script>
<script src="main.js"></script>
</head>
<body>
</body>
</html>
I am trying to avoid running an http server and piping the results to it in the browser. Is there any other way where I can do it ?
Thanks
You should look into hyperwatch, which pipes the server side stdout/stderr to the browser and renders it exactly like it would appear in your terminal (including colors).
If it doesn't exactly solve your problem, reading through the code should at least help you. It uses hypernal under the hood in order to convert terminal output to html.
I dont know if this is to late but i managed to run a program from browser starting from this code that works only on linux (i use ubuntu). You will have to run interactive programs with stdbuf -o0 prefix.
var child = require('child_process');
var myREPL = child.spawn('bash');
process.stdin.pipe(myREPL.stdin);
myREPL.stdin.on("end", function() {
process.exit(0);
});
myREPL.stdout.on('data', function (data) {
console.log(data+'');
});
myREPL.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
An then to make it to work on browser you only need to add socket.io
var myREPL = child.spawn(program);
myREPL.stdin.on("end", function() {
socket.emit('consoleProgramEnded');
});
myREPL.stdout.on('data', function (data) {
socket.emit('consoleWrite',data+'');
});
myREPL.stderr.on('data', function (data) {
socket.emit('consoleWrite',data+'');
});
socket.on('consoleRead',function(message){
console.log("Writing to console:"+message);
myREPL.stdin.write(message.replace("<br>","")+"\n");
});
I hope that will help you.
I think the frontail NPM module can also do what you want to do -
https://github.com/mthenw/frontail
I have used it and it works

phantomjs and requirejs

codes in file main.js is like this:
phantom.injectJs("libs/require-1.0.7.js");
require.config(
{
baseUrl: ""
}
);
require([], function(){});
when i run "phantomjs main.js" in the commandline, requirejs doesn't work well in the main.js. I know how to use requirejs in the page running in the browser(including phantomjs' way: page.open(url, callback)), but not like above. I tries using requirejs like the main.js, it is a popular problem, i think. Thank you!
I just struggled for some time. My solution is not clean, but it works, and I'm happy with that due to the unfinished api documentation from phantomjs.
Wordy explanation
You need three files. One is your amd phantomjs test file which I'll call "amd.js". The second is your html page to load which I'll name "amd.html". Finally the browser test which I called "amdTestModule.js".
In amd.html, declare your script tag per normal:
<script data-main="amdTestModule.js" src="require.js"></script>
In your phantomjs test file, this is where it gets hacky. Create your page, and load in the 'fs' module. This allows you to open a relative file path.
var page = require('webpage').create();
var fs = require('fs');
page.open('file://' + fs.absolute('tests/amd.html'));
Now since requirejs loads files asynchronously, we can't just pass in a callback into page.open and expect things to go smoothly. We need some way to either
1) Test our module in the browser and communicate the result back to our phantomjs context. Or
2) Tell our phantomjs context that upon loading all the resources, to run a test.
#1 was simpler for my case. I accomplished this via:
page.onConsoleMessage = function(msg) {
msg = msg.split('=');
if (msg[1] === 'success') {
console.log('amd test successful');
} else {
console.log('amd test failed');
}
phantom.exit();
};
**See full code below for my console.log message.
Now phantomjs apparently has an event api built in but it is undocumented. I was also successfully able to get request/response messages from their page.onResourceReceived and page.onResourceRequested - meaning you can debug when all your required modules are loaded. To communicate my test result however, I just used console.log.
Now what happens if the console.log message is never ran? The only way I could think of resolving this was to use setTimeout
setTimeout(function() {
console.log('amd test failed - timeout');
phantom.exit();
}, 500);
That should do it!
Full Code
directory structure
/projectRoot
/tests
- amd.js
- amdTestModule.js
- amd.html
- require.js (which I symlinked)
- <dependencies> (also symlinked)
amd.js
'use strict';
var page = require('webpage').create();
var fs = require('fs');
/*
page.onResourceRequested = function(req) {
console.log('\n');
console.log('REQUEST');
console.log(JSON.stringify(req, null, 4));
console.log('\n');
};
page.onResourceReceived = function(response) {
console.log('\n');
console.log('RESPONSE');
console.log('Response (#' + response.id + ', stage "' + response.stage + '"): ' + JSON.stringify(response, null, 4));
console.log('\n');
};
*/
page.onConsoleMessage = function(msg) {
msg = msg.split('=');
if (msg[1] === 'success') {
console.log('amd test successful');
} else {
console.log('amd test failed');
}
phantom.exit();
};
page.open('file://' + fs.absolute('tests/amd.html'));
setTimeout(function() {
console.log('amd test failed - timeout');
phantom.exit();
}, 500);
amd.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script data-main='amdTestModule.js' src='require.js'></script>
</body>
</html>
amdTestModule.js
require([<dependencies>], function(<dependencies>) {
...
console.log(
(<test>) ? "test=success" : "test=failed"
);
});
console
$ phantomjs tests/amd.js
amd test successful
you are misunderstanding webpage.injectJs()
it's for injecting scripts into the page you are loading, not into the phantomjs runtime environment.
So using .injectJs() is making requirejs load up into your page, not into phantomjs.exe.
That said, phantomjs's runtime environment has an aproximation of commonjs. RequireJs will not run on there by default. If you felt especially (VERY) motivated, you could attempt porting the require-shim made for nodejs, but it doesn't work out of the box, and would require an incredibly deep understanding of the runtimes. for more details: http://requirejs.org/docs/node.html
a better idea:
probably you should make sure you have commonjs versions of your javascript you wish to run. i personally write my code in typescript so i can build for either commonjs or amd. i use commonjs for phantomjs code, and amd for nodejs and browser.

Resources