使用 Window Management API 管理多個螢幕

取得已連線螢幕和與螢幕的相對位置視窗的相關資訊。

視窗管理 API

Window Management API 可讓您列舉連接至電腦的螢幕 以及在特定畫面上放置視窗

建議用途

以下列舉可能使用此 API 的網站:

  • 多視窗圖形編輯器 Gimp 可以 在正確定位視窗中調整編輯工具
  • 虛擬交易櫃可從多個視窗顯示市場趨勢,包括位於 全螢幕模式。
  • 投影播放應用程式可在內部主畫面和簡報中顯示演講者備忘稿 外部投影機

如何使用 Window Management API

問題

我們具有時間測試的方法來控制時間區間 很抱歉,Window.open() 且完全不知道有其他螢幕的情況下雖然這個 API 的某些面向看起來有點過時,例如 windowFeatures敬上 DOMString 參數,但我們多年來一直提供待命的服務。如何指定視窗的 position,就可以傳遞 座標為 lefttop (分別稱為 screenXscreenY),並傳遞所需的資訊 尺寸widthheight (或 innerWidthinnerHeight)。舉例來說,若要開啟 400×300 視窗 (距離左側 50 像素,距離頂端 50 像素) 的程式碼 可以使用:

const popup = window.open(
  'https://example.com/',
  'My Popup',
  'left=50,top=50,width=400,height=300',
);

如需目前畫面的相關資訊,請查看 window.screen 屬性, 會傳回 Screen 物件。這是 MacBook Pro 13 吋的輸出內容:

window.screen;
/* Output from my MacBook Pro 13″:
  availHeight: 969
  availLeft: 0
  availTop: 25
  availWidth: 1680
  colorDepth: 30
  height: 1050
  isExtended: true
  onchange: null
  orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
  pixelDepth: 30
  width: 1680
*/

如同多數的科技工作人員,我都必須適應新的工作環境,並 個人居家辦公室。我的圖片看起來像下方的相片 (如果你有興趣的話,可以閱讀 完整設定詳細資訊)。 MacBook 旁邊的 iPad 透過以下方式連線至筆記型電腦 Sidecar,因此無論何時,我都能快速將 將 iPad 投放到第二個螢幕

坐在兩張椅子上的學校長椅。學校長凳上方有一個鞋子盒,外圍有一台筆電,周圍有兩支 iPad。
多螢幕設定

如果我想利用更大的螢幕,可以把 程式碼範例。我自己 輸入:

popup.moveTo(2500, 50);

由於無法得知第二個螢幕的尺寸,因此這只是粗略的猜測。資訊 來自 window.screen 僅涵蓋內建螢幕,不含 iPad 螢幕。回報的width 的內建螢幕為 1680 像素,因此移至 2500 像素或許能將 複製到 iPad,因為 我知道它位於 MacBook 右側的項目上。做法 我可以在一般情況下這麼做嗎?答案是,有比猜測更好的方法了。如此一來 Window Management API。

特徵偵測

如要檢查系統是否支援 Window Management API,請使用:

if ('getScreenDetails' in window) {
  // The Window Management API is supported.
}

window-management 權限

我必須先要求使用者授予權限,才能使用 Window Management API。 您可以使用 window-management 權限查詢 Permissions API,例如:

let granted = false;
try {
  const { state } = await navigator.permissions.query({ name: 'window-management' });
  granted = state === 'granted';
} catch {
  // Nothing.
}

在使用舊版和新權限名稱的瀏覽器時,提出權限要求時,請務必使用防禦程式碼,如以下範例所示。

async function getWindowManagementPermissionState() {
  let state;
  // The new permission name.
  try {
    ({ state } = await navigator.permissions.query({
      name: "window-management",
    }));
  } catch (err) {
    return `${err.name}: ${err.message}`;
  }
  return state;
}

document.querySelector("button").addEventListener("click", async () => {
  const state = await getWindowManagementPermissionState();
  document.querySelector("pre").textContent = state;
});

瀏覽器 可以 則會選擇在第一次嘗試使用任何 新的 API請繼續閱讀以瞭解詳情!

window.screen.isExtended 屬性

如果想知道我的裝置是否連結了多個螢幕,我可以存取 window.screen.isExtended 屬性。其會傳回 truefalse。根據我的設定,此值會傳回 true

window.screen.isExtended;
// Returns `true` or `false`.

