squirrel
squirrel copied to clipboard
在已有 app_options 的基础上提供根据当前浏览器页面进行条件判断的功能
已经验证了通过类似 AppleScript 的进程间通信来实现的思路,不需要安装附加插件(除了 Firefox,后面会说明原因)
最简单的方法当然是直接调用 AppleScript 解释器:
(* 理论上适用于任何 Chromium-Based *)
tell application "Arc" to return URL of active tab of front window
(* Safari *)
tell application "Safari" to return URL of current tab of front window
Foundation 中已有 NSAppleScript,调用即可(但我没有找到“在切换 tab 时触发”等事件监听,所以可能需要轮询
也可以通过 ScriptingBridge 直接用 Objective-C 写逻辑:
#import <Foundation/Foundation.h>
#import "browser.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
BrowserApplication *browser = [SBApplication applicationWithBundleIdentifier:@"company.thebrowser.Browser"];
// BrowserApplication *browser = [SBApplication applicationWithBundleIdentifier:@"com.apple.safari"];
// for (BrowserWindow *window in [browser windows]) {
// NSLog(@"window %ld: name is %@", [window index], [window name]);
// }
BrowserWindow *window = browser.windows.firstObject;
// Chromium-Based 只有 activeTab,Safari 只有 currentTab,以此简单区分
BrowserTab *tab = [window respondsToSelector:@selector(activeTab)] ? window.activeTab : window.currentTab;
NSLog(@"active tab is %@ %@", tab.name, tab.URL);
}
return 0;
}
这个 browser.h 是我根据 Arc 和 Safari 原始导出的 protocol 修改合并而来的,导出 protocol 的命令是:
# 两个 CLI 都随 Xcode 安装
sdef /Applications/Arc.app/ > Firefox.sdef
sdp -fh -o Arc.h --basename 'Browser' Arc.sdef
如果有能避免维护一个 protocol 头文件的方法是否会更好?我没写过 Objective-C,网上搜索到的 id 类型似乎仍然需要“某处”有该方法约定存在,而不能完全省略 protocol 声明
Firefox 的问题是它的文档表明它需要从 document 属性获取 path 信息,但是从下面这张截图可以看到这个功能并没有做出来:
从 bugzilla 页面 来看这个问题貌似从 Firefox 3 开始有人注意到现在都没人真正弄出来……这个页面靠后的帖子提到一个 workaround 是用 插件 将 URL(默认是只有域名部分,不过对匹配网站来讲应该完全足够)放到窗口标题。AppleScript 是能正常获取到窗口标题的,因此最后就能获得当前网站。
`browser.h` 的内容
#import <AppKit/AppKit.h>
#import <ScriptingBridge/ScriptingBridge.h>
@class BrowserApplication, BrowserWindow, BrowserTab;
@protocol BrowserGenericMethods
/// All below is Chromium-Only
- (void) close; /// Close
- (void) select; /// Select the tab.
- (void) goBack; /// Go Back (If Possible).
- (void) goForward; /// Go Forward (If Possible).
- (void) reload; /// Reload a tab.
- (void) stop; /// Stop the current tab from loading.
- (NSString *) executeJavascript:(NSString *)javascript; /// Chromium-Only: Execute a piece of javascript.
- (void) focus; /// Focus on a space.
@end
/// The application's top-level scripting object.
@interface BrowserApplication : SBApplication
- (SBElementArray<BrowserWindow *> *) windows;
@property (copy, readonly) NSString *name; /// The name of the application.
@property (readonly) BOOL frontmost; /// Is this the frontmost (active) application?
@property (copy, readonly) NSString *version; /// The version of the application.
- (id) doJavaScript:(NSString *)x in:(id)in_; /// Safari-Only: Applies a string of JavaScript code to a document.
@end
/// An application's window
@interface BrowserWindow : SBObject <BrowserGenericMethods>
- (SBElementArray<BrowserTab *> *) tabs;
- (NSString *) id; /// The unique identifier of the window.
@property (copy, readonly) NSString *name; /// The full title of the window.
@property NSInteger index; /// The index of the window, ordered front to back.
@property (readonly) BOOL closeable; /// Whether the window has a close box.
@property (readonly) BOOL minimizable; /// Whether the window can be minimized.
@property BOOL minimized; /// Whether the window is currently minimized.
@property (readonly) BOOL resizable; /// Whether the window can be resized.
@property BOOL visible; /// Whether the window is currently visible.
@property (readonly) BOOL zoomable; /// Whether the window can be zoomed.
@property BOOL zoomed; /// Whether the window is currently zoomed.
@property (copy, readonly) BrowserTab *activeTab; /// Chromium-Only: Returns the currently selected tab
@property (copy) BrowserTab *currentTab; /// Safari-Only: The current tab.
@end
/// A window's tab
@interface BrowserTab : SBObject <BrowserGenericMethods>
- (NSString *) id; /// Chromium-Only: The unique identifier of the tab.
@property (copy, readonly) NSString *title; /// Chromium-Only: The full title of the tab.
@property (copy, readonly) NSString *name; /// Safari-Only: The name of the tab.
@property (copy) NSString *URL; /// The url of the tab.
@property (readonly) BOOL loading; /// Chromium-Only: Is loading?
@end
輸入法進程接收到的客戶端是系統的輸入法服務生成的proxy,所以能有特別的輸入優先級,也因此無法使用其他API(相信蘋果有保護隱私的考慮在)。所以你說的從根本上就無法實現
輸入法進程接收到的客戶端是系統的輸入法服務生成的proxy,所以能有特別的輸入優先級,也因此無法使用其他API(相信蘋果有保護隱私的考慮在)。所以你說的從根本上就無法實現
我尝试手动赋予输入法进程「控制其他 app 权限」确实无法生效,如果真要实现可能需要一个 helper daemon 然后与其进行 ipc
另外如果都要单独的 helper daemon 了,那可能不如直接做个浏览器插件