JXA 设置 window 边界奇怪的问题

JXA set window bounds weird issue

script1.js:

function run() {
  const chromeApp = Application('Google Chrome');
  const window = chromeApp.windows[0];
  console.log(window.name());
  window.bounds = {
    x: 0,
    y: 0,
    width: 500,
    height: 500,
  };
  chromeApp.activate();
}

运行:

osascript -l JavaScript script1.js

而且有效

script2.js:

function run() {
  const systemEvents = Application('System Events');
  const ap = systemEvents.processes().find(ap => ap.name() === 'Google Chrome');
  console.log(ap.name());
  const window = ap.windows[0];
  console.log(window.name());
  window.bounds = {
    x: 0,
    y: 0,
    width: 500,
    height: 500,
  };
}

运行:

osascript -l JavaScript script1.js

它不起作用:

script2.js: execution error: Error: Error: Can't set that. (-10006)

但我真的需要 script2.js 工作。因为在我的真实应用程序中,我事先不知道应用程序名称,我需要根据用户交互动态获取进程。因为我不知道应用程序名称,所以我不能使用 script1.js.

感谢任何意见!

function run() {
  const systemEvents = Application('System Events');
  const p = systemEvents.processes().find(ap => ap.frontmost() === true);
  const ap = Application (p.bundleIdentifier());
  const window = ap.windows[0];
  window.bounds = {
    x: 0,
    y: 0,
    width: 500,
    height: 500,
  };
  }

受罗伯特回答的启发,我发现了以下工作:

function run() {
  const systemEvents = Application('System Events');
  const p = systemEvents.processes().find(ap => ap.name() === 'Google Chrome');
  console.log(p.name());
  const app = Application(p.name());
  const window = app.windows[0];
  window.bounds = {
    x: 0,
    y: 0,
    width: 500,
    height: 500,
  };
  app.activate();
}

所以我可以通过名称将 Process 转换为 Applicationconst app = Application(p.name());然后 script2.js 变成 script1.js.

但这并不总是有效。例如,以下内容不起作用:

function run() {
  const systemEvents = Application('System Events');
  const p = systemEvents.processes().find(ap => ap.frontmost() === true);
  console.log(p.name());
  const app = Application(p.name());
  const window = app.windows[0];
  window.bounds = {
    x: 0,
    y: 0,
    width: 500,
    height: 500,
  };
  app.activate();
}

如果frontmost应用程序是Visual Studio代码。因为进程名称将是“Electron”并且将进程转换为应用程序将是错误的。

我想找到一种通过 ID 将进程转换为应用程序的方法。我仍在调查中,稍后我会 post 更新。

更新:请检查接受的答案。

多年以来我一直对使用 GUI 脚本感到不快,所以没有立即发现真正的问题。

真正的问题是,系统事件是一个臃肿、设计糟糕的混乱局面,它将十几个库的功能塞进了一个#BigBallOfMud。

SE 包括 Cocoa 脚本的标准套件 window class 定义,包括标准 bounds 属性,但实际上并没有实现它(因为SE 没有自己的 windows)。因此,虽然 SE 的字典声称 windows 元素具有 bounds 属性,但尝试 get/set 属性 会引发错误。很混乱。

因此,请忽略 SE 标准套件中的 window class 定义,只查看其 Process Suite(又名 GUI 脚本)中的 window class 定义.它没有 bounds 属性;相反,它具有单独的 positionsize 属性:

position (list of number or missing value) : the position of the window

size (list of number or missing value) : the size of the window

这是有效的代码:

tell application "System Events"
    set ap to first process whose name is "Firefox"
    set win to window 1 of ap
    -- set bounds of win to {100, 100, 600, 600} -- this doesn't actually work
    set position of win to {100, 100}
    set size of win to {500, 500}
end tell

换句话说,仅仅因为一个应用程序的字典它支持某些东西并不意味着它实际上支持。试图弄清楚应用程序的缺陷,同时还要与 JXA 的缺陷作斗争,充其量是一种西西弗斯式的练习。

先弄清楚如何让代码在 AppleScript 中运行;如果它在那里不起作用,那么您就知道是应用程序出了问题。如果你仍然想使用 JXA,那么你可以尝试将你的工作代码移植到它之后(尽管我通常不建议在 JXA 上浪费时间,因为它已经瘫痪和被遗弃,而且整个 AppleScript 堆栈无论如何都在慢慢消亡)。