getScreenDetails() 方法

現在我知道目前採用多螢幕設定,現在我可以進一步瞭解 使用 Window.getScreenDetails()。呼叫這個函式會顯示權限提示 詢問我是否能夠開啟網站並在我的畫面上顯示視窗。這個函式會傳回承諾 該物件會以 ScreenDetailed 物件解析在我的 MacBook Pro 13 上 (已連接 iPad) 上, 這包括一個包含兩個 ScreenDetailed 物件的 screens 欄位:

await window.getScreenDetails();
/* Output from my MacBook Pro 13″ with the iPad attached:
{
  currentScreen: ScreenDetailed {left: 0, top: 0, isPrimary: true, isInternal: true, devicePixelRatio: 2, …}
  oncurrentscreenchange: null
  onscreenschange: null
  screens: [{
    // The MacBook Pro
    availHeight: 969
    availLeft: 0
    availTop: 25
    availWidth: 1680
    colorDepth: 30
    devicePixelRatio: 2
    height: 1050
    isExtended: true
    isInternal: true
    isPrimary: true
    label: "Built-in Retina Display"
    left: 0
    onchange: null
    orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
    pixelDepth: 30
    top: 0
    width: 1680
  },
  {
    // The iPad
    availHeight: 999
    availLeft: 1680
    availTop: 25
    availWidth: 1366
    colorDepth: 24
    devicePixelRatio: 2
    height: 1024
    isExtended: true
    isInternal: false
    isPrimary: false
    label: "Sidecar Display (AirPlay)"
    left: 1680
    onchange: null
    orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
    pixelDepth: 24
    top: 0
    width: 1366
  }]
}
*/

如需已連結畫面的相關資訊,請參閱 screens 陣列。請注意 iPad 的 left1680 開始,剛好是內建螢幕的 width。這個 讓我能確實決定畫面的邏輯排列方式 (以相鄰方式, 等)。現在每個螢幕都有資料,可顯示是否為 isInternal 值 以及是否為 isPrimary 編號請注意,內建畫面 不一定是主畫面

currentScreen 欄位是與目前 window.screen 相對應的使用中物件。物件 會在跨螢幕視窗刊登位置或裝置變更時更新。

screenschange 事件

現在唯一需要注意的地方,就是能偵測螢幕設定變更的時間。新活動 screenschange,正好達成此目的:每當修改螢幕系列時,就會觸發。(通知 「螢幕」會加上複數形式)。這表示每當有新的畫面或 現有螢幕已接上或未接上電源 (無論是實體或虛擬畫面,就是「邊車」功能)。

請注意,您需要以非同步方式查詢新的畫面詳細資料,也就是 screenschange 事件 並不提供這項資料。如要查詢畫面詳細資料,請使用快取中的使用中物件 Screens 介面。

const screenDetails = await window.getScreenDetails();
let cachedScreensLength = screenDetails.screens.length;
screenDetails.addEventListener('screenschange', (event) => {
  if (screenDetails.screens.length !== cachedScreensLength) {
    console.log(
      `The screen count changed from ${cachedScreensLength} to ${screenDetails.screens.length}`,
    );
    cachedScreensLength = screenDetails.screens.length;
  }
});

currentscreenchange 事件

如果我只想查看目前畫面的變更 (也就是使用中物件的值), currentScreen),我可以監聽 currentscreenchange 事件。

const screenDetails = await window.getScreenDetails();
screenDetails.addEventListener('currentscreenchange', async (event) => {
  const details = screenDetails.currentScreen;
  console.log('The current screen has changed.', event, details);
});

change 事件

最後,如果只想變更具體畫面,可以聆聽該螢幕的 change事件。

const firstScreen = (await window.getScreenDetails())[0];
firstScreen.addEventListener('change', async (event) => {
  console.log('The first screen has changed.', event, firstScreen);
});

新的全螢幕選項

在此之前,您可以透過改寫方法,要求以全螢幕模式顯示元素 requestFullScreen()敬上 方法。此方法使用 options 參數,您可在此傳遞 FullscreenOptions。到目前為止 稱為 navigationUI。 Window Management API 會新增 screen 屬性,方便您判斷 啟動全螢幕檢視的螢幕例如,您想將 全螢幕:

try {
  const primaryScreen = (await getScreenDetails()).screens.filter((screen) => screen.isPrimary)[0];
  await document.body.requestFullscreen({ screen: primaryScreen });
} catch (err) {
  console.error(err.name, err.message);
}

聚合物

您無法在 Window Management API 進行聚合作業,但您可以清理其形狀, 您可以只針對新的 API 編寫程式碼:

if (!('getScreenDetails' in window)) {
  // Returning a one-element array with the current screen,
  // noting that there might be more.
  window.getScreenDetails = async () => [window.screen];
  // Set to `false`, noting that this might be a lie.
  window.screen.isExtended = false;
}

API 的其他方面,也就是各種螢幕變更事件和 screen 屬性 FullscreenOptions 一律不會觸發,也一律不會在通知的情況下個別遭到忽略 不支援的瀏覽器。

示範

如果你喜歡我,務必要密切關注 加密貨幣。(事實上,我超喜歡這顆星球,但 為了方便理解 did.)我開發了一款網頁應用程式,可讓我持續追蹤我擁有的加密貨幣 因為在我的生活中 像是舒適地躺在市場上 只需要設定一個畫面即可

巨大的電視螢幕,睡在床邊,有一隻作者的腿部放下。螢幕上是假的加密貨幣交易平台。
放鬆及觀看市場。

說到加密貨幣,市場中隨時都可能熱烈。如果發生這種情況,我可以 換到我的辦公桌。我可以點選任何貨幣的視窗 然後在另一台螢幕上,以全螢幕檢視畫面快速查看完整細節。以下是最近拍攝的相片 我最後一次看血抓到我 全心守護我,留在我身邊

這位作家將雙手擺在驚訝的臉上,對著假的加密貨幣交易櫃台看著。
阿尼看著 YCY 血流。

您可以播放下方內嵌的示範,也可以在故障時查看該功能的原始碼

安全性和權限

Chrome 團隊根據核心核心指標,設計並實作 Window Management API 控管強大的 Web Platform 功能存取權中定義的原則, 包括使用者控制權、資訊公開以及人因工程學Window Management API 會公開 裝置已連結螢幕的新資訊,讓 特別是那些螢幕持續連結至裝置的人。與一起 為減輕此隱私權疑慮,已揭露的螢幕屬性僅限於 常見刊登位置用途網站需要使用者許可,才能使用多螢幕功能 並在其他畫面上顯示視窗資訊Chromium 會傳回詳細畫面標籤 不必傳回敘述性內容 (甚至是空白標籤)。

使用者控制項

使用者可以完全掌控自身設定的公開程度。他們可以接受或拒絕 權限提示,然後透過 。

企業控管功能

Chrome Enterprise 使用者可以控管 Window Management API 的某些層面,例如 列於 不可部分完成的政策群組 可以管理叢集設定,像是節點 資源調度、安全性和其他預先設定項目

透明度

事實上,是否已經授予使用 Window Management API 的權限, 顯示於瀏覽器網站資訊中,也可以透過 Permissions API 查詢。

權限持續性

瀏覽器保留權限授權。可以透過瀏覽器的網站撤銷權限 可能不準確或不適當

意見回饋

Chrome 團隊想瞭解您使用 Window Management API 的體驗,

請與我們分享 API 設計

您覺得這個 API 有任何不如預期的運作方式嗎?或者缺少某些方法 需要實現什麼構想?對安全性有任何疑問或意見 以及模型

  • 在對應的 GitHub 存放區上提出規格問題,或將您的想法新增至現有的 問題。

回報導入問題

您發現 Chrome 實作錯誤嗎?還是採用與規格不同?

  • 前往 new.crbug.com 回報錯誤。請務必盡量附上詳細資料 可以提供重現重現指示的簡易操作說明,然後在字串欄位輸入 Blink>Screen>MultiScreen 「元件」方塊。Glitch 有便捷的報復工具,

顯示對 API 的支援

您是否打算使用 Window Management API?你的公開支援能協助 Chrome 以便優先開發這些功能,並向其他瀏覽器廠商說明支援這些功能的重要性。

實用連結

特別銘謝

Window Management API 規格已由以下使用者編輯: Victor CostanJoshua BellMike Wasserman。 這個 API 是由 Mike WassermanAdrienne Walker。本文評論者: Joe MedleyFrançois Beaufort、 和 Kayce Basques。感謝 Laura Torrent Puig 拍照。