Skip to content

Commit

Permalink
Merge pull request #8 from asus-linux-drivers/display-rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
ldrahnik authored Feb 9, 2023
2 parents 0f79368 + d096bab commit fb91e70
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 80 deletions.
41 changes: 10 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,22 @@
# Asus fliplock driver

[![License: GPLv2](https://img.shields.io/badge/License-GPL_v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)

![Maintainer](https://img.shields.io/badge/maintainer-ldrahnik-blue)
If you find the project useful, do not forget to give project a [![GitHub stars](https://img.shields.io/github/stars/asus-linux-drivers/asus-fliplock-driver.svg?style=flat-square)](https://github.com/asus-linux-drivers/asus-fliplock-driver/stargazers) People already did!

![gif preview](./preview.gif)

## TODO:
## Features

- [x] (Configurable support of flip key mapping)
- [x] (Disable backlight of keyboard in tablet mode and use latest level of backlight when is mode changed back to laptop; numpad backlight does the same; history may be done for example via optional file [`brightness_hw_changed`](https://patchwork.kernel.org/project/platform-driver-x86/patch/[email protected]/) or temp file located in `/tmp`)
- [x] (Disable backlight of capslock led in tablet mode and use latest level of backlight when is mode changed back to laptop; numpad backlight does the same)
- [x] (When after laptop start does not exist device `Intel HID switches` yet (driver will try find again every 5s) use for first change mode device `Asus WMI hotkeys` and listen for configurable key (in my case `KEY_PROG2`) then is imediatelly added device `Intel HID switches`)
- Disable backlight of keyboard in tablet mode and use latest level of backlight when is mode changed back to laptop; NumberPad backlight does the same; CapsLock led too; history may be done for example via optional file [`brightness_hw_changed`](https://patchwork.kernel.org/project/platform-driver-x86/patch/[email protected]/) or temp file located in `/tmp`
- When does not exist device `Intel HID switches` yet, driver will try find again every 5s and use for first flip event from `Asus WMI hotkeys` instead
- Customizable scripts for each display rotation (inverted, left-up, right-up and default)
- Touchpad rotates by default
- Configurable support of flip key mapping, by default `EV_KEY.KEY_PROG2`

<br/>

Install required packages

- Debian / Ubuntu / Linux Mint / Pop!_OS / Zorin OS:
```
sudo apt install libevdev2 python3-libevdev git
```

- Arch Linux / Manjaro:
```
sudo pacman -S libevdev python-libevdev git
```

- Fedora:
```
sudo dnf install libevdev python-libevdev git
```


Now you can get the latest ASUS fliplock driver for Linux from Git and install it using the following commands.
You can get the latest ASUS fliplock driver for Linux from Git and install it using the following commands.
```
git clone https://github.com/asus-linux-drivers/asus-fliplock-driver
cd asus-fliplock-driver
Expand All @@ -52,17 +35,13 @@ To activate logger, do in a console:
LOG=DEBUG sudo -E ./asus_fliplock.py
```

For some operating systems with boot failure (Pop!OS, Mint, ElementaryOS, SolusOS), before installing, please uncomment in the asus_fliplock.service file, this following property and adjust its value:
```
# ExecStartPre=/bin/sleep 2
```

## Credits

Thank you very much all the contributors of [asus-touchpad-numpad-driver](https://github.com/mohamed-badaoui/asus-touchpad-numpad-driver) for your work.

## Existing similar projects

- [bash] https://github.com/alesya-h/linux_detect_tablet_mode
- [bash] https://gist.github.com/ACamposPT/6794aa02a6e5e341f123d447b3645b93

Why was this project created? Easier installation/uinstallation and usage of python libevdev.
Why was this project created? Easy installation/uninstallation and implementation of handling touchpad rotation together with customizable possibility for each display rotation state. Aimed for Asus laptops.
159 changes: 117 additions & 42 deletions asus_fliplock.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
import os
import re
import sys
import time
import subprocess
from typing import Optional

from libevdev import Device, EV_SW

# Setup logging
# LOG=DEBUG sudo -E ./asus_fliplock.py # all messages
# LOG=ERROR sudo -E ./asus_fliplock.py # only error messages
# LOG=DEBUG sudo -E ./asus_fliplock.py "default" # all messages
# LOG=ERROR sudo -E ./asus_fliplock.py "default" # only error messages
logging.basicConfig()
log = logging.getLogger('Asus fliplock')
log.setLevel(os.environ.get('LOG', 'INFO'))
Expand All @@ -23,17 +24,19 @@

fliplock_layouts = importlib.import_module('conf.'+ layout)

touchpad_name: Optional[str] = None
touchpad_id = 0
switches: Optional[str] = None
wmi_hotkeys: Optional[str] = None


touchpad_detected = 0
switches_detected = 0
wmi_hotkeys_detected = 0

def search_devices():

global switches, switches_detected
global wmi_hotkeys, wmi_hotkeys_detected
global touchpad_name, touchpad_id, switches, wmi_hotkeys
global touchpad_detected, switches_detected, wmi_hotkeys_detected

tries = 5

Expand All @@ -44,8 +47,14 @@ def search_devices():
lines = f.readlines()
for line in lines:

# Look for the touchpad
if touchpad_detected == 0 and ("Name=\"ASUE" in line or "Name=\"ELAN" in line) and "Touchpad" in line:
touchpad_detected = 1
log.info('Detecting touchpad from string: \"%s\"', line.strip())
touchpad_name = line.split("\"")[1]

# Look for the device switches
if re.search("switches",line):
if re.search("switches", line):
switches_detected = 1
log.debug('Detect switches from %s', line.strip())

Expand All @@ -70,7 +79,7 @@ def search_devices():
log.debug('Set switches id %s from %s', switches, line.strip())
break

if switches_detected == 2 and wmi_hotkeys_detected == 2:
if switches_detected == 2 and wmi_hotkeys_detected == 2 and touchpad_detected == 1:
break

if switches_detected != 2:
Expand All @@ -91,6 +100,99 @@ def search_devices():
fd_t_wmi_hotkeys = open('/dev/input/event' + str(wmi_hotkeys), 'rb')
d_t_wmi_hotkeys = Device(fd_t_wmi_hotkeys)

def execute_cmd(cmd):
try:
os.system(cmd)
except OSError as e:
log.error(e)


def execute_cmds_in_array(cmds):
for cmd in cmds:
execute_cmd(cmd)


def change_touchpad_orientation(orientation):
global touchpad_name, touchpad_id

transform_matrix = False
if orientation == "normal":
transform_matrix = "1 0 0 0 1 0 0 0 1"
elif orientation == "bottom-up":
transform_matrix = "-1 0 1 0 -1 1 0 0 1"
elif orientation == "right-up":
transform_matrix = "0 1 0 -1 0 1 0 0 1"
elif orientation == "left-up":
transform_matrix = "0 -1 1 1 0 0 0 0 1"

if transform_matrix:
transform_matrix_name = "Coordinate Transformation Matrix"
touchpad_id_regexp = "(?<=id=).*(?=\\t)"

try:
cmd_touchpad_id = "xinput | grep '" + touchpad_name + "'"
touchpad_row_with_id = subprocess.check_output(cmd_touchpad_id, shell=True)
touchpad_row_with_id_decoded = touchpad_row_with_id.decode()
matches = re.findall(touchpad_id_regexp, touchpad_row_with_id_decoded)
if matches:
touchpad_id = matches[0]

if touchpad_id:
if orientation != "bottom-up":
cmd_enable_touchpad = "xinput set-prop {} 'Device Enabled' 1".format(touchpad_id)
log.debug(cmd_enable_touchpad)
subprocess.check_output(cmd_enable_touchpad, shell=True)
else:
cmd_disable_touchpad = "xinput set-prop {} 'Device Enabled' 0".format(touchpad_id)
log.debug(cmd_disable_touchpad)
subprocess.check_output(cmd_disable_touchpad, shell=True)

cmd_rotate_touchpad = "xinput set-prop '" + touchpad_name + "' '" + transform_matrix_name + "' " + transform_matrix
log.debug(cmd_rotate_touchpad)
subprocess.check_output(cmd_rotate_touchpad, shell=True)
except subprocess.CalledProcessError as e:
log.error(e.output)


def execute_cmds_according_to_accelerometer_orientation():

# inverted when is orientation not recognized
orientation = "bottom-up"
orientation_regexp = "(?<=orientation: ).*?(?=\))"

try:
monitor_sensors = subprocess.Popen("monitor-sensor", shell=True, stdout=subprocess.PIPE)

for line in monitor_sensors.stdout:
utf8_line = line.decode()
matches = re.findall(orientation_regexp, utf8_line)
if matches:
orientation = matches[0]
log.debug(utf8_line)
break

except subprocess.CalledProcessError as e:
log.error(e.output)

# change by default matrix of touchpad
# run custom commands from conf
if orientation == "bottom-up":
change_touchpad_orientation(orientation)
execute_cmds_in_array(fliplock_layouts.orientation_bottom_up_actions)
elif orientation == "right-up":
change_touchpad_orientation(orientation)
execute_cmds_in_array(fliplock_layouts.orientation_right_up_actions)
elif orientation == "left-up":
change_touchpad_orientation(orientation)
execute_cmds_in_array(fliplock_layouts.orientation_left_up_actions)
elif orientation == "normal":
change_touchpad_orientation(orientation)
execute_cmds_in_array(fliplock_layouts.orientation_normal_actions)


# run for first time when is service started
execute_cmds_according_to_accelerometer_orientation()

# If mode has been changed, do something
if switches is None and wmi_hotkeys is not None:

Expand All @@ -101,26 +203,13 @@ def search_devices():
if switches is not None:
break

if e.matches(fliplock_layouts.flip_key) and e.value == 1:

for cmd in fliplock_layouts.to_tablet_mode_actions:

try:
os.system(cmd)
except e:
log.error(e)

elif e.matches(fliplock_layouts.flip_key) and e.value == 0:

for cmd in fliplock_layouts.to_laptop_mode_actions:

try:
os.system(cmd)
except e:
log.error(e)
if e.matches(fliplock_layouts.flip_key):
time.sleep(2)
execute_cmds_according_to_accelerometer_orientation()

search_devices()


if switches is not None:

fd_t_switches = open('/dev/input/event' + str(switches), 'rb')
Expand All @@ -130,20 +219,6 @@ def search_devices():

log.debug(e)

if e.matches(EV_SW.SW_TABLET_MODE) and e.value == 1:

for cmd in fliplock_layouts.to_tablet_mode_actions:

try:
os.system(cmd)
except e:
log.error(e)

elif e.matches(EV_SW.SW_TABLET_MODE) and e.value == 0:

for cmd in fliplock_layouts.to_laptop_mode_actions:

try:
os.system(cmd)
except e:
log.error(e)
if e.matches(EV_SW.SW_TABLET_MODE):
time.sleep(2)
execute_cmds_according_to_accelerometer_orientation()
23 changes: 19 additions & 4 deletions conf/default.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,30 @@
from libevdev import EV_KEY

to_tablet_mode_actions = [
orientation_bottom_up_actions = [
"cat /sys/class/leds/asus::kbd_backlight/brightness | sudo tee /tmp/kbd_backlight_brightness",
"echo 0 | sudo tee /sys/class/leds/asus::kbd_backlight/brightness",
"cat /sys/class/leds/input3\:\:capslock/brightness | sudo tee /tmp/input3_capslock_brightness",
"echo 0 | sudo tee /sys/class/leds/input3\:\:capslock/brightness"
]

to_laptop_mode_actions = [
"cat /tmp/kbd_backlight_brightness | sudo tee /sys/class/leds/asus::kbd_backlight/brightness",
"cat /tmp/input3_capslock_brightness | sudo tee /sys/class/leds/input3\:\:capslock/brightness"
orientation_left_up_actions = [
"sudo rm -f /tmp/kbd_backlight_brightness",
"sudo rm -f /tmp/input3_capslock_brightness"
# TODO: enable touchpad (is disabled by default for every rotation probably)
#"xinput set-prop 17 'Device Enabled' 0"
]

orientation_right_up_actions = [
"sudo rm -f /tmp/kbd_backlight_brightness",
"sudo rm -f /tmp/input3_capslock_brightness",
# TODO: enable touchpad (is disabled by default for every rotation probably)
]

orientation_normal_actions = [
# backward setting up saved backlight brightness (only in case inverted was previous state! otherwise tmp file does not exist)
"test -f /tmp/kbd_backlight_brightness && cat /tmp/kbd_backlight_brightness | sudo tee /sys/class/leds/asus::kbd_backlight/brightness",
# backward setting up saved capslock led (only in case inverted was previous state! otherwise tmp file does not exist)
"test -f /tmp/input3_capslock_brightness && cat /tmp/input3_capslock_brightness | sudo tee /sys/class/leds/input3\:\:capslock/brightness"
]

flip_key = EV_KEY.KEY_PROG2
14 changes: 11 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@ then
fi

if [[ $(apt install 2>/dev/null) ]]; then
echo 'apt is here' && apt -y install libevdev2 python3-libevdev
echo 'apt is here' && apt -y install libevdev2 python3-libevdev iio-sensor-proxy
elif [[ $(pacman -h 2>/dev/null) ]]; then
echo 'pacman is here' && pacman --noconfirm -S libevdev python-libevdev
echo 'pacman is here' && pacman --noconfirm -S libevdev python-libevdev iio-sensor-proxy
elif [[ $(dnf install 2>/dev/null) ]]; then
echo 'dnf is here' && dnf -y install libevdev python-libevdev
echo 'dnf is here' && dnf -y install libevdev python-libevdev iio-sensor-proxy
fi

python3 -m pip install -r requirements.txt

# Checking if the pip dependencies are successfuly loaded
if [[ $? != 0 ]]; then
echo "pip dependencies via file requirements.txt cannot be loaded correctly."
exit 1
fi

if [[ -d conf/__pycache__ ]] ; then
Expand Down
Empty file added requirements.txt
Empty file.

0 comments on commit fb91e70

Please sign in to comment.