gpt4 book ai didi

objective-c - 优雅地获得和退出对话的后台应用程序焦点

转载 作者:太空狗 更新时间:2023-10-30 03:29:35 25 4
gpt4 key购买 nike

我正在开发一个小型 Mac 应用程序,它通常会在后台不可见地运行。但是,当用户在桌面或 Finder 中的其他地方重命名文件时,应用程序的主要功能就会发挥作用。发生这种情况时,我想显示一个类似于用户通过 Finder 更改文件扩展名时出现的对话框。因为这需要我的应用程序获得最前面的焦点(而不是 Finder),所以当用户在我的对话框中点击“确定”时,我想将 Finder 作为最前面的应用程序返回。

我目前正在使用 Apple 的 Process Manager函数 SetFrontProcessWithOptions(),但在以下情况下我遇到了麻烦:

  • 用户在其工作区某处打开 Finder 窗口
  • 然后用户点击他们的桌面,使窗口失去焦点。
  • 用户重命名桌面上的文件
  • 我的应用程序使用 SetFrontProcessWithOptions()
  • 使自己聚焦
  • 用户在对话框中点击 OK,我的应用使用 SetFrontProcessWithOptions()
  • 聚焦 Finder
  • 当 Finder 重新聚焦时,它会聚焦用户之前打开的窗口,尽管当 Finder 之前位于最前面时它并未聚焦。

如果您在桌面上重命名文件之前在另一个空间打开了一个 Finder 窗口,这会变得非常烦人:在这种情况下,在对话框中点击“确定”会导致 Finder 自动切换空间并返回到该窗口。

这只是因为 SetFrontProcessWithOptions() 函数的性质,它只能关注给定应用程序的一个窗口。由于桌面显然不算作一个窗口,该函数反而会找到另一个要聚焦的窗口,尽管用户之前没有聚焦该窗口。

如果有人对如何做像这样的基于对话的事情有任何更好的想法,甚至可能根本不需要聚焦和不聚焦 Finder,那就太好了。

编辑:我找到了一个有点丑陋的方法来修复这个行为,但它涉及到脚本桥,并且它不会在项目来自它被重命名了。这是我执行此操作的代码:

FinderApplication * app = [SBApplication applicationWithBundleIdentifier:@"com.apple.finder"];
if (!app || ![app isRunning]) {
SetFrontProcessWithOptions(&processSerial, kSetFrontProcessFrontWindowOnly);
return;
}
SBElementArray * selArray = app.selection.get;
if ([selArray count] == 0) {
SetFrontProcessWithOptions(&processSerial, kSetFrontProcessFrontWindowOnly);
return;
} else {
FinderWindow * window = [[[selArray objectAtIndex:0] container].get containerWindow].get;
if ([window isKindOfClass:NSClassFromString(@"FinderFinderWindow")]) {
SetFrontProcessWithOptions(&processSerial, kSetFrontProcessFrontWindowOnly);
} else {
// TODO: this is where I'd insert code to select the item
// on the desktop...
}
}

最佳答案

您是否考虑过简单地调用-[NSApp hide:nil]?也就是说,让系统担心如何重新激活以前激活的应用程序,只需确保您的应用程序不再处于事件状态即可。

顺便说一下,您观察到的行为,即 Finder 在收到事件状态时激活窗口而不是桌面,与您将 Command-Tab 离开然后返回时发生的情况相同。或者 Command-Tab 离开然后隐藏您切换到的应用程序。因此,它可能被认为是正确的行为。另一方面,在我的测试中,当 Finder 聚焦在桌面上但在不同空间上有一个窗口时隐藏前台应用程序不会切换到另一个空间。它会做你想做的事:激活以桌面为中心的 Finder。

最后,-[NSRunningApplication activateWithOptions:]SetFrontProcessWithOptions() 的现代替代品。


如果你真正想要的是一种运行等价物的方法

tell application "Finder"
activate
select the desktop's window
end tell

在 Objective-C 中,我看到了两个选项。首先,使用 Scripting Bridge API:

[self.finder activate];
[(FinderWindow*)self.finder.desktop.containerWindow select];

(我假设您已经掌握了使用 Scripting Bridge 和 Finder 的基础知识。如果没有,Apple 有一个 ScriptingBridgeFinder sample 。出于某种原因,它位于遗留文档部分。)

其次,您可以使用 NSAppleScript:

NSAppleScript* s = [[NSAppleScript alloc] initWithSource:@"tell application \"Finder\"\nactivate\nselect the desktop's window\nend tell"];
NSDictionary* err = nil;
if (![s executeAndReturnError:&err])
/* handle error */;

不过,在我对 Snow Leopard 的测试中,两种方法都无法切换到专注于桌面的 Finder。但是,您的 AppleScript 代码也没有从 AppleScript 编辑器运行。

关于objective-c - 优雅地获得和退出对话的后台应用程序焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10950802/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com