グローバルなホットキーでQuickSearchを開始する
更新履歴
2020/2/10
公開
2020/2/14
インプットメソッドを強制的に切り替える機能を追加
2020/4/5追記 : CatalinaではCarbon APIが使えなくなっているため動作しませんでした
/icons/hr.icon
Macユーザー向けの記事です。
Scrapboxを表示しているブラウザを最前面に出して、先頭のタブをアクティブにして、QuickSearchの窓にフォーカスを当てる、という操作を一度に実行するJXAスクリプトを紹介します。
スクリプトの機能
以下の操作を連続して行い、直ちに検索を開始できるようにする
Scrapboxを表示しているブラウザアプリを最前面に持ってくる
先頭のタブをアクティブにする
検索窓にフォーカスを当て、入力状態にする
利用に必要なアプリ
利用の必須条件
以下のいずれかのブラウザがScrapbox専用ブラウザとして常に起動されていて、先頭のタブに検索対象のプロジェクトが常に表示されている
Google Chrome
Vivaldi
Microsoft Edge
Brave Browser
Safari
/icons/hr.icon
導入の手順
1. ブラウザ側の「Apple EventsからのJavaScriptを許可」をEnabledにする
2. ホットキーにJXAスクリプトの実行を割り当てる
Alfredなら、Workflowsの「Run Script」アクションの「usr/bin/osascript (JS)」
BetterTouchToolなら、 「他のアプリケーションを制御する」 ->「 Apple Scriptを実行する」 -> 「ソースの種類 : Java Script」
3. スクリプトの先頭にある設定項目を適宜編集する
余談ですが、
QuickSearchの結果(ドロップダウン)からページを選択する時
QuickSearchではヒットしなかったので通常の検索に移行する時
に、Enterではなく、Commandを押しながらEnterすると結果が新しいタブで開きます。
定数appは適宜コメントアウトを付与、解除してください。
code:js
// 使用するブラウザアプリ
// const app = Application('Google Chrome');
const app = Application('Vivaldi');
// const app = Application('Microsoft Edge');
// const app = Application('Brave Browser');
// const app = Application('Safari');
// IMを切り替える機能を使うか (Catalinaでは動作しない)
const isSwitchingInputSourceEnabled = false;
// macOS標準
// const inputSourceID = 'com.apple.inputmethod.Kotoeri.Roman'; // 英字
const inputSourceID = 'com.apple.inputmethod.Kotoeri.Japanese'; // ひらがな
// Google日本語入力
// const inputSourceID = 'com.google.inputmethod.Japanese.Roman'; // 英数 (Google)
// const inputSourceID = 'com.google.inputmethod.Japanese.base'; // ひらがな (Google)
if (isSwitchingInputSourceEnabled) {
switchInputSource(inputSourceID);
}
app.activate();
const window = app.windows0; const jsString = `{
const selector = 'input.form-control';
const form = document.querySelector(selector);
if (form) {
form.value = '';
form.dispatchEvent(new Event('input', {'bubbles': true, 'cancelable': true}));
form.blur();
form.focus();
} else {
alert(selector + ' not found.');
}
}`;
switch (app.name()) {
case 'Google Chrome':
case 'Vivaldi':
case 'Microsoft Edge':
case 'Brave Browser': {
window.activeTabIndex = 1;
app.execute(window.activeTab(), {javascript : jsString});
break;
}
case 'Safari': {
window.currentTab = window.tabs0; app.doJavaScript(jsString, {in: window.currentTab()});
break;
}
default: {
break;
}
}
function switchInputSource(targetSourceID) {
ObjC.import('Carbon');
ObjC.bindFunction('CFMakeCollectable', ['id', 'void *']); const $targetSource = $.TISCreateInputSourceList(undefined, false).js.find($source => {
const $sourceID = $.TISGetInputSourceProperty($source, $.kTISPropertyInputSourceID);
return ObjC.unwrap($.CFMakeCollectable($sourceID)) === targetSourceID;
});
if ($targetSource) {
$.TISSelectInputSource($targetSource);
}
}
// inputSourceID を調べる関数
function seekInputSourceIDs() {
ObjC.import('Carbon');
ObjC.bindFunction('CFMakeCollectable', ['id', 'void *']); $.TISCreateInputSourceList(undefined, false).js.forEach(($source, index) => {
const $localizedName = $.TISGetInputSourceProperty($source, $.kTISPropertyLocalizedName);
const $sourceID = $.TISGetInputSourceProperty($source, $.kTISPropertyInputSourceID);
console.log(index, ObjC.unwrap($.CFMakeCollectable($localizedName)), ObjC.unwrap($.CFMakeCollectable($sourceID)));
});
}