Overwrite button behaviour

Which version of system do you use? Khadas official images, self built images, or others?

Official ubuntu image

Please describe your issue below:

I was wondering if it is possible to overwrite the behaviour of a button that is soldered to the XPWR pads? We would like to for example integrate a long vs short press option.

Hello @brunobiped

So you want to overwrite the behaviour of POWER button, right ?

You can try the stpes below:

Disable default POWER button function.

$ sudo systemctl stop systemd-logind.service

Then you can using POWER button as a normal button.

khadas@Khadas:~$ evtest /dev/input/event1 
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x0 product 0x0 version 0x0
Input device name: "rk805 pwrkey"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 116 (KEY_POWER)
Properties:
Testing ... (interrupt to exit)
Event: time 1704698972.764361, type 1 (EV_KEY), code 116 (KEY_POWER), value 1
Event: time 1704698972.764361, -------------- SYN_REPORT ------------
Event: time 1704698972.943655, type 1 (EV_KEY), code 116 (KEY_POWER), value 0
Event: time 1704698972.943655, -------------- SYN_REPORT ------------
Event: time 1704698973.362736, type 1 (EV_KEY), code 116 (KEY_POWER), value 1
Event: time 1704698973.362736, -------------- SYN_REPORT ------------
Event: time 1704698973.499300, type 1 (EV_KEY), code 116 (KEY_POWER), value 0
Event: time 1704698973.499300, -------------- SYN_REPORT ------------
Event: time 1704698973.800751, type 1 (EV_KEY), code 116 (KEY_POWER), value 1
Event: time 1704698973.800751, -------------- SYN_REPORT ------------
Event: time 1704698973.971780, type 1 (EV_KEY), code 116 (KEY_POWER), value 0
Event: time 1704698973.971780, -------------- SYN_REPORT ------------
Event: time 1704698974.306224, type 1 (EV_KEY), code 116 (KEY_POWER), value 1
Event: time 1704698974.306224, -------------- SYN_REPORT ------------
Event: time 1704698974.469930, type 1 (EV_KEY), code 116 (KEY_POWER), value 0
Event: time 1704698974.469930, -------------- SYN_REPORT ------------
Event: time 1704698974.747141, type 1 (EV_KEY), code 116 (KEY_POWER), value 1
Event: time 1704698974.747141, -------------- SYN_REPORT ------------
Event: time 1704698974.913957, type 1 (EV_KEY), code 116 (KEY_POWER), value 0
Event: time 1704698974.913957, -------------- SYN_REPORT ------------
Event: time 1704698975.226729, type 1 (EV_KEY), code 116 (KEY_POWER), value 1
Event: time 1704698975.226729, -------------- SYN_REPORT ------------
Event: time 1704698975.396758, type 1 (EV_KEY), code 116 (KEY_POWER), value 0
Event: time 1704698975.396758, -------------- SYN_REPORT ------------
1 Like

@numbqq thanks a lot for the quick answer.

Will disabling the systemd-logind service have any other consequences? That is ususally the service that manages user logins or?

And do you have by any chance some example code to handle the events of the button? Is there some existing functionality for long-press?

@numbqq any news on this?

Hello @brunobiped

@Jacobe will help you then.

Hello @brunobiped
What version of firmware do you have? You can check with uname -a .
And also your Ubuntu type: server, gnome etc…

I’ll provide a special kernel deb for you.
But It only for you to test this time, we won’t support this function in furure. :wink:

Hey @Jacobe

Thanks for taking a look at this.

khadas@dev101 [09:15:08 AM] [~]
-> % uname -a
Linux dev101 5.10.66 #1.5.1 SMP PREEMPT Wed Aug 16 10:24:45 CEST 2023 aarch64 aarch64 aarch64 GNU/Linux
khadas@dev101 [09:15:09 AM] [~]
-> % lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.3 LTS
Release:	22.04
Codename:	jammy

What do you mean by:

But It only for you to test this time, we won’t support this function in furure.

To be more precise what kind of functionality won’t be supported in the future?

To be more precise what kind of functionality won’t be supported in the future?

