SL5net
SL5net

Reputation: 2566

KDE: Bash script not detecting Shift + Left Click for custom window resizing

I am trying to create a script in KDE (Plasma) that allows me to resize a window by holding down the Shift key and left-clicking, and dragging with the mouse. The resizing should be centered around the initial mouse position (the position of the mouse when the Shift key and left mouse button are first pressed). The goal is to have a smooth, damped resizing effect that works regardless of where I click within the window, not just on the edges. The default KDE window resizing behavior doesn't allow for this level of control.

Current Approach:

I am using a bash script to achieve this, using xdotool for window management and xinput for keyboard monitoring. The script is designed to:

  1. Continuously monitor for the Shift key press.
  2. When Shift is pressed, check if the left mouse button is also pressed.
  3. If both conditions are met, get the active window ID, initial geometry, and mouse position.
  4. Enter a loop that continues as long as the left mouse button is held down.
  5. Within the loop, calculate the new window size and position based on the mouse movement and a damping factor.
  6. Use xdotool to resize and move the window.

Result at the moment:

sudo ~/scripts/dynamic-resize.sh
Setting up watches.
Watches established.

Code:

#!/bin/bash

# xinput must be installed:
#    Debian: sudo apt-get install xinput
#    Fedora: sudo dnf install xorg-x11-utils oder sudo yum install xorg-x11-utils
#    Arch: sudo pacman -S inotify-tools

# Configuration
modifier_key="Shift"  # or "Alt", "Control", etc.
mouse_button_code="1" #Code for the leftmouse click.
resize_button="3"      # 1=links, 2=mitte, 3=rechts #We aren't using this anymore.
damping_factor="0.2"   # Damping factor
threshold="400"        # Threshold for dynamic damping
sleep_time="0.02"      # Sleep time after each movement (in seconds)
event_mouse="3"
event_keyboard="2"

# Function: Dynamically resize window
resize_window() {
  # 1. Get active window ID
  active_window_id=$(xdotool getactivewindow)

  # 2. Get initial window geometry
  initial_x=$(xdotool getwindowgeometry $active_window_id | awk '{print $4}' | cut -d, -f1)
  initial_y=$(xdotool getwindowgeometry $active_window_id | awk '{print $4}' | cut -d, -f2)
  initial_width=$(xdotool getwindowgeometry $active_window_id | awk '{print $5}' | cut -d, -f1)
  initial_height=$(xdotool getwindowgeometry $active_window_id | awk '{print $5}' | cut -d, -f2)

  # 3. Get initial mouse position
  initial_mouse_x=$(xdotool getmouselocation | awk -F ":" '{print $2}' | awk '{print $1}')
  initial_mouse_y=$(xdotool getmouselocation | awk -F ":" '{print $4}' | awk '{print $1}')

  # 4. Loop: As long as the mouse button is pressed
  while is_mouse_button_pressed; do
      # 5. Get current mouse position
    current_mouse_x=$(xdotool getmouselocation | awk -F ":" '{print $2}' | awk '{print $1}')
    current_mouse_y=$(xdotool getmouselocation | awk -F ":" '{print $4}' | awk '{print $1}')

    # 6. Calculate difference
    diff_x=$((current_mouse_x - initial_mouse_x))
    diff_y=$((current_mouse_y - initial_mouse_y))

    # 7. Calculate dynamic damping factor
    if [ $(abs $diff_x) -lt $threshold ]; then
      damping_factor_x=$((damping_factor * (abs $diff_x) / $threshold + 0.1))
    else
      damping_factor_x=$damping_factor
    fi

    if [ $(abs $diff_y) -lt $threshold ]; then
      damping_factor_y=$((damping_factor * (abs $diff_y) / $threshold + 0.1))
    else
      damping_factor_y=$damping_factor
    fi

    # 8. Calculate new size and position
    new_width=$((initial_width + diff_x * damping_factor_x))
    new_height=$((initial_height + diff_y * damping_factor_y))
    new_x=$((initial_x - diff_x * damping_factor_x / 2))
    new_y=$((initial_y - diff_y * damping_factor_y / 2))

    # 9. Size restrictions (minimum, maximum, etc.)
    new_width=$((new_width < 100 ? 100 : new_width))
    new_height=$((new_height < 100 ? 100 : new_height))

    # 10. Change window size and position
    xdotool windowsize $active_window_id $new_width $new_height
    xdotool windowmove $active_window_id $new_x $new_y

    # 11. Short pause to reduce CPU load
    sleep $sleep_time
  done
}

# Returns 0 if mouse is not being left-clicked, and 1 if it is.
is_mouse_button_pressed() {
    #Returns 0 if shift is not pressed
    if ! is_shift_pressed; then
        #echo "shift is not pressed"
        return 1;
    fi
    #echo "shift is pressed, now checking mouse"
    xinput test $event_mouse | grep -q "button\[$mouse_button_code\]=down"
    mouse_result=$?
    #echo "mouse_result=$mouse_result"
    return $mouse_result
}
# Return 0 if shift is not pressed.
is_shift_pressed() {
    xinput query-state "HID 045e:000b" | grep -q "key\[62\]=down"
}
    # Hauptteil des Skripts
while true; do
        # Überprüfen, ob die Super-Taste gedrückt ist
        if is_shift_pressed; then
            # Funktion aufrufen
            resize_window
        fi
done

What I've Tried:

Specific Questions:

  1. How can I get this bash script to reliably and continuously detect when both the Shift key is held down and the left mouse button is pressed, so that the resizing logic is triggered? The current approach with xinput test and xinput query-state is not working.
  2. Am I approaching this problem in the wrong way? Is a bash script fundamentally unsuited for this type of real-time input monitoring in KDE?
  3. If a bash script is not the right approach, what alternative technologies (e.g., Python, KWin scripts, other tools) would be more appropriate and effective for the task?
  4. Is there a solution for the point-symmetric resizing behavior?

Upvotes: 0

Views: 27

Answers (0)

Related Questions