Unify per-device hooks

The recent patch to support the Nokia N900 offered a new dedicated
inputhandler hook. This would bring the number of those scripts to
three:

- the default three button, touchscreen support one we use on Pinephone
and most of the devices
- the one button e-reader one, which behave differently cause there is a
single state for the e-ink screen devices (no screenoff or screen
locked)
- and now this third one, cause the device got a non multi-touch support
screen, and a physical keyboard

I paused while reviewing this patch cause this is becoming too much
duplication. We had to think about this script, and how to deduplicate
the code as much as possible.

While investigating, I noted that with the recent addition
of sxmo_state_switch.sh, we could probaly unify cleanly the whole
management of the Sxmo state, on every devices.

With a simple refactorisation, I was able to change the available
states with a simple environment variable $SXMO_STATES. The default value
is of course "unlock lock screenoff", but on desktop it will become
"unlock locker", and on e-ink reader just "unlock".

This unify most of the variable code from the inputhandlers, cause all of them
can now call sxmo_state_switch.sh up/down in a common way. The last
pieces of code that is still dependent on the device type was the
sxmo_wakelock.sh part:

On three state mode devices, Sxmo remove the wakelock if the state is
"screenoff" after 3s of inactivity. On Pinenote Sxmo remove it when "unlock"
after 120s of inactivity. On desktop, we currently never suspend.

I managed to unify this by extending the "transition" method from
sxmo_state_switch.sh. The environment variables is
$SXMO_SUSPENDABLE_STATES:

By default (pinephone and other), we use "screenoff 3" as value.
On pinetab "unlock 120", and on desktop nothing explicit (we
never reach screenoff in this mode anyway).

It is possible to define multiple cases, ex "lock 120 screenoff 3", which
means 120s timeout while lock, and 3s timeout while screenoff.

It is now possible for a user, or a future device, to define a brand new
workflow, with different available states, and suspending behaviors.

This change also strip the state hooks of this responsibility, and ensure we
keep control over this behavior.

With those changes, we now can remove completely the subdirectories from the
hooks \o/

The in-screen keyboard specific case will be managed by an environment
variable, to disable it on Nokia 900, or devices that have a physical
keyboard (desktops too).
This commit is contained in:
Willow Barraco
2023-10-13 10:48:20 +02:00
parent b83b2e4f18
commit b09469d965
45 changed files with 152 additions and 449 deletions

View File

