-
Notifications
You must be signed in to change notification settings - Fork 29
Key press exit #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Key press exit #55
Conversation
|
I will take a look at this on friday |
This works on x11 for me, but it doesnt pass the key I pressed to exit anifetch to my terminal. (When I press a key it stops anifetch but the key isnt retyped onto my terminal. |
|
I did some research, appearently most terminals ignore "synthetic" inputs by xdotool or wtype, which is why it wasn't retyping what I wrote onto the terminal. I don't really know how this could be fixed. |
|
@jdafoe12 It seems to me that its not really possible to pass the keypress back to the terminal without some elaborate solution due to syntetic input detection. If you get rid of the xdotool/wtype sections and update the if statement for playing sounds, I will merge the PR. |
|
It shouldnt check for number of args to figure out if a sound file was given. if [ $# -eq 7 ]; then
ffplay -nodisp -autoexit -loop 0 -loglevel quiet "$soundname" &
fi |
|
Sure. I am not sure how to pass the keypress another way. We can remove that functionality for now. I did this and fixed the "optional" argument processing (sound/--key-exit), specifically the conditional around ffplay was fixed. |
|
I just checked and ffplay was not being terminated when a key was pressed. I messed around with the script and currently it does correctly terminate the ffplay instance regardless of if you do ctrl+c or press a key, but it's not really perfect. If I press a key it adds a bunch of whitespace for some reason, and when ctrl^c is entered it cuts like half of the animation output. Check it out and run the command a few times, you'll understand what I mean. Here's the modified script: #!/bin/bash
FRAME_DIR="$HOME/.local/share/anifetch/output"
STATIC_TEMPLATE_FILE="$HOME/.local/share/anifetch/template.txt"
# check for num of args
if [[ $# -ne 6 && $# -ne 7 && $# -ne 8 ]]; then
echo "Usage: $0 <framerate> <top> <left> <right> <bottom> <template_actual_width> [soundname] [--key-exit]"
exit 1
fi
framerate=$1
top=$2
left=$3
right=$4
bottom=$5
template_actual_width=$6
soundname=""
if [ $# -ge 7 ] && [ "${7}" != "--key-exit" ]; then
soundname=$7
fi
# Global variable to store the pressed key
pressed_key=""
# FFPLAY_PID needs to be global for cleanup
FFPLAY_PID=""
# Check if key-exit functionality is enabled
key_exit_enabled=false
if [[ "${!#}" == "--key-exit" ]]; then
key_exit_enabled=true
fi
num_lines=$((bottom - top))
sleep_time=$(echo "scale=4; 1 / $framerate" | bc)
adjusted_sleep_time=$(echo "$sleep_time / $num_lines" | bc -l)
# Buffer for storing processed template, only compute when necessary
declare -a template_buffer
# last terminal width
last_term_width=0
# Hide cursor
tput civis
terminate_ffplay() {
if [ -n "$FFPLAY_PID" ] && kill -0 "$FFPLAY_PID" 2>/dev/null; then
# Send SIGTERM (graceful termination)
kill "$FFPLAY_PID" 2>/dev/null
# Give time to terminate
sleep 0.1
if kill -0 "$FFPLAY_PID" 2>/dev/null; then
# If still running send SIGKILL (forceful termination)
kill -9 "$FFPLAY_PID" 2>/dev/null
fi
fi
}
# exit handler
cleanup() {
terminate_ffplay
tput cnorm # Show cursor
if [ -t 0 ]; then
stty echo # Restore echo
stty icanon
fi
tput sgr0 # Reset terminal attributes
tput cup $(tput lines) 0 # Move cursor to bottom
exit 0
}
trap cleanup SIGINT SIGTERM
stty -echo # won't allow ^C to be printed when SIGINT signal comes.
stty -icanon
# Process the template once and store in memory buffer
process_template() {
local term_width=$(tput cols)
# Only reprocess if terminal width has changed
if [ "$term_width" -ne "$last_term_width" ]; then
# Clear the buffer
template_buffer=()
# Make sure we're working with a valid width
if [ "$term_width" -lt 1 ]; then
term_width=1
fi
# Process each line and store in buffer
local line_num=0
while IFS= read -r line || [ -n "$line" ]; do
# Process the line and store in buffer
template_buffer[$line_num]=$(truncate_line "$line" "$term_width")
((line_num++))
done < "$STATIC_TEMPLATE_FILE"
# Update the last terminal width
last_term_width=$term_width
fi
}
# Function to truncate a line while preserving the ANSI color codes
truncate_line() {
local line="$1"
local max_width="$2"
# Don't process empty lines
if [ -z "$line" ]; then
echo -n ""
return
fi
# Remove ANSI codes to get visible text length
local stripped=$(printf "%b" "$line" | sed 's/\x1b\[[0-9;]*m//g')
# Calculate visible length while also considering Unicode characters
local visible_length=$(printf "%b" "$stripped" | wc -m)
if [ "$visible_length" -le "$max_width" ]; then
# Line is already short so add terminal control to prevent wrapping
printf "%b\r" "$line"
else
# keep ANSI codes while truncating
local result=""
local current_length=0
local i=0
local char
local in_escape=0
local escape_sequence=""
while [ $current_length -lt "$max_width" ] && [ $i -lt ${#line} ]; do
char="${line:$i:1}"
if [ $in_escape -eq 1 ]; then
escape_sequence+="$char"
if [[ "$char" =~ [a-zA-Z] ]]; then
# End of escape sequence
result+="$escape_sequence"
escape_sequence=""
in_escape=0
fi
else
if [ "$char" = $'\e' ]; then
# Start of escape sequence
escape_sequence="$char"
in_escape=1
else
result+="$char"
((current_length++))
fi
fi
((i++))
done
# Add any remaining escape sequences
if [ -n "$escape_sequence" ]; then
result+="$escape_sequence"
fi
# Add reset code at the end for proper termination
result+="\033[0m"
# prevent wrapping
printf "%b\r" "$result"
fi
}
# Draw the static template
draw_static_template() {
# Process template first
process_template
# Clear screen and position cursor
tput clear
tput cup $top 0
# Print the buffer in one go(faster than one by line)
for line in "${template_buffer[@]}"; do
# Clear to end of line before printing to eliminate any potential artifacts
tput el
printf "%b\n" "$line"
done
}
resize_requested=false
resize_in_progress=false
resize_delay=0.2 # seconds
last_resize_time=0
on_resize() {
resize_requested=true
}
process_resize_if_needed() {
current_time=$(date +%s.%N)
# If we're already processing a resize, don't start working on another one
if [ "$resize_in_progress" = true ]; then
return
fi
if [ "$resize_requested" = false ]; then
return
fi
# Check if enough time has passed since last resize
if [ "$last_resize_time" != "0" ]; then
time_diff=$(echo "$current_time - $last_resize_time" | bc)
if (( $(echo "$time_diff < $resize_delay" | bc -l) )); then
# Not enough time has passed, wait more
return
fi
fi
# we can process
resize_in_progress=true
resize_requested=false
last_resize_time=$current_time
new_width=$(tput cols)
new_height=$(tput lines)
# calculate the new template
process_template
tput clear
tput cup $top 0
# Print buffer all at once with terminal control codes to prevent wrapping
for line in "${template_buffer[@]}"; do
# First clear to end of line to ensure no artifacts
tput el
printf "%b\n" "$line"
done
# Reset flag
resize_in_progress=false
}
# Trap the SIGWINCH signal (window size change)
trap 'on_resize' SIGWINCH
# Initial draw
draw_static_template
# Start audio if sound is provided
if [ -n "$soundname" ]; then
ffplay -nodisp -autoexit -loop 0 -loglevel quiet "$soundname" &
FFPLAY_PID=$! # store the PID of the last background process
fi
i=1
wanted_epoch=0
start_time=$(date +%s.%N)
while true; do
# Check for any key press (non-blocking)
if [ "$key_exit_enabled" = true ]; then
if read -t 0 -n 1 pressed_key; then
cleanup
fi
fi
for frame in $(ls "$FRAME_DIR" | sort -n); do
current_top=$top
while IFS= read -r line; do
tput cup "$current_top" "$left"
echo -ne "$line"
current_top=$((current_top + 1))
if [[ $current_top -gt $bottom ]]; then
break
fi
done < "$FRAME_DIR/$frame"
wanted_epoch=$(echo "$i/$framerate" | bc -l)
# current time in seconds (with fractional part)
now=$(date +%s.%N)
# Calculate how long to sleep to stay in sync
sleep_duration=$(echo "$wanted_epoch - ($now - $start_time)" | bc -l)
# Only sleep if ahead of schedule
if [ "$key_exit_enabled" = true ]; then
if (( $(echo "$sleep_duration > 0" | bc -l) )); then
# Check for key press during sleep
# If key pressed
if read -t "$sleep_duration" -n 1 pressed_key; then
cleanup
fi
fi
else
# If key-exit is not enabled, just sleep normally
if (( $(echo "$sleep_duration > 0" | bc -l) )); then
sleep "$sleep_duration"
fi
fi
i=$((i + 1))
process_resize_if_needed
done
sleep 0.005
done |
Added
-kflag: Enables exit upon any keypress. The key which is pressed is then passed to the terminal being used. This makes it much more pleasant to useanifetchon terminal startup.On Wayland systems (like my own setup), such as those using Hyprland,
wtypeis used to pass the keypress to the terminal. On X11 systems,xdotoolis used. Note that this functionality has not been tested on X11.Updated the README to reflect these changes.
I have changed the cursor repositioning to the end of the
anifetchoutput. In my case, the cursor was being placed at the bottom of my terminal. This is more desirable on my system, but I note it here as the change is unrelated to the core feature.I hope others find this feature useful!