-
-
Notifications
You must be signed in to change notification settings - Fork 226
Description
The current screen off implementation relies on parsing the getevent command output, which is a bit buggy and the process seems to sometimes be stopped by the system. Perhaps a better way would be to write native code to interface with evdev directly. If one can find a way to consume the events then this could be used when the screen is on as well - perhaps remap mouse buttons, the power button??
- update documentation
- Find a way to consume the key events.
- The service should be in a package that will never change long term. Put it in
.api? - Find a way to map linux key codes to the Android equivalent.
- Does this work for mouse buttons?
-
Write in Rust? https://gendignoux.com/blog/2022/10/24/rust-library-android.html#optimizing-the-rust-library-size-dividing-the-apk-size-by-3 - Credit Shizuku for the ADB code, and launching user services. Move it to a separate module.
- Automate building the event-names.h file from the NDK installation.
-
Figure out a way to turn on wireless debugging without connecting to a wifi network.Seems to not be allowed. - Use a different file name to Shizuku for the starter script. "keymapper_shizuku_starter"?
- As described in the Shizuku "user service" docs, one must provide a tag because R8 obfuscates class names which can lead to duplicate services running. https://github.com/RikkaApps/Shizuku-API?tab=readme-ov-file#userservice
- Follow the instructions for stopping a user service. https://github.com/RikkaApps/Shizuku-API?tab=readme-ov-file#userservice
- Replace all uses of "Shizuku" text in the code.
- Delete shizuku strings
-
Detection when screen off is an opt in feature and use the existing checkbox. - Key Mapper should recognize unknown linux key codes that aren't mapped to Android.
- Add Key Mapper and the ADB Shell userid to the power save whitelist https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl. See DeviceIdleControllerApis in Shizuku.
- Test that R8 obfuscation works in all modules.
- Show icon in the trigger key when a key can only be detected with PRO mode. Similar to the IME remapping.
- Tips for what to do if not connected to wifi. Connect to a friend’s hotspot.
- When advertising mention that another advantage is not needing to use the Key Mapper keyboard.
- If trying to remap a controller button, point them towards gaming mode.
-
Tell the user they must not disable usb_debugging because turning off adb kills all processes with the shell user id.Solved by always turning on USB debugging with WRITE_SECURE_SETTINGS. - Disable all logging in native Android input code.
- PRO Mode requires API 29 or higher due to NDK binder not existing. API 31+ required for wifi debugging.
-
Use kernel level process killing prevention techniques. look at oom_score_adj.This requires root so don't bother for now - not many users would benefit. -
Show a warning when you remap a button that is potentially a touchscreen.Just filter out these events. - Turn on USB debugging, ADB authorization timeout, and
disable child process restrictionsin developer options once connected. Not sure child process restrictions solves the problem. - Advertise that buttons can be detected when the screen is off. "Only app in the play store can do this"
- Automatically set trigger as long press when adding a power button
Different ways to bind to the priv service
- Expose a Binder in a content provider, like Shizuku. ✅
- Pass a Binder when starting up the service. ❌ The priv service must be long running and not stop when key mapper crashes. Otherwise the user has to enable wifi debugging again etc.
- The priv service binds to a Key Mapper service. ❌ Same reason as above.
Dangerous scenarios to test
- Test if holding down remapped power button still shuts down
- Do not allow other apps to bind to the evdev service. Can be solved with signature permissions and checking them before binding.
- Have an emergency way to kill the server process. Long press power for 30 seconds?
- Restart the server with new code when the app updates. Check if version code on server is different.
- Test killing evdev service process while the power button is grabbed, and also the screen is off. Does the power button work again and can turn the screen on?
- Can Key Mapper turn screen on/off when you short press the power button and it is also remapped to a long press?
Auto start flow
- Rooted -> Start the service ourself manually
- Rooted & Shizuku granted -> Use root.
- Not rooted & Shizuku granted -> Use shizuku.
- Not rooted & Shizuku denied -> Use manual.
Useful resources
- https://users.softlab.ntua.gr/~thkala/projects/evmapd/evmapd.html
- https://cs.android.com/android/platform/superproject/main/+/main:system/core/toolbox/getevent.c
- https://github.com/timschneeb/awesome-shizuku?tab=readme-ov-file#input-methods
- https://newandroidbook.com/Book/Input.html?r
- https://cs.android.com/android/platform/superproject/main/+/main:external/toybox/toys/android/sendevent.c
- https://www.programmersought.com/article/88397797812/
- https://source.android.com/docs/core/interaction/input/keyboard-devices
- Guide for how evdev works: https://www.baeldung.com/linux/mouse-events-input-event-interface
Mapping linux EV_KEY event labels to key codes https://cs.android.com/android/platform/superproject/main/+/main:frameworks/native/libs/input/InputEventLabels.cpp. KeyCharacterMap code can also be used i think somehow.
https://github.com/android-generic/external_evtest Consuming any input event works with the --grab flag on oneplus 6t Android 11, and Pixel 7 Android 15.
Using this program I can remap https://github.com/KarsMulder/evsieve
Opening Device Info settings screen and highlighting Build Number. The fragment_arg_key can be found in the xml file for the preference screen in AOSP Settings source code.
Intent(Settings.ACTION_DEVICE_INFO_SETTINGS).apply {
val EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key"
val EXTRA_SHOW_FRAGMENT_ARGUMENTS = ":settings:show_fragment_args"
putExtra(EXTRA_FRAGMENT_ARG_KEY, "build_number")
val bundle = bundleOf(EXTRA_FRAGMENT_ARG_KEY to "build_number")
putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle)
startActivity(this)
}