@@ -1,13 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
sxmo_wakelock.sh lock sxmo_not_screenoff infinite
# Go to locker after 5 minutes of inactivity
if [ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ]; then
sxmo_jobs.sh stop idle_locker
else
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout 300 'sxmo_hook_locker.sh'
fi

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1,299 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# This script handles input actions, it is called by lisgd for gestures
# and by dwm for button presses
ACTION="$1"
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
XPROPOUT="$(sxmo_wm.sh focusedwindow)"
WMCLASS="$(printf %s "$XPROPOUT" | grep app: | cut -d" " -f2- | tr '[:upper:]' '[:lower:]')"
WMNAME="$(printf %s "$XPROPOUT" | grep title: | cut -d" " -f2- | tr '[:upper:]' '[:lower:]')"
sxmo_debug "ACTION: $ACTION WMNAME: $WMNAME WMCLASS: $WMCLASS XPROPOUT: $XPROPOUT"
#special context-sensitive handling
case "$WMCLASS" in
*"mpv"*)
case "$ACTION" in
"oneright")
sxmo_type.sh -k Left
exit 0
;;
"oneleft")
sxmo_type.sh -k Right
exit 0
;;
"oneup")
sxmo_type.sh m
exit 0
;;
"onedown")
sxmo_type.sh p
exit 0
;;
esac
;;
*"foot"*|*"st"*)
# First we try to handle the app running inside st:
case "$WMNAME" in
*"weechat"*)
case "$ACTION" in
*"oneleft")
sxmo_type.sh -M Alt -k a
exit 0
;;
*"oneright")
sxmo_type.sh -M Alt -k less
exit 0
;;
*"oneup")
sxmo_type.sh -k Page_Down
exit 0
;;
*"onedown")
sxmo_type.sh -k Page_Up
exit 0
;;
esac
;;
*" sms")
case "$ACTION" in
*"upbottomedge")
number="$(printf %s "$WMNAME" | sed -e 's|^\"||' -e 's|\"$||' | cut -f1 -d' ')"
sxmo_terminal.sh sxmo_modemtext.sh conversationloop "$number" &
exit 0
;;
esac
;;
*"tuir"*)
if [ "$ACTION" = "rightbottomedge" ]; then
sxmo_type.sh o
exit 0
elif [ "$ACTION" = "leftbottomedge" ]; then
sxmo_type.sh s
exit 0
fi
;;
*"less"*)
case "$ACTION" in
"leftbottomedge")
sxmo_type.sh q
exit 0
;;
"leftrightedge_short")
sxmo_type.sh q
exit 0
;;
*"onedown")
sxmo_type.sh u
exit 0
;;
*"oneup")
sxmo_type.sh d
exit 0
;;
*"oneleft")
sxmo_type.sh ":n" -k Return
exit 0
;;
*"oneright")
sxmo_type.sh ":p" -k Return
exit 0
;;
esac
;;
*"amfora"*)
case "$ACTION" in
"downright")
sxmo_type.sh -k Tab
exit 0
;;
"upleft")
sxmo_type.sh -M Shift -k Tab
exit 0
;;
*"onedown")
sxmo_type.sh u
exit 0
;;
*"oneup")
sxmo_type.sh d
exit 0
;;
*"oneright")
sxmo_type.sh -k Return
exit 0
;;
"upright")
sxmo_type.sh -M Ctrl t
exit 0
;;
*"oneleft")
sxmo_type.sh b
exit 0
;;
"downleft")
sxmo_type.sh -M Ctrl w
exit 0
;;
esac
;;
esac
# Now we try generic actions for terminal
case "$ACTION" in
*"onedown")
case "$WMCLASS" in
*"foot"*)
sxmo_type.sh -M Shift -k Page_Up
exit 0
;;
*"st"*)
sxmo_type.sh -M Ctrl -M Shift -k b
exit 0
;;
esac
;;
*"oneup")
case "$WMCLASS" in
*"foot"*)
sxmo_type.sh -M Shift -k Page_Down
exit 0
;;
*"st"*)
sxmo_type.sh -M Ctrl -M Shift -k f
exit 0
;;
esac
;;
esac
esac
#standard handling
case "$ACTION" in
"powerbutton_one")
if echo "$WMCLASS" | grep -i "megapixels"; then
sxmo_type.sh -k space
fi
# swallow: postwake calls sxmo_hook_unlock.sh
exit 0
;;
"powerbutton_two")
sxmo_keyboard.sh toggle
exit 0
;;
"powerbutton_three")
sxmo_killwindow.sh
exit 0
;;
"rightleftedge")
sxmo_wm.sh previousworkspace
exit 0
;;
"leftrightedge")
sxmo_wm.sh nextworkspace
exit 0
;;
"twoleft")
sxmo_wm.sh movepreviousworkspace
exit 0
;;
"tworight")
sxmo_wm.sh movenextworkspace
exit 0
;;
"righttopedge")
sxmo_brightness.sh up
exit 0
;;
"lefttopedge")
sxmo_brightness.sh down
exit 0
;;
"upleftedge")
sxmo_audio.sh vol up
exit 0
;;
"downleftedge")
sxmo_audio.sh vol down
exit 0
;;
"upbottomedge")
sxmo_keyboard.sh open
exit 0
;;
"downbottomedge")
sxmo_keyboard.sh close
exit 0
;;
"downtopedge")
sxmo_dmenu.sh isopen || sxmo_appmenu.sh &
exit 0
;;
"twodowntopedge")
sxmo_dmenu.sh isopen || sxmo_appmenu.sh sys &
exit 0
;;
"uptopedge")
sxmo_dmenu.sh close
if pgrep mako >/dev/null; then
makoctl dismiss --all
elif pgrep dunst >/dev/null; then
dunstctl close-all
fi
exit 0
;;
"twodownbottomedge")
sxmo_killwindow.sh
exit 0
;;
"uprightedge")
sxmo_type.sh -k Up
exit 0
;;
"downrightedge")
sxmo_type.sh -k Down
exit 0
;;
"leftrightedge_short")
sxmo_type.sh -k Left
exit 0
;;
"rightrightedge_short")
sxmo_type.sh -k Right
exit 0
;;
"rightbottomedge")
sxmo_type.sh -k Return
exit 0
;;
"leftbottomedge")
sxmo_type.sh -k BackSpace
exit 0
;;
"topleftcorner")
sxmo_appmenu.sh sys &
exit 0
;;
"toprightcorner")
sxmo_appmenu.sh scripts &
exit 0
;;
"bottomleftcorner")
# could go into suspend? leaving blank for now.
exit 0
;;
"bottomrightcorner")
if [ "$(sxmo_rotate.sh isrotated)" = "right" ]; then
sxmo_rotate.sh rotinvert
else
sxmo_rotate.sh rotright
fi
exit 0
;;
esac

