Node.js
MacOSX
Cocoa
Electron

Electron on Macでclick-thruを実現する

More than 1 year has passed since last update.

Electronで作成するアプリケーションのウィンドウをクリックスルー(そのウィンドウの下をクリックさせる)という記事です。本来Electronはクロスプラットフォームですが今回の記事ではOS Xのみ動きます。

Electron 0.35.3まではクリックスルーが実装されてなかったのですが、0.36.0からOS Xに限り実装されました!


やり方

let win = new BrowserWindow({opt....})

win.setIgnoreMouseEvents(true)

これだけです。BrowserWindowsetIgnoreMouseEventsというメソッドが追加されたので引数にtrueを指定すれば、そのウィンドウはクリックスルーになります。


以下古い内容

Electronではアプリケーションウィンドウを透明にしたり枠をなくしたりできるのですがなぜかクリックスルーは実装されていません。Cocoa APIをたたくことで実現できます。


nodobjcでCocoa APIをたたく

nodobjcは、Cocoa APIというか、Objective-Cの機能にアクセスするためのものです。一つ罠があってnpmで公開されているnodobjcは古すぎて動きません。直接Githubのリポジトリを指定してインストールしましょう。

npm i https://github.com/TooTallNate/NodObjC.git --save


setIgnoresMouseEvents

click-thruを実現するCocoa APIがsetIgnoresMouseEventsで、これはNSWindowクラスに対して実行するメソッドです。そのため、Electronのウィンドウを取得する必要があります。

とりあえず僕がいろいろ試した中で唯一成功したのは


  • Electronのbrowserプロセス側で

  • NSApplication.sharedApplicationして得られたNSApplicationに対して

  • windowsメソッドで得られたNSWindowの配列の一番目

で取得するというやり方だけでした。

nodobjcを使った書き方にすると以下の通り。

$.NSApplication('sharedApplication')('windows')('objectAtIndex', 0)('setIgnoresMouseEvents', $.YES)

ただ、このやり方はおそらく問題があって、絶妙なタイミングでウィンドウがもう一つ追加されてトップに表示されていたら、そいつに誤爆する可能性があるということです。まぁelectronのプロセスで謎のウィンドウが勝手に生えてくるという自体は起きるものでもないでしょうから基本的には考えなくてもいいかもしれませんが、そういう可能性もあるというのは念頭に置いた方がいいかもしれません。

個人的にこれを探す上での大きな罠は、rendererプロセスの方ではなく、browserプロセス側で実行しなければならなかった点でしょうか。


ソースコード

var app = require('app')

var BrowserWindow = require('browser-window')
var $ = require('nodobjc')

$.import('Foundation')
$.import('Cocoa')

app.on('window-all-closed', function() {
app.quit();
});

app.on('ready', function() {
var win = new BrowserWindow({
frame: false,
width: 800,
height: 600,
transparent: true,
'always-on-top': true,
});
win.loadUrl('file://' + __dirname + '/index.html');
win.webContents.on('did-finish-load', function(){
$.NSApplication('sharedApplication')('windows')('objectAtIndex', 0)('setIgnoresMouseEvents', $.YES);
});
});

index.htmlは適当に用意してください。注意点はウィンドウをクリックできないため、終了するための手段を別途用意した方がよくて、具体的にはトレイアイコンを用意した上でトレイから終了できるようにしておく方が吉です。