やあ、みなさん。
SlateというMac専用のオープンソースのウィンドウマネージャを使うと、キーボード生活が楽になります。
jigish/slate - GitHub
Macにおけるウィンドウマネージャ的な役割を担うソフトウェアで有名なものには『BetterTouchTool』や『Spectacle』なんかがあるかと思いますが、それらよりかはかなり細かく設定できると思われて便利です。
設定方法
ホームフォルダに".slate.js"というJavaScriptファイルを置いとくと、それを設定ファイルとして読み込んでくれます。専用の表記方法を利用した".slate"というファイルも置いておけるらしくて、これらはショートカットキーが被ってなければ共存できるらしいです。
何ができるの?
この記事の最後に僕が使っている".slate.js"のソースを載せますが、それを使うと以下のようなことができます。| alt-shift-tab | 複数ウィンドウあるアプリを画面にタイル状に並べる |
| alt-cmd-t | iTermにフォーカスor起動 |
| alt-cmd-e | Emacs〃 |
| alt-cmd-b | Firefox〃 |
| alt-cmd-f | Finder〃 |
| alt-cmd-d | Dictionary〃 |
| alt-cmd-i | iTunes〃 |
| alt-cmd-space | Found〃 |
| alt-cmd-p | Preview〃 |
| alt-cmd-m | Mjograph〃 |
| alt-h, j, k or l | Vimライクにウィンドウのフォーカスを移動 |
| alt-i | 下に隠れているウィンドウをフォーカス |
| alt-p | スクリーン間でフォーカスを移動 |
| alt-shift-p | 次のスクリーンへ飛ばす |
| alt-shift-o | 四隅に飛ばす |
| alt-shift-u | 左右に飛ばす |
| alt-shift-i | 上下に飛ばす |
| alt-shift-h | ウィンドウが左にあるなら縮小, 右にあるなら拡大 |
| alt-shift-l | ウィンドウが右にあるなら縮小, 左にあるなら拡大 |
| alt-shift-k | ウィンドウが上にあるなら縮小, 下にあるなら拡大 |
| alt-shift-j | ウィンドウが下にあるなら縮小, 上にあるなら拡大 |
| alt-shift-m | ウィンドウを最大化 |
| alt-n | 同じアプリケーションで別のウィンドウにフォーカスする |
alt-cmd系はアプリを起動するものに割り当てて、alt-shift系はウィンドウのリサイズ関係、alt系はウィンドウのフォーカス関係になってます。
alt-ctrlは僕のキーボード配列じゃ打ちづらいんで入れてませんが、入れてもいいと思います。
設定
以下が僕の".slate.js"ファイルです。JavaScript分かんないんで、ほとんどコピペです。
// http://yohasebe.com/wp/archives/3513
// for tiling windows of focused app onto desktop
// (2 x 2, clockwise)
var topLeft = slate.operation("corner", {
"direction" : "top-left",
"width" : "screenSizeX/2",
"height" : "screenSizeY/2"
});
var topRight = slate.operation("corner", {
"direction" : "top-right",
"width" : "screenSizeX/2",
"height" : "screenSizeY/2"
});
var bottomRight = slate.operation("corner", {
"direction" : "bottom-right",
"width" : "screenSizeX/2",
"height" : "screenSizeY/2"
});
var bottomLeft = slate.operation("corner", {
"direction" : "bottom-left",
"width" : "screenSizeX/2",
"height" : "screenSizeY/2"
});
// [tab]+alt+shiftでアプリのウィンドウをタイル状に並べる
var tileKey = "tab:alt;shift";
slate.bind(tileKey, function(win){
var appName = win.app().name();
var tiled = {};
tiled[appName] = {
"operations" : [topLeft, topRight, bottomRight, bottomLeft],
"main-first" : true,
"repeat" : true
};
var tiledLayout = slate.layout("tiledLayout", tiled);
slate.operation("layout", {"name" : tiledLayout }).run();
slate.operation("show", {"app" : appName}).run();
});
// http://d.hatena.ne.jp/sugyan/20130301/1362129310
// アプリ立ち上げる関数
var launch_and_focus = function (target) {
return function (win) {
var apps = [];
S.eachApp(function (app) { apps.push(app.name()); });
if (! _.find(apps, function (name) { return name === target; })) {
win.doOperation(
S.operation('shell', {
command: "/usr/bin/open -a " + target,
waithFoeExit: true
})
);
}
win.doOperation(S.operation('focus', { app: target }));
};
};
S.bind('t:alt,cmd', launch_and_focus('iTerm'));
S.bind('e:alt,cmd', launch_and_focus('Emacs'));
S.bind('b:alt,cmd', launch_and_focus('Firefox'));
S.bind('f:alt,cmd', launch_and_focus('Finder'));
S.bind('d:alt,cmd', launch_and_focus('Dictionary'));
S.bind('i:alt,cmd', launch_and_focus('iTunes'));
S.bind('space:alt,cmd', launch_and_focus('Found'));
S.bind('p:alt,cmd', launch_and_focus('Preview'));
S.bind('m:alt,cmd', launch_and_focus('Mjograph'));
// http://www.infiniteloop.co.jp/blog/2013/08/osx_slate/
var util = {
// alt + ..
key: function(k, mod) {
return k + ':alt' + (mod ? ',' + mod : '');
},
focusWindow: function(f) {
var hit = false;
slate.eachApp(function(app) {
if (hit) return;
app.eachWindow(function(win) {
if (hit) return;
if (f(win)) {
win.focus();
hit = true;
}
});
});
},
nextScreen: function(screen) {
return slate.screenForRef(String( (screen.id()+1)%slate.screenCount() ));
}
};
// ----------- 以下 alt+
// hjkl .. その方向へフォーカス移動
slate.bind(util.key('h'), slate.operation('focus', { direction: 'left' }));
slate.bind(util.key('j'), slate.operation('focus', { direction: 'down' }));
slate.bind(util.key('k'), slate.operation('focus', { direction: 'up' }));
slate.bind(util.key('l'), slate.operation('focus', { direction: 'right' }));
// i .. 下に隠れているウィンドウをフォーカス
slate.bind(util.key('i'), slate.operation('focus', { direction: 'behind' }));
// p .. スクリーン間でフォーカスを移動
slate.bind(util.key('p'), function(win) {
var next = util.nextScreen(slate.screen());
util.focusWindow(function(win) {
return win.screen().id() == next.id();
});
});
// p+shift .. 次のスクリーンへ飛ばす
slate.bind(util.key('p', 'shift'), function(win) {
if (!win) return;
var next = util.nextScreen(win.screen());
win.move(next.visibleRect());
});
// o+shift .. 4隅に飛ばす
var corners = slate.bind(util.key('o', 'shift'), slate.operation('chain', {
operations: _.map(['top-right', 'bottom-right', 'bottom-left', 'top-left'], function(d) {
return slate.operation('corner', {
direction: d,
width: 'screenSizeX/2',
height: 'screenSizeY/2'
});
})
}));
// u+shift .. 左右に飛ばす
slate.bind(util.key('u', 'shift'), slate.operation('chain', {
operations: _.map(['left', 'right'], function(d) {
return slate.operation('push', {
direction: d,
style: 'bar-resize:screenSizeX/2'
});
})
}));
// i+shift .. 上下に飛ばす
slate.bind(util.key('i', 'shift'), slate.operation('chain', {
operations: _.map(['top', 'bottom'], function(d) {
return slate.operation('push', {
direction: d,
style: 'bar-resize:screenSizeY/2'
});
})
}));
// h+shift .. ウィンドウが左にあるなら縮小, 右にあるなら拡大
slate.bind(util.key('h', 'shift'), function(win) {
if (!win) return;
var rect = win.rect();
var bounds = win.screen().visibleRect();
if (bounds.x + bounds.width - 30 < rect.x + rect.width) {
rect.x -= bounds.width * 0.05;
rect.width = bounds.x + bounds.width - rect.x;
} else {
rect.width -= bounds.width * 0.05;
}
win.doOperation('move', rect);
});
// l+shift .. ウィンドウが右にあるなら縮小, 左にあるなら拡大
slate.bind(util.key('l', 'shift'), function(win) {
if (!win) return;
var rect = win.rect();
var bounds = win.screen().visibleRect();
if (rect.x < bounds.x + 30) {
rect.x = bounds.x;
rect.width += bounds.width * 0.05;
} else {
rect.x += bounds.width * 0.05;
rect.width -= bounds.width * 0.05;
}
win.doOperation('move', rect);
});
// k+shift .. ウィンドウが上にあるなら縮小, 下にあるなら拡大
slate.bind(util.key('k', 'shift'), function(win) {
if (!win) return;
var rect = win.rect();
var bounds = win.screen().visibleRect();
if (bounds.y + bounds.height - 30 < rect.y + rect.height) {
rect.y -= bounds.height * 0.05;
rect.height += bounds.height * 0.05;
} else {
rect.height -= bounds.height * 0.05;
}
win.doOperation('move', rect);
});
// j+shift .. ウィンドウが下にあるなら縮小, 上にあるなら拡大
slate.bind(util.key('j', 'shift'), function(win) {
if (!win) return;
var rect = win.rect();
var bounds = win.screen().visibleRect();
if (rect.y < bounds.y + 30) {
rect.y = bounds.y;
rect.height += bounds.height * 0.05;
} else {
rect.y += bounds.height * 0.05;
rect.height -= bounds.height * 0.05;
}
win.doOperation('move', rect);
});
// m .. 最大化
slate.bind(util.key('m', 'shift'), function(win) {
if (!win) return;
var bounds = win.screen().visibleRect();
win.doOperation('move', bounds);
});
// http://mint.hateblo.jp/category/Slate
// 同じアプリケーションで別のウィンドウにフォーカスする (Chrome対応版)
S.bind('n:alt', function() {
function get_next_win(windows) {
truth_values_of_is_main = _.map(windows, function(w){ return w.isMain(); })
next_idx = _.indexOf(truth_values_of_is_main, 1) + 1;
if (next_idx >= _.size(windows)) { return windows[0]; }
return windows[next_idx];
}
windows = [];
slate.app().eachWindow(function(win){
if (win.title() !== '') { windows.push(win); } // タイトルが無いウィンドウは無視
});
if (_.size(windows) === 1){ return; }
sorted = _.sortBy(windows, function(win){ return win.title(); });
get_next_win(sorted).focus();
});
設定し終わったらマウスを外に投げましょう。追記
ウィンドウの微妙な位置調整がやりたい場面があって、その関数がまだ無かったので作りました。Alt + Shift + WASDキーで上下左右の移動ができるようになります。
// d+shift .. ウィンドウを右に移動
slate.bind(util.key('d', 'shift'), function(win) {
if (!win) return;
var rect = win.rect();
var bounds = win.screen().visibleRect();
rect.x += bounds.width * 0.05;
win.doOperation('move', rect);
});
// a+shift .. ウィンドウを左に移動
slate.bind(util.key('a', 'shift'), function(win) {
if (!win) return;
var rect = win.rect();
var bounds = win.screen().visibleRect();
rect.x -= bounds.width * 0.05;
win.doOperation('move', rect);
});
// s+shift .. ウィンドウを下に移動
slate.bind(util.key('s', 'shift'), function(win) {
if (!win) return;
var rect = win.rect();
var bounds = win.screen().visibleRect();
rect.y += bounds.height * 0.05;
win.doOperation('move', rect);
});
// w+shift .. ウィンドウを上に移動
slate.bind(util.key('w', 'shift'), function(win) {
if (!win) return;
var rect = win.rect();
var bounds = win.screen().visibleRect();
rect.y -= bounds.height * 0.05;
win.doOperation('move', rect);
});
参考サイト
Slateを入れてみた - すぎゃーんメモSlate - ミントフレーバー緑茶
Slateの設定ファイル(JavaScript版) | yohasebe.com
OS Xで作業効率を5%上げるSlateの紹介 | 株式会社インフィニットループ技術ブログ

0 件のコメント :
コメントを投稿