XRInputSourceArray.cpp (5534B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/dom/XRInputSourceArray.h" 8 9 #include "VRDisplayClient.h" 10 #include "mozilla/dom/XRInputSourcesChangeEvent.h" 11 #include "mozilla/dom/XRSession.h" 12 13 namespace mozilla::dom { 14 15 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(XRInputSourceArray, mParent, 16 mInputSources) 17 NS_IMPL_CYCLE_COLLECTING_ADDREF(XRInputSourceArray) 18 NS_IMPL_CYCLE_COLLECTING_RELEASE(XRInputSourceArray) 19 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XRInputSourceArray) 20 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 21 NS_INTERFACE_MAP_ENTRY(nsISupports) 22 NS_INTERFACE_MAP_END 23 24 XRInputSourceArray::XRInputSourceArray(nsISupports* aParent) 25 : mParent(aParent) {} 26 27 JSObject* XRInputSourceArray::WrapObject(JSContext* aCx, 28 JS::Handle<JSObject*> aGivenProto) { 29 return XRInputSourceArray_Binding::Wrap(aCx, this, aGivenProto); 30 } 31 32 void XRInputSourceArray::Update(XRSession* aSession) { 33 MOZ_ASSERT(aSession); 34 35 gfx::VRDisplayClient* displayClient = aSession->GetDisplayClient(); 36 if (!displayClient) { 37 return; 38 } 39 40 XRInputSourcesChangeEventInit addInit; 41 nsTArray<RefPtr<XRInputSource>> removedInputs; 42 if (NS_WARN_IF(!addInit.mAdded.SetCapacity(gfx::kVRControllerMaxCount, 43 mozilla::fallible))) { 44 MOZ_ASSERT(false, 45 "'add' sequence in XRInputSourcesChangeEventInit SetCapacity() " 46 "failed."); 47 return; 48 } 49 50 for (int32_t i = 0; i < gfx::kVRControllerMaxCount; ++i) { 51 const gfx::VRControllerState& controllerState = 52 displayClient->GetDisplayInfo().mControllerState[i]; 53 if (controllerState.controllerName[0] == '\0') { 54 // Checking if exising controllers need to be removed. 55 for (auto& input : mInputSources) { 56 if (input->GetIndex() == i) { 57 removedInputs.AppendElement(input); 58 break; 59 } 60 } 61 continue; 62 } 63 64 bool found = false; 65 RefPtr<XRInputSource> inputSource = nullptr; 66 for (auto& input : mInputSources) { 67 if (input->GetIndex() == i) { 68 found = true; 69 inputSource = input; 70 break; 71 } 72 } 73 // Checking if it is added before. 74 if (!found && 75 (controllerState.numButtons > 0 || controllerState.numAxes > 0)) { 76 inputSource = new XRInputSource(mParent); 77 inputSource->Setup(aSession, i); 78 mInputSources.AppendElement(inputSource); 79 80 addInit.mBubbles = false; 81 addInit.mCancelable = false; 82 addInit.mSession = aSession; 83 if (!addInit.mAdded.AppendElement(*inputSource, mozilla::fallible)) { 84 MOZ_ASSERT(false, 85 "'add' sequence in XRInputSourcesChangeEventInit " 86 "AppendElement() failed, it might be due to the" 87 "wrong size when SetCapacity()."); 88 } 89 } 90 // If added, updating the current controller states. 91 if (inputSource) { 92 inputSource->Update(aSession); 93 } 94 } 95 96 // Send `inputsourceschange` for new controllers. 97 if (addInit.mAdded.Length()) { 98 RefPtr<XRInputSourcesChangeEvent> event = 99 XRInputSourcesChangeEvent::Constructor( 100 aSession, u"inputsourceschange"_ns, addInit); 101 102 event->SetTrusted(true); 103 aSession->DispatchEvent(*event); 104 } 105 106 // If there's a controller is removed, dispatch `inputsourceschange`. 107 if (removedInputs.Length()) { 108 DispatchInputSourceRemovedEvent(removedInputs, aSession); 109 } 110 for (auto& input : removedInputs) { 111 mInputSources.RemoveElement(input); 112 } 113 } 114 115 void XRInputSourceArray::DispatchInputSourceRemovedEvent( 116 const nsTArray<RefPtr<XRInputSource>>& aInputs, XRSession* aSession) { 117 if (!aSession) { 118 return; 119 } 120 121 XRInputSourcesChangeEventInit init; 122 if (NS_WARN_IF( 123 !init.mRemoved.SetCapacity(aInputs.Length(), mozilla::fallible))) { 124 MOZ_ASSERT(false, 125 "'removed' sequence in XRInputSourcesChangeEventInit " 126 "SetCapacity() failed."); 127 return; 128 } 129 for (const auto& input : aInputs) { 130 input->SetGamepadIsConnected(false, aSession); 131 init.mBubbles = false; 132 init.mCancelable = false; 133 init.mSession = aSession; 134 if (!init.mRemoved.AppendElement(*input, mozilla::fallible)) { 135 MOZ_ASSERT(false, 136 "'removed' sequence in XRInputSourcesChangeEventInit " 137 "AppendElement() failed, it might be due to the" 138 "wrong size when SetCapacity()."); 139 } 140 } 141 142 if (init.mRemoved.Length()) { 143 RefPtr<XRInputSourcesChangeEvent> event = 144 XRInputSourcesChangeEvent::Constructor(aSession, 145 u"inputsourceschange"_ns, init); 146 147 event->SetTrusted(true); 148 aSession->DispatchEvent(*event); 149 } 150 } 151 152 void XRInputSourceArray::Clear(XRSession* aSession) { 153 DispatchInputSourceRemovedEvent(mInputSources, aSession); 154 mInputSources.Clear(); 155 } 156 157 uint32_t XRInputSourceArray::Length() { return mInputSources.Length(); } 158 159 XRInputSource* XRInputSourceArray::IndexedGetter(uint32_t aIndex, 160 bool& aFound) { 161 aFound = aIndex < mInputSources.Length(); 162 if (!aFound) { 163 return nullptr; 164 } 165 return mInputSources[aIndex]; 166 } 167 168 } // namespace mozilla::dom