browser_fullscreen-api-keys.js (9452B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // List of key codes which should exit full-screen mode. 7 const kKeyList = [ 8 { key: "Escape", keyCode: "VK_ESCAPE", suppressed: true }, 9 { key: "F11", keyCode: "VK_F11", suppressed: false }, 10 ]; 11 12 function receiveExpectedKeyEvents(aBrowser, aKeyCode, aTrusted) { 13 return SpecialPowers.spawn( 14 aBrowser, 15 [aKeyCode, aTrusted], 16 (keyCode, trusted) => { 17 return new Promise(resolve => { 18 let events = trusted 19 ? ["keydown", "keyup"] 20 : ["keydown", "keypress", "keyup"]; 21 if (trusted && keyCode == content.wrappedJSObject.KeyEvent.DOM_VK_F11) { 22 // trusted `F11` key shouldn't be fired because of reserved when it's 23 // a shortcut key for exiting from the full screen mode. 24 events.shift(); 25 } 26 function listener(event) { 27 let expected = events.shift(); 28 Assert.equal( 29 event.type, 30 expected, 31 `Should receive a ${expected} event` 32 ); 33 Assert.equal( 34 event.keyCode, 35 keyCode, 36 `Should receive the event with key code ${keyCode}` 37 ); 38 if (!events.length) { 39 content.document.removeEventListener("keydown", listener, true); 40 content.document.removeEventListener("keyup", listener, true); 41 content.document.removeEventListener("keypress", listener, true); 42 resolve(); 43 } 44 } 45 46 content.document.addEventListener("keydown", listener, true); 47 content.document.addEventListener("keyup", listener, true); 48 content.document.addEventListener("keypress", listener, true); 49 }); 50 } 51 ); 52 } 53 54 async function requestFullscreenAndWait(aBrowser) { 55 await SimpleTest.promiseFocus(aBrowser); 56 await SpecialPowers.spawn(aBrowser, [], async () => { 57 // Wait for the document being activated, so that 58 // fullscreen request won't be denied. 59 await ContentTaskUtils.waitForCondition( 60 () => content.browsingContext.isActive && content.document.hasFocus(), 61 "document is active" 62 ); 63 64 await new Promise(resolve => { 65 content.document.addEventListener("fullscreenchange", resolve, { 66 once: true, 67 }); 68 content.document.body.requestFullscreen(); 69 }); 70 }); 71 } 72 73 const kPage = 74 "https://example.org/browser/" + 75 "dom/base/test/fullscreen/file_fullscreen-api-keys.html"; 76 77 add_setup(async function init() { 78 await pushPrefs( 79 ["full-screen-api.transition-duration.enter", "0 0"], 80 ["full-screen-api.transition-duration.leave", "0 0"] 81 ); 82 }); 83 84 for (let { key, keyCode, suppressed } of kKeyList) { 85 /** Test for Bug 545812 */ 86 add_task(async function testExitFullscreenByKeyboard() { 87 let keyCodeValue = KeyEvent["DOM_" + keyCode]; 88 info(`Test keycode ${key} (${keyCodeValue})`); 89 90 let tab = BrowserTestUtils.addTab(gBrowser, kPage); 91 let browser = tab.linkedBrowser; 92 gBrowser.selectedTab = tab; 93 await waitForDocLoadComplete(); 94 95 // Wait for the document being activated, so that 96 // fullscreen request won't be denied. 97 await SimpleTest.promiseFocus(browser); 98 await SpecialPowers.spawn(browser, [], () => { 99 return ContentTaskUtils.waitForCondition( 100 () => content.browsingContext.isActive && content.document.hasFocus(), 101 "document is active" 102 ); 103 }); 104 105 // Register listener to capture unexpected events 106 let keyEventsCount = 0; 107 let fullScreenEventsCount = 0; 108 let removeFullScreenListener = BrowserTestUtils.addContentEventListener( 109 browser, 110 "fullscreenchange", 111 () => fullScreenEventsCount++ 112 ); 113 let removeKeyDownListener = BrowserTestUtils.addContentEventListener( 114 browser, 115 "keydown", 116 () => keyEventsCount++, 117 { wantUntrusted: true } 118 ); 119 let removeKeyPressListener = BrowserTestUtils.addContentEventListener( 120 browser, 121 "keypress", 122 () => keyEventsCount++, 123 { wantUntrusted: true } 124 ); 125 let removeKeyUpListener = BrowserTestUtils.addContentEventListener( 126 browser, 127 "keyup", 128 () => keyEventsCount++, 129 { wantUntrusted: true } 130 ); 131 132 let expectedFullScreenEventsCount = 0; 133 let expectedKeyEventsCount = 0; 134 135 info("Enter fullscreen"); 136 let state = new Promise(resolve => { 137 let removeFun = BrowserTestUtils.addContentEventListener( 138 browser, 139 "fullscreenchange", 140 async () => { 141 removeFun(); 142 resolve( 143 await SpecialPowers.spawn(browser, [], () => { 144 return !!content.document.fullscreenElement; 145 }) 146 ); 147 } 148 ); 149 }); 150 // request fullscreen 151 SpecialPowers.spawn(browser, [], () => { 152 content.document.body.requestFullscreen(); 153 }); 154 ok(await state, "The content should have entered fullscreen"); 155 ok(document.fullscreenElement, "The chrome should also be in fullscreen"); 156 157 is( 158 fullScreenEventsCount, 159 ++expectedFullScreenEventsCount, 160 "correct number of fullscreen events occurred" 161 ); 162 163 info("Dispatch untrusted key events from content"); 164 let promiseExpectedKeyEvents = receiveExpectedKeyEvents( 165 browser, 166 keyCodeValue, 167 false 168 ); 169 170 SpecialPowers.spawn(browser, [keyCode], keyCodeChild => { 171 var evt = new content.CustomEvent("Test:DispatchKeyEvents", { 172 detail: Cu.cloneInto({ code: keyCodeChild }, content), 173 }); 174 content.dispatchEvent(evt); 175 }); 176 await promiseExpectedKeyEvents; 177 178 expectedKeyEventsCount += 3; 179 is( 180 keyEventsCount, 181 expectedKeyEventsCount, 182 "correct number of key events occurred" 183 ); 184 185 info("Send trusted key events"); 186 187 state = new Promise(resolve => { 188 let removeFun = BrowserTestUtils.addContentEventListener( 189 browser, 190 "fullscreenchange", 191 async () => { 192 removeFun(); 193 resolve( 194 await SpecialPowers.spawn(browser, [], () => { 195 return !!content.document.fullscreenElement; 196 }) 197 ); 198 } 199 ); 200 }); 201 202 promiseExpectedKeyEvents = suppressed 203 ? Promise.resolve() 204 : receiveExpectedKeyEvents(browser, keyCodeValue, true); 205 await SpecialPowers.spawn(browser, [], () => {}); 206 207 EventUtils.synthesizeKey("KEY_" + key); 208 await promiseExpectedKeyEvents; 209 210 ok(!(await state), "The content should have exited fullscreen"); 211 ok( 212 !document.fullscreenElement, 213 "The chrome should also have exited fullscreen" 214 ); 215 216 is( 217 fullScreenEventsCount, 218 ++expectedFullScreenEventsCount, 219 "correct number of fullscreen events occurred" 220 ); 221 if (!suppressed) { 222 expectedKeyEventsCount += keyCode == "VK_F11" ? 1 : 3; 223 } 224 is( 225 keyEventsCount, 226 expectedKeyEventsCount, 227 "correct number of key events occurred" 228 ); 229 230 info("Cleanup"); 231 removeFullScreenListener(); 232 removeKeyDownListener(); 233 removeKeyPressListener(); 234 removeKeyUpListener(); 235 gBrowser.removeTab(tab); 236 }); 237 238 /** Test for Bug 1621736 */ 239 // macOS places fullscreen windows in their own virtual desktop, and it is not 240 // possible to programmatically move focus to another chrome window in a different 241 // virtual desktop, so this test doesn't work on macOS. 242 if (AppConstants.platform != "macosx") { 243 add_task(async function testMultipleFullscreenExitByKeyboard() { 244 let keyCodeValue = KeyEvent["DOM_" + keyCode]; 245 info(`Test keycode ${key} (${keyCodeValue})`); 246 247 await BrowserTestUtils.withNewTab( 248 { 249 gBrowser, 250 url: kPage, 251 }, 252 async function (browser) { 253 info("Enter fullscreen"); 254 await requestFullscreenAndWait(browser); 255 256 info("Open new browser window"); 257 const win = await BrowserTestUtils.openNewBrowserWindow(); 258 const tab = await BrowserTestUtils.openNewForegroundTab( 259 win.gBrowser, 260 kPage 261 ); 262 263 info("Enter fullscreen on new browser window"); 264 const newBrowser = tab.linkedBrowser; 265 await requestFullscreenAndWait(newBrowser); 266 267 let removeFullScreenListener; 268 let promiseFullscreenExit = new Promise(resolve => { 269 removeFullScreenListener = BrowserTestUtils.addContentEventListener( 270 newBrowser, 271 "fullscreenchange", 272 resolve, 273 {}, 274 event => { 275 return !event.target.fullscreenElement; 276 } 277 ); 278 }); 279 280 info("Send key event to new browser window"); 281 EventUtils.synthesizeKey("KEY_" + key, {}, win); 282 await promiseFullscreenExit; 283 284 ok( 285 await SpecialPowers.spawn(browser, [], () => { 286 return ( 287 content.document.fullscreenElement == content.document.body 288 ); 289 }), 290 "First browser window should still in fullscreen mode" 291 ); 292 293 info("Cleanup"); 294 removeFullScreenListener(); 295 296 // Close opened tab 297 let tabClosed = BrowserTestUtils.waitForTabClosing(tab); 298 await BrowserTestUtils.removeTab(tab); 299 await tabClosed; 300 301 // Close opened window 302 await BrowserTestUtils.closeWindow(win); 303 } 304 ); 305 }); 306 } 307 }