diff options
author | 2023-11-03 17:21:25 +0000 | |
---|---|---|
committer | 2023-11-15 10:33:49 +0000 | |
commit | 5766aee030d135875317d742f9c23039a7e382a3 (patch) | |
tree | 3bc5d3eb0d32200b005f75a0896f9a1ff3b27ce8 | |
parent | e560468ef239064832690d1b617034f7721ad891 (diff) |
Add InputFilter rust component as InputListener stage.
Test: TEST=libinputflinger_rs_test; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST
Bug: 294546335
Change-Id: I2731d45f141c12c1e61b794ee614690b0a121e28
-rw-r--r-- | libs/input/input_flags.aconfig | 7 | ||||
-rw-r--r-- | services/inputflinger/Android.bp | 1 | ||||
-rw-r--r-- | services/inputflinger/InputFilter.cpp | 129 | ||||
-rw-r--r-- | services/inputflinger/InputFilter.h | 64 | ||||
-rw-r--r-- | services/inputflinger/InputManager.cpp | 8 | ||||
-rw-r--r-- | services/inputflinger/InputManager.h | 4 | ||||
-rw-r--r-- | services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl | 45 | ||||
-rw-r--r-- | services/inputflinger/aidl/com/android/server/inputflinger/IInputFlingerRust.aidl | 6 | ||||
-rw-r--r-- | services/inputflinger/aidl/com/android/server/inputflinger/KeyEvent.aidl | 37 | ||||
-rw-r--r-- | services/inputflinger/rust/Android.bp | 22 | ||||
-rw-r--r-- | services/inputflinger/rust/input_filter.rs | 122 | ||||
-rw-r--r-- | services/inputflinger/rust/lib.rs | 32 |
12 files changed, 468 insertions, 9 deletions
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index 3672387119..a807d823f1 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -62,3 +62,10 @@ flag { description: "Disable touch rejection when the stylus hovers the screen" bug: "301216095" } + +flag { + name: "enable_input_filter_rust_impl" + namespace: "input" + description: "Enable input filter rust implementation" + bug: "294546335" +} diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 76729efb0a..10f386e0fd 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -76,6 +76,7 @@ filegroup { srcs: [ "InputCommonConverter.cpp", "InputDeviceMetricsCollector.cpp", + "InputFilter.cpp", "InputProcessor.cpp", "PointerChoreographer.cpp", "PreferStylusOverTouchBlocker.cpp", diff --git a/services/inputflinger/InputFilter.cpp b/services/inputflinger/InputFilter.cpp new file mode 100644 index 0000000000..1b8fad3c65 --- /dev/null +++ b/services/inputflinger/InputFilter.cpp @@ -0,0 +1,129 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "InputFilter" + +#include "InputFilter.h" + +namespace android { + +using aidl::com::android::server::inputflinger::IInputFilter; +using AidlKeyEvent = aidl::com::android::server::inputflinger::KeyEvent; + +AidlKeyEvent notifyKeyArgsToKeyEvent(const NotifyKeyArgs& args) { + AidlKeyEvent event; + event.id = args.id; + event.eventTime = args.eventTime; + event.deviceId = args.deviceId; + event.source = args.source; + event.displayId = args.displayId; + event.policyFlags = args.policyFlags; + event.action = args.action; + event.flags = args.flags; + event.keyCode = args.keyCode; + event.scanCode = args.scanCode; + event.metaState = args.metaState; + event.downTime = args.downTime; + event.readTime = args.readTime; + return event; +} + +NotifyKeyArgs keyEventToNotifyKeyArgs(const AidlKeyEvent& event) { + return NotifyKeyArgs(event.id, event.eventTime, event.readTime, event.deviceId, event.source, + event.displayId, event.policyFlags, event.action, event.flags, + event.keyCode, event.scanCode, event.metaState, event.downTime); +} + +namespace { + +class RustCallbacks : public IInputFilter::BnInputFilterCallbacks { +public: + RustCallbacks(InputListenerInterface& nextListener) : mNextListener(nextListener) {} + ndk::ScopedAStatus sendKeyEvent(const AidlKeyEvent& event) override { + mNextListener.notifyKey(keyEventToNotifyKeyArgs(event)); + return ndk::ScopedAStatus::ok(); + } + +private: + InputListenerInterface& mNextListener; +}; + +} // namespace + +InputFilter::InputFilter(InputListenerInterface& listener, IInputFlingerRust& rust) + : mNextListener(listener), mCallbacks(ndk::SharedRefBase::make<RustCallbacks>(listener)) { + LOG_ALWAYS_FATAL_IF(!rust.createInputFilter(mCallbacks, &mInputFilterRust).isOk()); + LOG_ALWAYS_FATAL_IF(!mInputFilterRust); +} + +void InputFilter::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) { + if (isFilterEnabled()) { + std::vector<int32_t> deviceIds; + for (auto info : args.inputDeviceInfos) { + deviceIds.push_back(info.getId()); + } + LOG_ALWAYS_FATAL_IF(!mInputFilterRust->notifyInputDevicesChanged(deviceIds).isOk()); + } + mNextListener.notify(args); +} + +void InputFilter::notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) { + mNextListener.notify(args); +} + +void InputFilter::notifyKey(const NotifyKeyArgs& args) { + if (!isFilterEnabled()) { + mNextListener.notifyKey(args); + return; + } + LOG_ALWAYS_FATAL_IF(!mInputFilterRust->notifyKey(notifyKeyArgsToKeyEvent(args)).isOk()); +} + +void InputFilter::notifyMotion(const NotifyMotionArgs& args) { + mNextListener.notify(args); +} + +void InputFilter::notifySwitch(const NotifySwitchArgs& args) { + mNextListener.notify(args); +} + +void InputFilter::notifySensor(const NotifySensorArgs& args) { + mNextListener.notify(args); +} + +void InputFilter::notifyVibratorState(const NotifyVibratorStateArgs& args) { + mNextListener.notify(args); +} + +void InputFilter::notifyDeviceReset(const NotifyDeviceResetArgs& args) { + mNextListener.notify(args); +} + +void InputFilter::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) { + mNextListener.notify(args); +} + +bool InputFilter::isFilterEnabled() { + bool result; + LOG_ALWAYS_FATAL_IF(!mInputFilterRust->isEnabled(&result).isOk()); + return result; +} + +void InputFilter::dump(std::string& dump) { + dump += "InputFilter:\n"; +} + +} // namespace android diff --git a/services/inputflinger/InputFilter.h b/services/inputflinger/InputFilter.h new file mode 100644 index 0000000000..699f3a0151 --- /dev/null +++ b/services/inputflinger/InputFilter.h @@ -0,0 +1,64 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <aidl/com/android/server/inputflinger/IInputFlingerRust.h> +#include "InputListener.h" +#include "NotifyArgs.h" + +namespace android { + +/** + * The C++ component of InputFilter designed as a wrapper around the rust implementation. + */ +class InputFilterInterface : public InputListenerInterface { +public: + /** + * This method may be called on any thread (usually by the input manager on a binder thread). + */ + virtual void dump(std::string& dump) = 0; +}; + +class InputFilter : public InputFilterInterface { +public: + using IInputFlingerRust = aidl::com::android::server::inputflinger::IInputFlingerRust; + using IInputFilter = aidl::com::android::server::inputflinger::IInputFilter; + using IInputFilterCallbacks = + aidl::com::android::server::inputflinger::IInputFilter::IInputFilterCallbacks; + + explicit InputFilter(InputListenerInterface& listener, IInputFlingerRust&); + ~InputFilter() override = default; + void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; + void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override; + void notifyKey(const NotifyKeyArgs& args) override; + void notifyMotion(const NotifyMotionArgs& args) override; + void notifySwitch(const NotifySwitchArgs& args) override; + void notifySensor(const NotifySensorArgs& args) override; + void notifyVibratorState(const NotifyVibratorStateArgs& args) override; + void notifyDeviceReset(const NotifyDeviceResetArgs& args) override; + void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override; + void dump(std::string& dump) override; + +private: + InputListenerInterface& mNextListener; + std::shared_ptr<IInputFilterCallbacks> mCallbacks; + std::shared_ptr<IInputFilter> mInputFilterRust; + + bool isFilterEnabled(); +}; + +} // namespace android diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp index 92c65e19b6..8cf61f9064 100644 --- a/services/inputflinger/InputManager.cpp +++ b/services/inputflinger/InputManager.cpp @@ -42,6 +42,7 @@ const bool ENABLE_INPUT_DEVICE_USAGE_METRICS = sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true); const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer(); +const bool ENABLE_INPUT_FILTER_RUST = input_flags::enable_input_filter_rust_impl(); int32_t exceptionCodeFromStatusT(status_t status) { switch (status) { @@ -118,6 +119,7 @@ std::shared_ptr<IInputFlingerRust> createInputFlingerRust() { * The event flow is via the "InputListener" interface, as follows: * InputReader * -> UnwantedInteractionBlocker + * -> InputFilter * -> PointerChoreographer * -> InputProcessor * -> InputDeviceMetricsCollector @@ -132,6 +134,12 @@ InputManager::InputManager(const sp<InputReaderPolicyInterface>& readerPolicy, mTracingStages.emplace_back( std::make_unique<TracedInputListener>("InputDispatcher", *mDispatcher)); + if (ENABLE_INPUT_FILTER_RUST) { + mInputFilter = std::make_unique<InputFilter>(*mTracingStages.back(), *mInputFlingerRust); + mTracingStages.emplace_back( + std::make_unique<TracedInputListener>("InputFilter", *mInputFilter)); + } + if (ENABLE_INPUT_DEVICE_USAGE_METRICS) { mCollector = std::make_unique<InputDeviceMetricsCollector>(*mTracingStages.back()); mTracingStages.emplace_back( diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h index 20b9fd50df..aea7bd56ae 100644 --- a/services/inputflinger/InputManager.h +++ b/services/inputflinger/InputManager.h @@ -21,6 +21,7 @@ */ #include "InputDeviceMetricsCollector.h" +#include "InputFilter.h" #include "InputProcessor.h" #include "InputReaderBase.h" #include "PointerChoreographer.h" @@ -40,6 +41,7 @@ using android::os::BnInputFlinger; +using aidl::com::android::server::inputflinger::IInputFilter; using aidl::com::android::server::inputflinger::IInputFlingerRust; namespace android { @@ -137,6 +139,8 @@ private: std::unique_ptr<UnwantedInteractionBlockerInterface> mBlocker; + std::unique_ptr<InputFilterInterface> mInputFilter; + std::unique_ptr<PointerChoreographerInterface> mChoreographer; std::unique_ptr<InputProcessorInterface> mProcessor; diff --git a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl new file mode 100644 index 0000000000..44f959ef63 --- /dev/null +++ b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFilter.aidl @@ -0,0 +1,45 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.inputflinger; + +import com.android.server.inputflinger.KeyEvent; + +/** + * A local AIDL interface used as a foreign function interface (ffi) to + * filter input events. + * + * NOTE: Since we use this as a local interface, all processing happens on the + * calling thread. + */ +interface IInputFilter { + + /** Callbacks for the rust InputFilter to call into C++. */ + interface IInputFilterCallbacks { + /** Sends back a filtered key event */ + void sendKeyEvent(in KeyEvent event); + } + + /** Returns if InputFilter is enabled */ + boolean isEnabled(); + + /** Notifies if a key event occurred */ + void notifyKey(in KeyEvent event); + + /** Notifies if any InputDevice list changed and provides the list of connected peripherals */ + void notifyInputDevicesChanged(in int[] deviceIds); +} + diff --git a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFlingerRust.aidl b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFlingerRust.aidl index 8e826fda44..de852c0c24 100644 --- a/services/inputflinger/aidl/com/android/server/inputflinger/IInputFlingerRust.aidl +++ b/services/inputflinger/aidl/com/android/server/inputflinger/IInputFlingerRust.aidl @@ -16,6 +16,9 @@ package com.android.server.inputflinger; +import com.android.server.inputflinger.IInputFilter; +import com.android.server.inputflinger.IInputFilter.IInputFilterCallbacks; + /** * A local AIDL interface used as a foreign function interface (ffi) to * communicate with the Rust component of inputflinger. @@ -31,4 +34,7 @@ interface IInputFlingerRust { interface IInputFlingerRustBootstrapCallback { void onProvideInputFlingerRust(in IInputFlingerRust inputFlingerRust); } + + /** Create the rust implementation of InputFilter. */ + IInputFilter createInputFilter(IInputFilterCallbacks callbacks); } diff --git a/services/inputflinger/aidl/com/android/server/inputflinger/KeyEvent.aidl b/services/inputflinger/aidl/com/android/server/inputflinger/KeyEvent.aidl new file mode 100644 index 0000000000..e213221d44 --- /dev/null +++ b/services/inputflinger/aidl/com/android/server/inputflinger/KeyEvent.aidl @@ -0,0 +1,37 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.inputflinger; + +/** + * Analogous to Android's native KeyEvent / NotifyKeyArgs. + * Stores the basic information about Key events. + */ +parcelable KeyEvent { + int id; + int deviceId; + long downTime; + long readTime; + long eventTime; + int source; + int displayId; + int policyFlags; + int action; + int flags; + int keyCode; + int scanCode; + int metaState; +}
\ No newline at end of file diff --git a/services/inputflinger/rust/Android.bp b/services/inputflinger/rust/Android.bp index 23c1691b28..2775bcc962 100644 --- a/services/inputflinger/rust/Android.bp +++ b/services/inputflinger/rust/Android.bp @@ -31,8 +31,8 @@ genrule { out: ["inputflinger_bootstrap.rs.h"], } -rust_ffi_static { - name: "libinputflinger_rs", +rust_defaults { + name: "libinputflinger_rs_defaults", crate_name: "inputflinger", srcs: ["lib.rs"], rustlibs: [ @@ -45,6 +45,24 @@ rust_ffi_static { host_supported: true, } +rust_ffi_static { + name: "libinputflinger_rs", + defaults: ["libinputflinger_rs_defaults"], +} + +rust_test { + name: "libinputflinger_rs_test", + defaults: ["libinputflinger_rs_defaults"], + test_options: { + unit_test: true, + }, + test_suites: ["device_tests"], + sanitize: { + address: true, + hwaddress: true, + }, +} + cc_library_headers { name: "inputflinger_rs_bootstrap_cxx_headers", host_supported: true, diff --git a/services/inputflinger/rust/input_filter.rs b/services/inputflinger/rust/input_filter.rs new file mode 100644 index 0000000000..585187750b --- /dev/null +++ b/services/inputflinger/rust/input_filter.rs @@ -0,0 +1,122 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//! InputFilter manages all the filtering components that can intercept events, modify the events, +//! block events, etc depending on the situation. This will be used support Accessibility features +//! like Slow keys, Bounce keys, etc. + +use binder::{Interface, Strong}; +use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{ + IInputFilter::{IInputFilter, IInputFilterCallbacks::IInputFilterCallbacks}, + KeyEvent::KeyEvent, +}; + +/// The rust implementation of InputFilter +pub struct InputFilter { + callbacks: Strong<dyn IInputFilterCallbacks>, +} + +impl Interface for InputFilter {} + +impl InputFilter { + /// Create a new InputFilter instance. + pub fn new(callbacks: Strong<dyn IInputFilterCallbacks>) -> InputFilter { + Self { callbacks } + } +} + +impl IInputFilter for InputFilter { + fn isEnabled(&self) -> binder::Result<bool> { + // TODO(b/294546335): Return true if any filters are to be applied, false otherwise + Result::Ok(false) + } + fn notifyKey(&self, event: &KeyEvent) -> binder::Result<()> { + // TODO(b/294546335): Handle key event and modify key events here + // Just send back the event without processing for now. + let _ = self.callbacks.sendKeyEvent(event); + Result::Ok(()) + } + fn notifyInputDevicesChanged(&self, _device_ids: &[i32]) -> binder::Result<()> { + // TODO(b/294546335): Update data based on device changes here + Result::Ok(()) + } +} + +#[cfg(test)] +mod tests { + use crate::input_filter::InputFilter; + use binder::{Interface, Strong}; + use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{ + IInputFilter::IInputFilter, IInputFilter::IInputFilterCallbacks::IInputFilterCallbacks, + KeyEvent::KeyEvent, + }; + + struct FakeCallbacks {} + + impl Interface for FakeCallbacks {} + + impl IInputFilterCallbacks for FakeCallbacks { + fn sendKeyEvent(&self, _event: &KeyEvent) -> binder::Result<()> { + Result::Ok(()) + } + } + + #[test] + fn test_is_enabled() { + let fake_callbacks: Strong<dyn IInputFilterCallbacks> = + Strong::new(Box::new(FakeCallbacks {})); + let filter: Box<dyn IInputFilter> = Box::new(InputFilter::new(fake_callbacks)); + let result = filter.isEnabled(); + assert!(result.is_ok()); + assert!(!result.unwrap()); + } + + #[test] + fn test_notify_key() { + let fake_callbacks: Strong<dyn IInputFilterCallbacks> = + Strong::new(Box::new(FakeCallbacks {})); + let filter: Box<dyn IInputFilter> = Box::new(InputFilter::new(fake_callbacks)); + let event = create_key_event(); + assert!(filter.notifyKey(&event).is_ok()); + } + + #[test] + fn test_notify_devices_changed() { + let fake_callbacks: Strong<dyn IInputFilterCallbacks> = + Strong::new(Box::new(FakeCallbacks {})); + let filter: Box<dyn IInputFilter> = Box::new(InputFilter::new(fake_callbacks)); + let result = filter.notifyInputDevicesChanged(&[0]); + assert!(result.is_ok()); + } + + fn create_key_event() -> KeyEvent { + KeyEvent { + id: 1, + deviceId: 1, + downTime: 0, + readTime: 0, + eventTime: 0, + source: 0, + displayId: 0, + policyFlags: 0, + action: 0, + flags: 0, + keyCode: 0, + scanCode: 0, + metaState: 0, + } + } +} diff --git a/services/inputflinger/rust/lib.rs b/services/inputflinger/rust/lib.rs index 501e4359cd..a4049d52d1 100644 --- a/services/inputflinger/rust/lib.rs +++ b/services/inputflinger/rust/lib.rs @@ -19,13 +19,19 @@ //! We use cxxbridge to create IInputFlingerRust - the Rust component of inputflinger - and //! pass it back to C++ as a local AIDL interface. +mod input_filter; + +use crate::input_filter::InputFilter; use binder::{ - unstable_api::{AIBinder, new_spibinder,}, + unstable_api::{new_spibinder, AIBinder}, BinderFeatures, Interface, StatusCode, Strong, }; -use com_android_server_inputflinger::aidl::com::android::server::inputflinger::IInputFlingerRust::{ - BnInputFlingerRust, IInputFlingerRust, - IInputFlingerRustBootstrapCallback::IInputFlingerRustBootstrapCallback, +use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{ + IInputFilter::{BnInputFilter, IInputFilter, IInputFilterCallbacks::IInputFilterCallbacks}, + IInputFlingerRust::{ + BnInputFlingerRust, IInputFlingerRust, + IInputFlingerRustBootstrapCallback::IInputFlingerRustBootstrapCallback, + }, }; use log::debug; @@ -71,8 +77,8 @@ unsafe fn create_inputflinger_rust(callback: *mut ffi::IInputFlingerRustBootstra // SAFETY: Our caller guaranteed that `callback` is a valid pointer to an `AIBinder` and its // reference count has been incremented.. let Some(callback) = (unsafe { new_spibinder(callback) }) else { - panic!("Failed to get SpAIBinder from raw callback pointer"); - }; + panic!("Failed to get SpAIBinder from raw callback pointer"); + }; let callback: Result<Strong<dyn IInputFlingerRustBootstrapCallback>, StatusCode> = callback.into_interface(); @@ -93,7 +99,19 @@ struct InputFlingerRust {} impl Interface for InputFlingerRust {} -impl IInputFlingerRust for InputFlingerRust {} +impl IInputFlingerRust for InputFlingerRust { + fn createInputFilter( + &self, + callbacks: &Strong<dyn IInputFilterCallbacks>, + ) -> binder::Result<Strong<dyn IInputFilter>> { + debug!("Creating InputFilter"); + let filter = BnInputFilter::new_binder( + InputFilter::new(callbacks.clone()), + BinderFeatures::default(), + ); + Result::Ok(filter) + } +} impl Drop for InputFlingerRust { fn drop(&mut self) { |