View File

@@ -1,11 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
sxmo_wakelock.sh lock sxmo_stay_awake "${SXMO_UNLOCK_IDLE_TIME:-120}s"
# Add here whatever you want to do

View File

@@ -1,28 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2022 Sxmo Contributors
# This hook is called when the system becomes unlocked again
# include common definitions
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
sxmo_wakelock.sh lock sxmo_stay_awake "${SXMO_UNLOCK_IDLE_TIME:-120}s"
sxmo_hook_statusbar.sh state_change &
sxmo_wm.sh dpms off
sxmo_wm.sh inputevent touchscreen on
sxmo_wm.sh inputevent stylus on
if [ ! -e "$XDG_CACHE_HOME"/sxmo/sxmo.nogesture ]; then
superctl start sxmo_hook_lisgd
fi
# suspend after if no activity after 120s
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "1" '' \
resume "sxmo_wakelock.sh lock sxmo_stay_awake \"${SXMO_UNLOCK_IDLE_TIME:-120}s\""
wait

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen/

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
desktop/

View File

@@ -1 +0,0 @@
desktop/

View File

@@ -1 +0,0 @@
one_button_e_reader

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
desktop/

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen/

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -1 +0,0 @@
three_button_touchscreen

View File

@@ -14,8 +14,6 @@
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
sxmo_wakelock.sh lock sxmo_not_screenoff infinite
# This hook is called when the system reaches a locked state
sxmo_led.sh blink blue &
@@ -27,10 +25,10 @@ sxmo_wm.sh inputevent touchscreen off
sxmo_jobs.sh stop periodic_blink
sxmo_jobs.sh stop periodic_wakelock_check
# Go to screenoff after 8 seconds of inactivity
# Go down after 8 seconds of inactivity
if ! [ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ]; then
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "${SXMO_LOCK_IDLE_TIME:-8}" "sxmo_state_switch.sh set screenoff"
timeout "${SXMO_LOCK_IDLE_TIME:-8}" "sxmo_state_switch.sh down"
fi
wait

View File

@@ -15,4 +15,5 @@ case "$SXMO_WM" in
;;
esac
sxmo_state_switch.sh set unlock
# need & cause we are still holding flock
sxmo_state_switch.sh set unlock &

View File

@@ -35,7 +35,3 @@ case "$SXMO_WM" in
esac
wait
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout 3 'sxmo_wakelock.sh unlock sxmo_not_screenoff' \
resume 'sxmo_wakelock.sh lock sxmo_not_screenoff infinite'

View File

@@ -16,9 +16,8 @@ while ! superctl status > /dev/null 2>&1; do
sleep 0.5
done
if [ "$(command -v sxmo_hook_locker.sh)" ]; then
sxmo_hook_locker.sh
fi
# Not dangerous if "locker" isn't an available state
sxmo_state_switch.sh set locker
# Load our sound daemons
@@ -65,15 +64,15 @@ case "$SXMO_WM" in
;;
esac
# To setup initial lock state
sxmo_state_switch.sh set unlock
# Turn on auto-suspend
if sxmo_wakelock.sh isenabled; then
sxmo_wakelock.sh lock sxmo_not_screenoff infinite
sxmo_wakelock.sh lock sxmo_not_suspendable infinite
superctl start sxmo_autosuspend
fi
# To setup initial unlock state
sxmo_state_switch.sh set unlock
# Turn on lisgd
if [ ! -e "$XDG_CACHE_HOME"/sxmo/sxmo.nogesture ]; then
superctl start sxmo_hook_lisgd

View File

