Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在已有 app_options 的基础上提供根据当前浏览器页面进行条件判断的功能 #847

Open
shirok1 opened this issue Feb 26, 2024 · 4 comments

Comments

@shirok1
Copy link

shirok1 commented Feb 26, 2024

已经验证了通过类似 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 信息,但是从下面这张截图可以看到这个功能并没有做出来:

Screenshot 2024-02-27 at 00 29 31

bugzilla 页面 来看这个问题貌似从 Firefox 3 开始有人注意到现在都没人真正弄出来……这个页面靠后的帖子提到一个 workaround 是用 插件 将 URL(默认是只有域名部分,不过对匹配网站来讲应该完全足够)放到窗口标题。AppleScript 是能正常获取到窗口标题的,因此最后就能获得当前网站。

@shirok1
Copy link
Author

shirok1 commented Feb 26, 2024

`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

@groverlynn
Copy link
Contributor

輸入法進程接收到的客戶端是系統的輸入法服務生成的proxy,所以能有特別的輸入優先級,也因此無法使用其他API(相信蘋果有保護隱私的考慮在)。所以你說的從根本上就無法實現

@shirok1
Copy link
Author

shirok1 commented May 24, 2024

輸入法進程接收到的客戶端是系統的輸入法服務生成的proxy,所以能有特別的輸入優先級,也因此無法使用其他API(相信蘋果有保護隱私的考慮在)。所以你說的從根本上就無法實現

我尝试手动赋予输入法进程「控制其他 app 权限」确实无法生效,如果真要实现可能需要一个 helper daemon 然后与其进行 ipc

@shirok1
Copy link
Author

shirok1 commented May 24, 2024

另外如果都要单独的 helper daemon 了,那可能不如直接做个浏览器插件

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants