تتيح واجهة برمجة التطبيقات Screen Capture API للمستخدم اختيار علامة تبويب أو نافذة أو شاشة لتسجيلها كبث وسائط. ويمكن بعد ذلك تسجيل هذا البث أو مشاركته مع مستخدمين آخرين على الشبكة. تعرِض هذه المستندات ميزة "التركيز المشروط"، وهي آلية تتيح لتطبيقات الويب التحكّم في ما إذا كان سيتم التركيز على علامة التبويب أو النافذة التي يتم تسجيلها عند بدء التسجيل، أو ما إذا كان سيتم التركيز على صفحة التسجيل.
دعم المتصفح
تتوفّر ميزة "التركيز المشروط" في الإصدار 109 من Chrome.
الخلفية
عندما يبدأ تطبيق الويب في تسجيل علامة تبويب أو نافذة، يواجه المتصفّح قرارًا: هل يجب عرض المساحة التي تم تسجيلها في المقدّمة، أم يجب أن تظل الصفحة التي يتم التسجيل منها في التركيز؟ تعتمد الإجابة على سبب الاتصال getDisplayMedia()
، وعلى الخيار الذي يختار المستخدم ظاهريًا.
لنفترض أنّ هناك تطبيقًا افتراضيًا على الويب لعقد اجتماعات الفيديو. من خلال قراءة track.getSettings().displaySurface
وربما فحص اسم معرِّف الالتقاط، يمكن لتطبيق الويب لعقد اجتماعات الفيديو فهم ما اختار المستخدم مشاركته. بعد ذلك:
- إذا كان بالإمكان التحكّم عن بُعد في علامة التبويب أو النافذة التي تم التقاطها، عليك التركيز على مؤتمر الفيديو.
- وبخلاف ذلك، ركِّز على علامة التبويب أو النافذة التي تم تسجيلها.
في المثال أعلاه، سيحتفظ تطبيق الويب لمؤتمرات الفيديو بالتركيز في حال مشاركة مجموعة شرائح، ما يسمح للمستخدم بالانتقال من شريحة إلى أخرى عن بُعد، ولكن إذا اختار المستخدم مشاركة محرِّر نص، سينقل تطبيق الويب لمؤتمرات الفيديو التركيز على الفور إلى علامة التبويب أو النافذة التي تم التقاطها.
استخدام واجهة برمجة التطبيقات Conditional Focus API
أنشئ مثيلًا لـ CaptureController
وأرسِله إلى getDisplayMedia()
. من خلال استدعاء setFocusBehavior()
مباشرةً بعد حلّ الوعد الذي تم إرجاعه من getDiplayMedia()
، يمكنك التحكّم في ما إذا كان سيتم التركيز على علامة التبويب أو النافذة التي تمّ التقاطها أم لا. لا يمكن إجراء ذلك إلا إذا شارك المستخدم علامة تبويب أو نافذة.
const controller = new CaptureController();
// Prompt the user to share a tab, a window or a screen.
const stream =
await navigator.mediaDevices.getDisplayMedia({ controller });
const [track] = stream.getVideoTracks();
const displaySurface = track.getSettings().displaySurface;
if (displaySurface == "browser") {
// Focus the captured tab.
controller.setFocusBehavior("focus-captured-surface");
} else if (displaySurface == "window") {
// Do not move focus to the captured window.
// Keep the capturing page focused.
controller.setFocusBehavior("focus-capturing-application");
}
عند اتخاذ قرار بشأن التركيز، يمكنك أخذ اسم معرِّف الالتقاط في الاعتبار.
// Retain focus if capturing a tab dialed to example.com.
// Focus anything else.
const origin = track.getCaptureHandle().origin;
if (displaySurface == "browser" && origin == "https://example.com") {
controller.setFocusBehavior("focus-capturing-application");
} else if (displaySurface != "monitor") {
controller.setFocusBehavior("focus-captured-surface");
}
من الممكن أيضًا تحديد ما إذا كنت تريد التركيز قبل الاتصال getDisplayMedia()
.
// Focus the captured tab or window when capture starts.
const controller = new CaptureController();
controller.setFocusBehavior("focus-captured-surface");
// Prompt the user to share their screen.
const stream =
await navigator.mediaDevices.getDisplayMedia({ controller });
يمكنك استدعاء setFocusBehavior()
عددًا عشوائيًا من المرات قبل أن يتم حلّ الوعد، أو مرة واحدة على الأكثر بعد حلّ الوعد مباشرةً. تلغي عملية الاستدعاء الأخيرة جميع عمليات الاستدعاء السابقة.
بعبارة أدق:
- يتم حلّ الوعد الذي تم إرجاعه من خلال getDisplayMedia()
في مهمة صغيرة. يؤدي استدعاء setFocusBehavior()
بعد اكتمال هذه المهمة الصغيرة إلى ظهور خطأ.
- لن يؤدي الضغط على setFocusBehavior()
بعد مرور أكثر من ثانية على بدء الالتقاط إلى أي إجراء.
وهذا يعني أنّ كلا المقتطفَين التاليَين سيتعذّر تنفيذهما:
// Prompt the user to share their screen.
const stream =
await navigator.mediaDevices.getDisplayMedia({ controller });
// Too late, because it follows the completion of the task
// on which the getDisplayMedia() promise resolved.
// This will throw.
setTimeout(() => {
controller.setFocusBehavior("focus-captured-surface");
});
// Prompt the user to share their screen.
const stream =
await navigator.mediaDevices.getDisplayMedia({ controller });
const start = new Date();
while (new Date() - start <= 1000) {
// Idle for ≈1s.
}
// Because too much time has elapsed, the browser will have
// already decided whether to focus.
// This fails silently.
controller.setFocusBehavior("focus-captured-surface");
يؤدي الاتصال بالرقم setFocusBehavior()
أيضًا إلى ظهور الخطأ في الحالات التالية:
- مقطع الفيديو الخاص بالبث الذي يعرضه
getDisplayMedia()
ليس "مباشرًا". - بعد حلّ الوعد الذي تم إرجاعه من
getDisplayMedia()
، إذا شارك المستخدم شاشة (وليس علامة تبويب أو نافذة).
عيّنة
يمكنك تجربة ميزة "التركيز المشروط" من خلال تشغيل الإصدار التجريبي على Glitch. احرص على الاطّلاع على رمز المصدر.
رصد الميزات
للتحقّق مما إذا كان CaptureController.setFocusBehavior()
متوافقًا، استخدِم:
if (
"CaptureController" in window &&
"setFocusBehavior" in CaptureController.prototype
) {
// CaptureController.setFocusBehavior() is supported.
}
ملاحظات
يريد فريق Chrome ومجتمع معايير الويب معرفة تجاربك مع ميزة "التركيز المشروط".
أخبرنا عن التصميم
هل هناك مشكلة في ميزة "التركيز المشروط" لا تعمل على النحو المتوقّع؟ هل هناك طرق أو سمات غير متوفّرة تحتاج إليها لتنفيذ فكرتك؟ هل لديك سؤال أو تعليق بشأن نموذج الأمان؟
- يمكنك الإبلاغ عن مشكلة في المواصفات على مستودع GitHub، أو إضافة أفكارك إلى مشكلة حالية.
هل هناك مشكلة في التنفيذ؟
هل رصدت خطأ في عملية تنفيذ Chrome؟ أم أنّ عملية التنفيذ مختلفة عن المواصفات؟
- يمكنك إرسال بلاغ عن خلل على الرابط https://new.crbug.com. احرص على تضمين أكبر قدر ممكن من التفاصيل وتعليمات بسيطة لإعادة إنتاج المشكلة. يعمل تطبيق Glitch بشكل جيد لمشاركة الرمز.
إظهار الدعم
هل تخطّط لاستخدام ميزة "التركيز المشروط"؟ يساعد دعمك العلني فريق Chrome في تحديد أولويات الميزات ويُظهر لموفّري المتصفّحات الآخرين مدى أهمية توفير هذه الميزات.
يمكنك إرسال تغريدة إلى @ChromiumDev وإعلامنا بالمكان الذي تستخدم فيه هذه الميزة وطريقة استخدامها.
روابط مفيدة
الشكر والتقدير
الصورة الرئيسية من تصميم إيلينا تارانينكو.
نشكر راشيل أندرو على مراجعة هذه المقالة.