@@ -8,8 +8,6 @@
# This hook is called when the system becomes unlocked again
sxmo_wakelock.sh lock sxmo_not_screenoff infinite
sxmo_led.sh blink red green &
sxmo_wm.sh dpms off
@@ -18,7 +16,7 @@ sxmo_wm.sh inputevent touchscreen on
sxmo_jobs.sh stop periodic_blink
sxmo_jobs.sh stop periodic_wakelock_check
# Go to lock after 120 seconds of inactivity
# Go down after 120 seconds of inactivity
if [ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ]; then
sxmo_jobs.sh stop idle_locker
else
@@ -27,12 +25,12 @@ else
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" 'sh -c "
swaymsg mode default;
exec sxmo_state_switch.sh set lock
exec sxmo_state_switch.sh down
"'
;;
dwm)
sxmo_jobs.sh start idle_locker sxmo_idle.sh -w \
timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" "sxmo_state_switch.sh set lock"
timeout "${SXMO_UNLOCK_IDLE_TIME:-120}" "sxmo_state_switch.sh down"
;;
esac
fi

View File

@@ -34,7 +34,7 @@ A brief overview of sxmo's features (in order of presentation):
- *Autosuspend, screen blanking, and input locking*: sxmo states allow sxmo to
automatically suspend when idle unless certain programs block it; to offer
protection from accidental wakeups; and to blank the screen and lock the input
while in a phone call and the phone is near your face. See STATES.
while in a phone call and the phone is near your face. See STATES AND SUSPENSION.
- *Smart cronjobs*: sxmo uses _crond_(1) to handle cronjobs and a special
program called _mnc_(1) to wake the phone up in time to execute cron jobs.
See CRONJOBS.
@@ -330,27 +330,41 @@ HOOKS: _sxmo_hook_apps.sh_ (control list of apps)
SEE _sxmo_files.sh_(1).
# STATES
# STATES AND SUSPENSION
Sxmo recognizes five basic states:
Sxmo recognizes three basic states:
- *unlock*: Screen is on; touchscreen is enabled.
- *lock*: Screen is on; touchscreen is disabled.
- *screenoff*: Screen is off; touchscreen is disabled. The led will also blink
purple every few seconds to indicate that you are in this state.
- *suspend or CRUST*: This is CRUST (or suspend), where the modem will still be
active and monitor for incoming calls/texts but everything else will be
suspended.
- *Proximity Mode*: This is a special state when one is in a phone call. If you
bring it close to your face, it will disable input and turn the screen off,
and if you move the phone away from your face, it will enable input and turn
the screen back on.
the screen back on. This script actually switch back and forth between *unlock*
and *screenoff*.
A diagram of the states can be found here:
There also is some dedicated workflow for some type of device.
https://sxmo.org/assets/lock-power-states.png
On desktops, which is the default mode, if no other one is recognised:
The usual workflow is this.
- *unlock*: The entry point, and default one.
- *locker*: A session locker is running, and prevent any interaction with the
environment.
On e-ink display devices, by example e-reader devices:
- *unlock*: The entry point, and only available state. The screens stay on while
the device is suspended, which means that the power button is only a refresh of
the suspension idle timeout, and a way to bring back interactivity.
Sxmo will also *suspend* on most devices, when this feature is available.
- *suspend or CRUST*: This is CRUST (or suspend), where the modem will still be
active and monitor for incoming calls/texts but everything else will be
suspended.
The usual workflow is this.
- If the phone is in the *unlock* state (default when you boot up) and you wish
to suspend it, tap the power button once. This will transition to the
@@ -370,7 +384,7 @@ Sxmo also handles automatic transitions from some states to others.
- It will automatically transition from *screenoff* to *CRUST* immediately
unless something is blocking it.
You can set up suspend blockers in the wakelocks hook.
You can set up suspend blockers in the block_suspend hook.
HOOKS:
_sxmo_hook_postwake.sh_ (what to do after waking up from suspend state),

View File

