events_input_source_recreation.https.html (5426B)
1 <!DOCTYPE html> 2 <script src="/resources/testharness.js"></script> 3 <script src="/resources/testharnessreport.js"></script> 4 <script src="resources/webxr_util.js"></script> 5 <script src="resources/webxr_test_constants.js"></script> 6 7 <script> 8 let testName = "Input sources are re-created when handedness or target ray mode changes"; 9 10 let watcherDone = new Event("watcherdone"); 11 12 let fakeDeviceInitParams = TRACKED_IMMERSIVE_DEVICE; 13 14 let testFunction = function(session, fakeDeviceController, t) { 15 let eventWatcher = new EventWatcher(t, session, ["watcherdone"]); 16 let eventPromise = eventWatcher.wait_for(["watcherdone"]); 17 18 let inputChangeEvents = 0; 19 let cached_input_source = null; 20 function onInputSourcesChange(event) { 21 t.step(() => { 22 inputChangeEvents++; 23 assert_equals(event.session, session); 24 25 if (inputChangeEvents == 1) { 26 // The first change event should be adding our controller. 27 validateAdded(event.added, 1); 28 validateRemoved(event.removed, 0); 29 cached_input_source = getInputSources()[0]; 30 assert_not_equals(cached_input_source, null); 31 assert_equals(cached_input_source.handedness, "none"); 32 assert_equals(cached_input_source.targetRayMode, "gaze"); 33 assertProfilesEqual(cached_input_source.profiles, ["a", "b"]); 34 } else if (inputChangeEvents == 2) { 35 // The second event should be replacing the controller with one that has 36 // the updated target ray mode. 37 validateInputSourceChange(event, "none", "tracked-pointer", ["a", "b"]); 38 cached_input_source = getInputSources()[0]; 39 } else if (inputChangeEvents == 3) { 40 // The third event should be replacing the controller with one that has 41 // the updated handedness. 42 validateInputSourceChange(event, "left", "tracked-pointer", ["a", "b"]); 43 cached_input_source = getInputSources()[0]; 44 } else if (inputChangeEvents == 4) { 45 // The fourth event should be updating the second value in the profiles 46 // array. 47 validateInputSourceChange(event, "left", "tracked-pointer", ["a", "c"]); 48 cached_input_source = getInputSources()[0]; 49 } else if (inputChangeEvents == 5) { 50 // The fifth event should be removing the second value from the profiles 51 // array. 52 validateInputSourceChange(event, "left", "tracked-pointer", ["a"]); 53 session.dispatchEvent(watcherDone); 54 } 55 }); 56 } 57 58 function assertProfilesEqual(profiles, expected_profiles) { 59 assert_equals(profiles.length, expected_profiles.length); 60 for (let i = 0; i < profiles.length; ++i) { 61 assert_equals(profiles[i], expected_profiles[i]); 62 } 63 } 64 65 function validateInputSourceChange( 66 event, expected_hand, expected_mode, expected_profiles) { 67 validateAdded(event.added, 1); 68 validateRemoved(event.removed, 1); 69 assert_true(event.removed.includes(cached_input_source)); 70 assert_false(event.added.includes(cached_input_source)); 71 let source = event.added[0]; 72 assert_equals(source.handedness, expected_hand); 73 assert_equals(source.targetRayMode, expected_mode); 74 assertProfilesEqual(source.profiles, expected_profiles); 75 } 76 77 function validateAdded(added, length) { 78 t.step(() => { 79 assert_not_equals(added, null); 80 assert_equals(added.length, length, 81 "Added length matches expectations"); 82 83 let currentSources = getInputSources(); 84 added.forEach((source) => { 85 assert_true(currentSources.includes(source), 86 "Every element in added should be in the input source list"); 87 }); 88 }); 89 } 90 91 function validateRemoved(removed, length) { 92 t.step(() => { 93 assert_not_equals(removed, null); 94 assert_equals(removed.length, length, 95 "Removed length matches expectations"); 96 97 let currentSources = getInputSources(); 98 removed.forEach((source) => { 99 assert_false(currentSources.includes(source), 100 "No element in removed should be in the input source list"); 101 }); 102 }); 103 } 104 105 function getInputSources() { 106 return Array.from(session.inputSources.values()); 107 } 108 109 session.addEventListener('inputsourceschange', onInputSourcesChange, false); 110 111 // Create a gaze based input source with no handedness that we can change 112 // to validate SameObject properties. 113 let input_source = fakeDeviceController.simulateInputSourceConnection({ 114 handedness: "none", 115 targetRayMode: "gaze", 116 pointerOrigin: VALID_POINTER_TRANSFORM, 117 profiles: ["a", "b"] 118 }); 119 120 // Make our first input source change after one frame, and wait an additional 121 // frame for that change to propogate. Then make additional changes, waiting 122 // one frame after each one to verify that they fired an inputsourceschanged 123 // event. 124 session.requestAnimationFrame((time, xrFrame) => { 125 input_source.setTargetRayMode("tracked-pointer"); 126 session.requestAnimationFrame((time, xrFrame) => { 127 input_source.setHandedness("left"); 128 session.requestAnimationFrame((time, xrFrame) => { 129 input_source.setProfiles(["a", "c"]); 130 session.requestAnimationFrame((time, xrFrame) => { 131 input_source.setProfiles(["a"]); 132 session.requestAnimationFrame((time, xrFrame) => {}); 133 }); 134 }); 135 }); 136 }); 137 138 return eventPromise; 139 }; 140 141 xr_session_promise_test( 142 testName, testFunction, fakeDeviceInitParams, 'immersive-vr'); 143 </script>