I mean the button function.
Because it used to power off the device. For your demand, I disable the power off function so that you can use it more conveniently.Subsequent firmwares will still treat this button as poweroff.

Please download the .deb from the here, install it and reboot.

Install the library

$ sudo apt install python3-pip
$ pip install evdev

Then you can use the code to detect events

import evdev

# Open the device
device_path = '/dev/input/event1'  # Your device path
device = evdev.InputDevice(device_path)

# Initialize variables
pressed = False
long_press_threshold = 1  # Long press time threshold (seconds)
long_press = False

# Listen for events
for event in device.read_loop():
    if event.type == evdev.ecodes.EV_KEY:
        if event.value == 1:  # Key is pressed
            pressed = True
            start_time = event.timestamp()
        elif event.value == 0:  # Key is released
            pressed = False
            long_press = False
            end_time = event.timestamp()
            if end_time - start_time >= long_press_threshold:
                print("Long press")
            else:
                print("Short press")
2 Likes

Thanks a lot. I will try it out. Could you explain to me in a bit more detail what the debian package does and how it does it? Is there another way to get the change done?

You’re welcom.

When the key is pressed, a KEY_POWER message will be sent to the kernel, there are many KEY related macros in the kernel, I have modified KEY_POWER to an unused macro definition, so that it will not trigger the poweroff function.

You can find the driver code in
fenix/build/linux/drivers/input/misc/rk805-pwrkey.c

Hey @Jacobe
I am Bruno’s colleague, and taking over the work on this functionality.
What would be the exact change to do to this file, and how can we handle the next firmware updates to keep this functionality on our side ?
We forked the fenix repository to generate our custom ubuntu images.
And this might be a long shot, but do you think there would be a way to disable the power off function only if our service is running ? So that the default power off button could still work if the service that uses it is not enabled / crashed
Thanks for your help !

Hello @paul-biped
You can open the file fenix/build/linux/drivers/input/misc/rk805-pwrkey.c, replace all KEY_POWER with KEY_TEXT, that’s what I did last time.

Now I’m still thinking about a suitable program to disable the key when service is running and enable it when service stopped.I’ll get back to you as soon as I can. :man_technologist:

I solved! Here is the code in C and Python. These codes don’t need to change the driver code, you can just use them.

#include <linux/input.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    // Open the input device file
    int fd = open("/dev/input/event1", O_RDONLY);
    if (fd == -1) {
        perror("Failed to open input device");
        exit(EXIT_FAILURE);
    }

    // Grab the input device to prevent other programs from receiving events
    if (ioctl(fd, EVIOCGRAB, 1) == -1) {
        perror("Failed to grab input device");
        close(fd);
        exit(EXIT_FAILURE);
    }

    // Execute your program logic here
    while (1) {
        // ...
    }

    // Release the input device
    if (ioctl(fd, EVIOCGRAB, 0) == -1) {
        perror("Failed to release input device");
        close(fd);
        exit(EXIT_FAILURE);
    }

    close(fd);
    return 0;
}
import fcntl
import os
import struct
import array
import time

# Define constants
EVIOCGRAB = 0x40044590
EV_KEY = 0x01
KEY_POWER = 116  # Replace with the actual key code

# Open the input device file
input_device = "/dev/input/event1"  # Replace with your actual input device
fd = os.open(input_device, os.O_RDONLY)

# Grab the input device to prevent other programs from receiving events
fcntl.ioctl(fd, EVIOCGRAB, 1)

# Execute your program logic here
try:
    print("try")
    while True:
        print("disable key")
        time.sleep(1)

except KeyboardInterrupt:
    pass

finally:
    # Release the input device
    fcntl.ioctl(fd, EVIOCGRAB, 0)
    os.close(fd)
1 Like

Thank you so much ! Not having to do a driver update is a great help, and having this handled in our service is even better.
I actually found an even easier way to do that, but wouldn’t have look into it without your idea

device = evdev.InputDevice(device_path)
device.grab() # similar to EVIOCGRAB -> 1

...

device.ungrab() # similar to EVIOCGRAB -> 0

Thanks again !
Paul

1 Like