@@ -4,51 +4,122 @@
# shellcheck source=scripts/core/sxmo_common.sh
. sxmo_common.sh
SXMO_STATES="${SXMO_STATES:-unlock lock screenoff}"
SXMO_SUSPENDABLE_STATES="${SXMO_SUSPENDABLE_STATES:-screenoff 3}"
transition_can_suspend() {
# shellcheck disable=SC2086
set -- $SXMO_SUSPENDABLE_STATES
tmpstate=
timeout=
while [ $# -gt 0 ]; do
if [ "$1" = "$state" ]; then
tmpstate="$1"
timeout="$2"
break
fi
shift 2
done
stop_idle_suspender() {
sxmo_jobs.sh stop idle_suspender
sxmo_wakelock.sh lock sxmo_not_suspendable infinite
}
if [ -z "$tmpstate" ]; then
sxmo_log "this state is not suspendable"
stop_idle_suspender
return
fi
if ! printf "%b\n" "$timeout" | grep -q '^[0-9]\+$'; then
sxmo_log "there is no valid suspendable timeout for this state"
stop_idle_suspender
return
fi
sxmo_log "idle suspender started with timeout $timeout"
sxmo_jobs.sh start idle_suspender sxmo_idle.sh -w \
timeout "$timeout" 'sxmo_wakelock.sh unlock sxmo_not_suspendable' \
resume 'sxmo_wakelock.sh lock sxmo_not_suspendable infinite'
}
transition() {
# We don't transition if we stay with the same state
# shellcheck disable=SC2153
if [ "$state" = "$(cat "$SXMO_STATE")" ]; then
return
fi
sxmo_log "transitioning to stage $state"
printf %s "$state" > "$SXMO_STATE"
sxmo_hook_"$state".sh &
sxmo_hook_statusbar.sh state_change &
wait
(
# We need a subshell so we can close the lock fd, without
# releasing the lock
exec 3<&-
sxmo_hook_"$state".sh &
sxmo_hook_statusbar.sh state_change &
transition_can_suspend &
wait
)
}
up() {
count="${1:-1}"
while [ "$count" -gt 0 ]; do
case "$state" in
unlock)
state=screenoff
;;
screenoff)
state=lock
;;
lock)
state=unlock
;;
esac
count=$((count-1))
# shellcheck disable=SC2086
set -- $SXMO_STATES
i=1
while [ $i -le $# ]; do
tmpstate=
prevstate=
eval "tmpstate=\$$i"
if [ "$tmpstate" = "$state" ]; then
if [ $i = 1 ]; then
eval "prevstate=\$$#"
else
eval "prevstate=\$$((i-1))"
fi
state="$prevstate"
break
fi
i=$((i+1))
done
transition
if [ "$count" -gt 1 ]; then
up $((count-1))
else
transition
fi
}
down() {
count="${1:-1}"
while [ "$count" -gt 0 ]; do
case "$state" in
unlock)
state=lock
;;
screenoff)
state=unlock
;;
lock)
state=screenoff
;;
esac
count=$((count-1))
# shellcheck disable=SC2086
set -- $SXMO_STATES
i=1
while [ $i -le $# ]; do
tmpstate=
nextstate=
eval "tmpstate=\$$i"
if [ "$tmpstate" = "$state" ]; then
if [ $i = $# ]; then
nextstate=$1
else
eval "nextstate=\$$((i+1))"
fi
state="$nextstate"
break
fi
i=$((i+1))
done
transition
if [ "$count" -gt 1 ]; then
down $((count-1))
else
transition
fi
}
exec 3<> "$SXMO_STATE.lock"
@@ -66,11 +137,9 @@ case "$action" in
down "$@"
;;
set)
case "$1" in
lock|unlock|screenoff)
state="$1"
transition
;;
esac
if printf "%b\n" "$SXMO_STATES" | tr ' ' '\n' | grep -xq "$1"; then
state="$1"
transition
fi
;;
esac

View File

@@ -76,3 +76,7 @@ SXMO_MONITOR | Display "Output" from `swaymsg -t get_outputs`. Should be the sa
### General / Misc.
SXMO_VIBRATE_DEV | Path to vibration device (see sxmo_vibrate.c and clickclack.c) [default: /dev/input/by-path/platform-vibrator-event]
SXMO_VIBRATE_STRENGTH | Strength parameter to pass to sxmo_vibrate [default: 1]
SXMO_STATES | The list of available state [default: "unlock lock screenoff"]
SXMO_SUSPENDABLE_STATES | The list of suspendable states, with their timeout duration [default: "screenoff 3"]

View File

@@ -1,3 +1,5 @@
export SXMO_DISABLE_LEDS=1
export SXMO_STATUS_DATE_FORMAT="%Y-%m-%d %H:%M"
export SXMO_DISABLE_KEYBINDS=1
export SXMO_STATES="unlock locker"
export SXMO_UNLOCK_IDLE_TIME=300

View File

@@ -19,3 +19,5 @@ export SXMO_ROTATION_POLL_TIME="0" # the device already polls at 1s so a further
export SXMO_UNLOCK_IDLE_TIME="30"
export SXMO_SPEAKER="Master"
export SXMO_SWAY_SCALE="2"
export SXMO_STATES="unlock"
export SXMO_SUSPENDABLE_STATES="unlock 120"