Created
February 6, 2016 17:58
-
-
Save danshan/b3e902418eec2a4fc48c to your computer and use it in GitHub Desktop.
phoenix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Phoenix | |
* doc: https://github.com/jasonm23/phoenix/wiki/JavaScript-API-documentation | |
* | |
* Global Settings | |
*/ | |
var mash = ["alt"]; | |
var mashShift = ["alt", "shift"]; | |
var mashCtrl = ["alt", "ctrl"]; | |
var CMD_BTN = ["cmd"]; | |
var mousePositions = {}; | |
var HIDE_INACTIVE_WINDOW_TIME = 10; // minitus | |
var ACTIVE_WINDOWS_TIMES = {}; | |
var DEFAULT_WIDTH = 1280; | |
/** | |
* Utils Functions | |
*/ | |
function alert(message) { | |
var modal = new Modal(); | |
modal.message = message; | |
modal.duration = 2; | |
modal.show(); | |
} | |
function assert(condition, message) { | |
if (!condition) { | |
throw message || "Assertion failed"; | |
} | |
} | |
var alert_title = function(window) { Modal.show(window.title()); }; | |
function sortByMostRecent(windows) { | |
var visibleAppMostRecentFirst = _.map(Window.visibleWindowsInOrder(), | |
function(w) { return w.app().name(); }); | |
var visibleAppMostRecentFirstWithWeight = _.object(visibleAppMostRecentFirst, | |
_.range(visibleAppMostRecentFirst.length)); | |
return _.sortBy(windows, function(window) { | |
return visibleAppMostRecentFirstWithWeight[window.app().name()]; | |
}); | |
}; | |
function getNewFrame(frame, oldScreenRect, newScreenRect) { | |
} | |
function getResizeFrame(frame, ratio) { | |
var mid_pos_x = frame.x + 0.5 * frame.width; | |
var mid_pos_y = frame.y + 0.5 * frame.height; | |
return { | |
x: Math.round(frame.x + frame.width / 2 * (1 - ratio)), | |
y: Math.round(frame.y + frame.height / 2 * (1 - ratio)), | |
width: Math.round(frame.width * ratio), | |
height: Math.round(frame.height * ratio) | |
} | |
} | |
function getSmallerFrame(frame) { | |
return getResizeFrame(frame, 0.9); | |
} | |
function getLargerFrame(frame) { | |
return getResizeFrame(frame, 1.1); | |
} | |
/** | |
* Screen Functions | |
*/ | |
function moveToScreen(window, screen) { | |
if (!window) return; | |
if (!screen) return; | |
var frame = window.frame(); | |
var oldScreenRect = window.screen().frameInRectangle(); | |
var newScreenRect = screen.frameInRectangle(); | |
var xRatio = newScreenRect.width / oldScreenRect.width; | |
var yRatio = newScreenRect.height / oldScreenRect.height; | |
var mid_pos_x = frame.x + Math.round(0.5 * frame.width); | |
var mid_pos_y = frame.y + Math.round(0.5 * frame.height); | |
window.setFrame({ | |
x: (mid_pos_x - oldScreenRect.x) * xRatio + newScreenRect.x - 0.5 * frame.width, | |
y: (mid_pos_y - oldScreenRect.y) * yRatio + newScreenRect.y - 0.5 * frame.height, | |
width: frame.width, | |
height: frame.height | |
}); | |
}; | |
function windowsOnOtherScreen() { | |
var start = new Date().getTime(); | |
var otherWindowsOnSameScreen = Window.focusedWindow().otherWindowsOnSameScreen(); // slow | |
Phoenix.log('windowsOnOtherScreen 0.1: ' + (new Date().getTime() - start)); | |
var otherWindowTitlesOnSameScreen = _.map(otherWindowsOnSameScreen , function(w) { return w.title(); }); | |
var return_value = _.chain(Window.focusedWindow().otherWindowsOnAllScreens()) | |
.filter(function(window) { return ! _.contains(otherWindowTitlesOnSameScreen, window.title()); }) | |
.value(); | |
return return_value; | |
}; | |
/** | |
* Window Functions | |
*/ | |
function hide_inactiveWindow(windows) { | |
var now = new Date().getTime() / 1000; | |
_.chain(windows).filter(function(window) { | |
if (!ACTIVE_WINDOWS_TIMES[window.app().pid]) { | |
ACTIVE_WINDOWS_TIMES[window.app().pid] = now; | |
return false; | |
} | |
return true; | |
}).filter(function(window) { | |
return now - ACTIVE_WINDOWS_TIMES[window.app().pid]> HIDE_INACTIVE_WINDOW_TIME * 60; | |
//return now - ACTIVE_WINDOWS_TIMES[window.app().pid]> 5; | |
}).map(function(window) {window.app().hide()}); | |
} | |
function heartbeat_window(window) { | |
ACTIVE_WINDOWS_TIMES[window.app().pid] = new Date().getTime() / 1000; | |
//hide_inactiveWindow(window.otherWindowsOnSameScreen()); | |
} | |
function getAnotherWindowsOnSameScreen(window, offset) { | |
var start = new Date().getTime(); | |
var windows = window.otherWindowsOnSameScreen(); // slow, makes `Saved spin report for Phoenix version 1.2 (1.2) to /Library/Logs/DiagnosticReports/Phoenix_2015-05-30-170354_majin.spin` | |
Phoenix.log('getAnotherWindowsOnSameScreen 1: ' + (new Date().getTime() - start)); | |
windows.push(window); | |
windows = _.chain(windows).sortBy(function(window) { | |
return [window.frame().x, window.frame().y, window.app().pid, window.title()].join('_'); | |
}).value().reverse(); | |
return windows[(_.indexOf(windows, window) + offset + windows.length) % windows.length]; | |
} | |
function getNextWindowsOnSameScreen(window) { | |
return getAnotherWindowsOnSameScreen(window, -1) | |
}; | |
function getPreviousWindowsOnSameScreen(window) { | |
return getAnotherWindowsOnSameScreen(window, 1) | |
}; | |
function setWindowCentral(window) { | |
window.setTopLeft({ | |
x: (window.screen().frameInRectangle().width - window.size().width) / 2 + window.screen().frameInRectangle().x, | |
y: (window.screen().frameInRectangle().height - window.size().height) / 2 + window.screen().frameInRectangle().y | |
}); | |
heartbeat_window(window); | |
}; | |
/** | |
* Mouse Functions | |
*/ | |
function save_mouse_position_for_window(window) { | |
if (!window) return; | |
heartbeat_window(window); | |
mousePositions[window.title()] = Mouse.location(); | |
} | |
function set_mouse_position_for_window_center(window) { | |
Mouse.moveTo({ | |
x: window.topLeft().x + window.frame().width / 2, | |
y: window.topLeft().y + window.frame().height / 2 | |
}); | |
heartbeat_window(window); | |
} | |
function restore_mouse_position_for_window(window) { | |
if (!mousePositions[window.title()]) { | |
set_mouse_position_for_window_center(window); | |
return; | |
} | |
var pos = mousePositions[window.title()]; | |
var rect = window.frame(); | |
if (pos.x < rect.x || pos.x > (rect.x + rect.width) || pos.y < rect.y || pos. y > (rect.y + rect.height)) { | |
set_mouse_position_for_window_center(window); | |
return; | |
} | |
Mouse.moveTo(pos); | |
heartbeat_window(window); | |
} | |
function restore_mouse_position_for_now() { | |
if (Window.focusedWindow() === undefined) { | |
return; | |
} | |
restore_mouse_position_for_window(Window.focusedWindow()); | |
} | |
/** | |
* App Functions | |
*/ | |
function launchOrFocus(appName) { | |
var app = App.launch(appName); | |
assert(app !== undefined); | |
app.focus(); | |
return app; | |
} | |
//switch app, and remember mouse position | |
function callApp(appName) { | |
var window = Window.focusedWindow(); | |
if (window) { | |
save_mouse_position_for_window(window); | |
} | |
//App.launch(appName); | |
var newWindow = _.first(launchOrFocus(appName).windows()); | |
if (newWindow && window !== newWindow) { | |
restore_mouse_position_for_window(newWindow); | |
} | |
} | |
/** | |
* My Configuartion App | |
*/ | |
// Launch App | |
Phoenix.bind('`', mash, function() { callApp('iTerm'); }); | |
Phoenix.bind('1', mash, function() { callApp('Google Chrome'); }); | |
Phoenix.bind('2', mash, function() { callApp('Firefox'); }); | |
Phoenix.bind('3', mash, function() { callApp('BearyChat'); }); | |
Phoenix.bind('4', mash, function() { callApp('QQ'); }); | |
Phoenix.bind('q', mash, function() { callApp('QQ'); }); | |
Phoenix.bind('5', mash, function() { callApp('Wechat'); }); | |
Phoenix.bind('a', mash, function() { callApp('Wechat'); }); | |
Phoenix.bind('e', mash, function() { callApp('Preview'); }); | |
// Phoenix.bind('a', mash, function() { callApp('MacVim'); }); | |
Phoenix.bind('w', mash, function() { callApp('KeePassX'); }); | |
Phoenix.bind('s', mash, function() { callApp('IntelliJ IDEA 15'); }); | |
//Phoenix.bind('z', mash, function() { callApp('Mou'); }); | |
Phoenix.bind('z', mash, function() { callApp('Mou'); }); | |
//Phoenix.bind('z', mash, function() { callApp('Typora'); }); | |
//Phoenix.bind('z', mash, function() { callApp('Atom'); }); | |
Phoenix.bind(',', mash, function() { callApp('Google Chrome'); }); | |
Phoenix.bind('9', mash, function() { callApp('NeteaseMusic'); }); | |
//Phoenix.bind(',', mash, function() { callApp('Sparrow'); }); | |
//Phoenix.bind(',', mash, function() { callApp('Inky'); }); | |
Phoenix.bind('.', mash, function() { callApp('Evernote'); }); | |
Phoenix.bind('/', mash, function() { callApp('Finder'); }); | |
/** | |
* My Configuartion Screen | |
*/ | |
// Next screen, now only support 2 display // TODO | |
Phoenix.bind('l', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
if (window.screen() === window.screen().next()) return; | |
if (window.screen().next().frameInRectangle().x < window.screen().frameInRectangle().x) { | |
return; | |
} | |
save_mouse_position_for_window(window); | |
var nextScreenWindows = sortByMostRecent(windowsOnOtherScreen()); | |
if (nextScreenWindows.length > 0) { | |
nextScreenWindows[0].focus(); | |
restore_mouse_position_for_window(nextScreenWindows[0]); | |
} | |
}); | |
// Previous Screen, now only support 2 display // TODO | |
Phoenix.bind('h', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
if (window.screen() === window.screen().next()) return; | |
if (window.screen().next().frameInRectangle().x > window.screen().frameInRectangle().x) { | |
return; | |
} | |
save_mouse_position_for_window(window); | |
var nextScreenWindows = sortByMostRecent(windowsOnOtherScreen()); // find it!!! cost !!! | |
if (nextScreenWindows.length > 0) { | |
nextScreenWindows[0].focus(); | |
restore_mouse_position_for_window(nextScreenWindows[0]); | |
} | |
}); | |
// Move Current Window to Next Screen | |
Phoenix.bind('l', mashShift, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
if (window.screen() === window.screen().next()) return; | |
if (window.screen().next().frameInRectangle().x < 0) { | |
return; | |
} | |
moveToScreen(window, window.screen().next()); | |
}); | |
// Move Current Window to Previous Screen | |
Phoenix.bind('h', mashShift, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
if (window.screen() === window.screen().next()) return; | |
if (window.screen().next().frameInRectangle().x == 0) { | |
return; | |
} | |
moveToScreen(window, window.screen().previous()); | |
}); | |
/** | |
* My Configuartion Window | |
*/ | |
// Window Hide Inactive | |
Phoenix.bind('delete', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
heartbeat_window(window); | |
hide_inactiveWindow(window.otherWindowsOnAllScreens()); | |
}); | |
//Phoenix.bind('h', CMD_BTN, function() { | |
//var window = Window.focusedWindow(); | |
//if (!window) return; | |
//window.app().hide(); | |
//var window = Window.focusedWindow(); | |
//Modal.show(window.title()); // TODO need delay | |
//if (!window) return; | |
//restore_mouse_position_for_window(window); | |
//}); | |
// Window Maximize | |
Phoenix.bind('m', mashShift, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
window.maximize(); | |
setWindowCentral(window); | |
//heartbeat_window(window); | |
}); | |
// Window Smaller | |
Phoenix.bind('-', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
var oldFrame = window.frame(); | |
var frame = getSmallerFrame(oldFrame); | |
window.setFrame(frame); | |
if (window.frame().width == oldFrame.width || window.frame().height == oldFrame.height) { | |
window.setFrame(oldFrame); | |
} | |
//heartbeat_window(window); | |
}); | |
// Window Larger | |
Phoenix.bind('=', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
var frame = getLargerFrame(window.frame()); | |
if (frame.width > window.screen().frameInRectangle().width || | |
frame.height > window.screen().frameInRectangle().height) { | |
window.maximize(); | |
} else { | |
window.setFrame(frame); | |
} | |
//heartbeat_window(window); | |
}); | |
// Window Central | |
Phoenix.bind('m', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
setWindowCentral(window); | |
}); | |
// Window Height | |
Phoenix.bind('\\', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
window.setFrame({ | |
x: window.frame().x, | |
y: window.screen().frameInRectangle().y, | |
width: window.frame().width, | |
height: window.screen().frameInRectangle().height | |
}); | |
heartbeat_window(window); | |
}); | |
// Window Width | |
Phoenix.bind('\\', mashShift, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
window.setFrame({ | |
x: window.frame().x, | |
y: window.screen().frameInRectangle().y, | |
width: DEFAULT_WIDTH, // Mac width | |
height: window.frame().height | |
}); | |
heartbeat_window(window); | |
}); | |
// Window > | |
Phoenix.bind('l', mashCtrl, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
window.setFrame({ | |
x: window.frame().x + 100, | |
y: window.frame().y, | |
width: window.frame().width, | |
height: window.frame().height | |
}); | |
heartbeat_window(window); | |
}); | |
// Window < | |
Phoenix.bind('h', mashCtrl, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
window.setFrame({ | |
x: window.frame().x - 100, | |
y: window.frame().y, | |
width: window.frame().width, | |
height: window.frame().height | |
}); | |
heartbeat_window(window); | |
}); | |
// Window ^ | |
Phoenix.bind('k', mashCtrl, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
window.setFrame({ | |
x: window.frame().x, | |
y: window.frame().y - 100, | |
width: window.frame().width, | |
height: window.frame().height | |
}); | |
heartbeat_window(window); | |
}); | |
// Window v | |
Phoenix.bind('j', mashCtrl, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
window.setFrame({ | |
x: window.frame().x, | |
y: window.frame().y + 100, | |
width: window.frame().width, | |
height: window.frame().height | |
}); | |
heartbeat_window(window); | |
}); | |
// Next Window in One Screen | |
Phoenix.bind('k', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) { | |
if (Window.visibleWindowsInOrder().length == 0) return; | |
Window.visibleWindowsInOrder()[0].focus(); | |
return; | |
} | |
save_mouse_position_for_window(window); | |
var targetWindow = getNextWindowsOnSameScreen(window); | |
targetWindow.focus(); | |
restore_mouse_position_for_window(targetWindow); | |
}); | |
// Previous Window in One Screen | |
Phoenix.bind('j', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) { | |
if (Window.visibleWindowsInOrder().length == 0) return; | |
Window.visibleWindowsInOrder()[0].focus(); | |
return; | |
} | |
save_mouse_position_for_window(window); | |
var targetWindow = getPreviousWindowsOnSameScreen(window); // <- most time cost | |
targetWindow.focus(); | |
restore_mouse_position_for_window(targetWindow); | |
}); | |
/** | |
* My Configuartion Mouse | |
*/ | |
// Central Mouse | |
Phoenix.bind('space', mash, function() { | |
var window = Window.focusedWindow(); | |
if (!window) return; | |
set_mouse_position_for_window_center(window); | |
}); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment