add key-selector
This commit is contained in:
parent
aca1038700
commit
f6ad2a201e
|
|
@ -38,6 +38,7 @@ dependencies {
|
|||
implementation 'rikka.ndk:riru:10'
|
||||
implementation project(path: ':sandhook-hooklib')
|
||||
compileOnly project(':hiddenapi-stubs')
|
||||
compileOnly project(':key-selector')
|
||||
compileOnly 'androidx.annotation:annotation:1.1.0'
|
||||
}
|
||||
|
||||
|
|
@ -152,6 +153,7 @@ afterEvaluate {
|
|||
def prepareMagiskFilesTask = task("prepareMagiskFiles${variantCapped}", type: Delete) {
|
||||
dependsOn "assemble${variantCapped}"
|
||||
dependsOn tasks.getByPath(":sandhook-hooklib:copySandHook${variantCapped}LibraryToMagiskTemplate")
|
||||
dependsOn tasks.getByPath(":key-selector:copyKeySelector${variantCapped}LibraryToMagiskTemplate")
|
||||
doFirst {
|
||||
copy {
|
||||
from "${projectDir}/tpl/module.prop.tpl"
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
/build
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion androidCompileSdkVersion.toInteger()
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion androidMinSdkVersion.toInteger()
|
||||
targetSdkVersion androidTargetSdkVersion.toInteger()
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
abiFilters 'arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64'
|
||||
cppFlags "-std=c++17"
|
||||
cFlags "-std=gnu99"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-O0"
|
||||
cFlags "-O0"
|
||||
}
|
||||
}
|
||||
}
|
||||
release {
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-fvisibility=hidden -fvisibility-inlines-hidden -O2 -s -Wno-unused-value"
|
||||
cFlags "-fvisibility=hidden -fvisibility-inlines-hidden -O2 -s -Wno-unused-value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
path "src/main/cpp/CMakeLists.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
android.libraryVariants.all { variant ->
|
||||
def variantNameCapped = variant.name.capitalize()
|
||||
def variantNameLowered = variant.name.toLowerCase()
|
||||
|
||||
task("copyKeySelector${variantNameCapped}LibraryToMagiskTemplate") {
|
||||
def libPathRelease = "${buildDir}/intermediates/cmake/${variantNameLowered}/obj"
|
||||
doLast {
|
||||
copy {
|
||||
include "key_selector"
|
||||
from "${libPathRelease}/armeabi-v7a"
|
||||
into "${zipPathMagiskReleasePath}/system/bin"
|
||||
}
|
||||
copy {
|
||||
include "key_selector"
|
||||
from "${libPathRelease}/arm64-v8a"
|
||||
into "${zipPathMagiskReleasePath}/system/bin64"
|
||||
}
|
||||
copy {
|
||||
include "key_selector"
|
||||
from "${libPathRelease}/x86"
|
||||
into "${zipPathMagiskReleasePath}/system_x86/bin"
|
||||
}
|
||||
copy {
|
||||
include "key_selector"
|
||||
from "${libPathRelease}/x86_64"
|
||||
into "${zipPathMagiskReleasePath}/system_x86/bin64"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.elderdrivers.riru.edxp.key_selector">
|
||||
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
project(key_selector)
|
||||
|
||||
add_executable(key_selector key_selector.cpp)
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* Copyright (C) 2015-2016 The CyanogenMod Project
|
||||
* Copyright (C) 2021 LSPosed
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <cstring>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/poll.h>
|
||||
#include <linux/input.h>
|
||||
#include <cerrno>
|
||||
#include <unistd.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "key_selector.h"
|
||||
|
||||
// Global variables
|
||||
static struct pollfd *ufds;
|
||||
static char **device_names;
|
||||
static int nfds;
|
||||
|
||||
static int open_device(const char *device)
|
||||
{
|
||||
int version;
|
||||
int fd;
|
||||
int clkid = CLOCK_MONOTONIC;
|
||||
struct pollfd *new_ufds;
|
||||
char **new_device_names;
|
||||
char name[80];
|
||||
char location[80];
|
||||
char idstr[80];
|
||||
struct input_id id;
|
||||
|
||||
fd = open(device, O_RDWR);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, EVIOCGVERSION, &version)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, EVIOCGID, &id)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
location[sizeof(location) - 1] = '\0';
|
||||
idstr[sizeof(idstr) - 1] = '\0';
|
||||
|
||||
if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
|
||||
name[0] = '\0';
|
||||
}
|
||||
|
||||
if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
|
||||
location[0] = '\0';
|
||||
}
|
||||
|
||||
if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
|
||||
idstr[0] = '\0';
|
||||
}
|
||||
|
||||
if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) {
|
||||
// a non-fatal error
|
||||
}
|
||||
|
||||
new_ufds = static_cast<pollfd *>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
|
||||
if (new_ufds == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ufds = new_ufds;
|
||||
new_device_names = static_cast<char **>(realloc(device_names,
|
||||
sizeof(device_names[0]) * (nfds + 1)));
|
||||
if (new_device_names == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
device_names = new_device_names;
|
||||
|
||||
ufds[nfds].fd = fd;
|
||||
ufds[nfds].events = POLLIN;
|
||||
device_names[nfds] = strdup(device);
|
||||
nfds++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int close_device(const char *device)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < nfds; i++) {
|
||||
if (strcmp(device_names[i], device) == 0) {
|
||||
int count = nfds - i - 1;
|
||||
free(device_names[i]);
|
||||
memmove(device_names + i, device_names + i + 1,
|
||||
sizeof(device_names[0]) * count);
|
||||
memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
|
||||
nfds--;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int read_notify(const char *dirname, int nfd)
|
||||
{
|
||||
int res;
|
||||
char devname[PATH_MAX];
|
||||
char *filename;
|
||||
char event_buf[512];
|
||||
int event_size;
|
||||
int event_pos = 0;
|
||||
struct inotify_event *event;
|
||||
|
||||
res = read(nfd, event_buf, sizeof(event_buf));
|
||||
if (res < (int)sizeof(*event)) {
|
||||
if (errno == EINTR) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
strcpy(devname, dirname);
|
||||
filename = devname + strlen(devname);
|
||||
*filename++ = '/';
|
||||
|
||||
while (res >= (int)sizeof(*event)) {
|
||||
event = (struct inotify_event *)(event_buf + event_pos);
|
||||
if (event->len) {
|
||||
strcpy(filename, event->name);
|
||||
if (event->mask & IN_CREATE) {
|
||||
open_device(devname);
|
||||
} else {
|
||||
close_device(devname);
|
||||
}
|
||||
}
|
||||
event_size = sizeof(*event) + event->len;
|
||||
res -= event_size;
|
||||
event_pos += event_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scan_dir(const char *dirname)
|
||||
{
|
||||
char devname[PATH_MAX];
|
||||
char *filename;
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
|
||||
dir = opendir(dirname);
|
||||
if (dir == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(devname, dirname);
|
||||
filename = devname + strlen(devname);
|
||||
*filename++ = '/';
|
||||
|
||||
while ((de = readdir(dir))) {
|
||||
if (de->d_name[0] == '.' && (de->d_name[1] == '\0' ||
|
||||
(de->d_name[1] == '.' && de->d_name[2] == '\0'))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strcpy(filename, de->d_name);
|
||||
open_device(devname);
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t get_event() {
|
||||
int i;
|
||||
int res;
|
||||
struct input_event event;
|
||||
const char *device_path = "/dev/input";
|
||||
unsigned char keys;
|
||||
|
||||
keys = KEYCHECK_CHECK_VOLUMEDOWN | KEYCHECK_CHECK_VOLUMEUP;
|
||||
nfds = 1;
|
||||
ufds = static_cast<pollfd *>(calloc(1, sizeof(ufds[0])));
|
||||
ufds[0].fd = inotify_init();
|
||||
ufds[0].events = POLLIN;
|
||||
|
||||
res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
|
||||
if (res < 0) {
|
||||
throw std::logic_error("inotify_add_watch failed");
|
||||
}
|
||||
|
||||
res = scan_dir(device_path);
|
||||
if (res < 0) {
|
||||
throw std::logic_error("scan dev failed");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
poll(ufds, nfds, -1);
|
||||
if (ufds[0].revents & POLLIN) {
|
||||
read_notify(device_path, ufds[0].fd);
|
||||
}
|
||||
|
||||
for (i = 1; i < nfds; i++) {
|
||||
if ((ufds[i].revents) && (ufds[i].revents & POLLIN)) {
|
||||
res = read(ufds[i].fd, &event, sizeof(event));
|
||||
if (res < (int)sizeof(event)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// keypress only
|
||||
if (event.value == 1) {
|
||||
if (event.code == KEY_VOLUMEDOWN &&
|
||||
(keys & KEYCHECK_CHECK_VOLUMEDOWN) != 0) {
|
||||
return KEYCHECK_PRESSED_VOLUMEDOWN;
|
||||
}
|
||||
else if (event.code == KEY_VOLUMEUP &&
|
||||
(keys & KEYCHECK_CHECK_VOLUMEUP) != 0) {
|
||||
return KEYCHECK_PRESSED_VOLUMEUP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
if (getuid() != 0) {
|
||||
std::cout << "Root required" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// for phone which has no button
|
||||
const uint16_t timeout = 20;
|
||||
alarm(timeout);
|
||||
auto sig_handler = [](int){
|
||||
std::cout << "No operation after " << timeout << " seconds" << std::endl;
|
||||
exit(YAHFA);
|
||||
};
|
||||
signal(SIGALRM, sig_handler);
|
||||
|
||||
int cursor = YAHFA;
|
||||
const int cursor_max = SandHook;
|
||||
|
||||
auto print_status = [&cursor](){
|
||||
std::cout << "\33[2K\r"; // clear this line
|
||||
std::cout << "[";
|
||||
std::cout << (cursor == YAHFA ? "x" : " ");
|
||||
std::cout << "] YAHFA [";
|
||||
std::cout << (cursor == SandHook ? "x" : " ");
|
||||
std::cout << "] SandHook" << std::flush;
|
||||
};
|
||||
|
||||
std::cout << "Select variant. Use Volume Down to move and Volume Up to confirm." << std::endl;
|
||||
std::cout << "The program will select YAHFA for you in " << timeout << " seconds if you don't have a physical volume button. " << std::endl;
|
||||
print_status();
|
||||
while (int event = get_event()) {
|
||||
bool leave = false;
|
||||
//std::cout << event << " " << cursor << std::endl;
|
||||
switch (event) {
|
||||
case KEYCHECK_PRESSED_VOLUMEUP:
|
||||
leave = true;
|
||||
break;
|
||||
case KEYCHECK_PRESSED_VOLUMEDOWN:
|
||||
cursor++;
|
||||
if (cursor > cursor_max) {
|
||||
cursor = YAHFA;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
std::cout << "ERROR\n";
|
||||
}
|
||||
print_status();
|
||||
if (leave) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// std::cout << std::endl << cursor << std::endl;
|
||||
return cursor;
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2016 The CyanogenMod Project
|
||||
* Copyright (C) 2021 LSPosed
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __KEYCHECK_H__
|
||||
#define __KEYCHECK_H__
|
||||
|
||||
// Constants: pressed keys
|
||||
#define KEYCHECK_CHECK_VOLUMEDOWN 0x01u
|
||||
#define KEYCHECK_CHECK_VOLUMEUP 0x02u
|
||||
#define KEYCHECK_PRESSED_VOLUMEDOWN 41u
|
||||
#define KEYCHECK_PRESSED_VOLUMEUP 42u
|
||||
|
||||
enum Variant {
|
||||
YAHFA = 0x11,
|
||||
SandHook = 0x12,
|
||||
};
|
||||
|
||||
#endif // __KEYCHECK_H__
|
||||
|
|
@ -1 +1 @@
|
|||
include ':edxp-core', ':hiddenapi-stubs', ':sandhook-hooklib', ':sandhook-annotation', ':app'
|
||||
include ':edxp-core', ':hiddenapi-stubs', ':sandhook-hooklib', ':sandhook-annotation', ':app', ':key-selector'
|
||||
|
|
|
|||
Loading…
Reference in New Issue