hyprwm / Hyprland

Hyprland is an independent, highly customizable, dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
https://hyprland.org
BSD 3-Clause "New" or "Revised" License
20.65k stars 875 forks source link

hyprctl switchxkblayout followed by wtype behaves in a strange way #6589

Open izvyk opened 3 months ago

izvyk commented 3 months ago

Regression?

Yes

System Info and Version

System/Version info ```sh Hyprland, built from branch at commit 9e781040d9067c2711ec2e9f5b47b76ef70762b3 (props: bump version to 0.41.1). Date: Thu Jun 13 09:54:06 2024 Tag: v0.41.1, commits: 4818 flags: (if any) System Information: System name: Linux Node name: NotPC Release: 6.9.5-arch1-1 Version: #1 SMP PREEMPT_DYNAMIC Sun, 16 Jun 2024 19:06:37 +0000 GPU information: 03:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Renoir [Radeon Vega Series / Radeon Vega Mobile Series] [1002:1636] (rev ce) (prog-if 00 [VGA controller]) os-release: NAME="Arch Linux" PRETTY_NAME="Arch Linux" ID=arch BUILD_ID=rolling ANSI_COLOR="38;2;23;147;209" HOME_URL="https://archlinux.org/" DOCUMENTATION_URL="https://wiki.archlinux.org/" SUPPORT_URL="https://bbs.archlinux.org/" BUG_REPORT_URL="https://gitlab.archlinux.org/groups/archlinux/-/issues" PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/" LOGO=archlinux-logo plugins: ======Config-Start====== Config File: /home/izvyk/.config//hypr/hyprland.conf: Read Succeeded monitor=,preferred,auto,auto exec-once = dbus-update-activation-environment --systemd --all # exec-once = dbus-update-activation-environment --systemd SSH_ASKPASS=/usr/bin/ksshaskpass exec-once = swww-daemon exec-once = wl-gammarelay-rs run >/dev/null exec-once = ~/.local/bin/wl-temp & exec-once = hyprctl setcursor Bibata-Gruvbox 24 exec-once = waybar & exec-once = /usr/lib/polkit-kde-authentication-agent-1 exec-once = foot --server exec-once = swaync exec-once = wl-paste --type text --watch sh -c '~/.local/bin/clipboard-private.sh || cliphist store -max-items 100' #Stores only text data exec-once = wl-paste --type image --watch sh -c '~/.local/bin/clipboard-private.sh || cliphist store -max-items 100' #Stores only image data exec-once = playerctld daemon exec-once = udiskie --tray & exec-once = /usr/lib/geoclue-2.0/demos/agent exec-once = systemctl --user start weather-update.service & exec-once = kdeconnectd exec-once = kdeconnect-indicator & exec-once = sleep 1 && keepassxc & # Source a file (multi-file configs) # source = ~/.config/hypr/myColors.conf input { kb_layout = us, ru kb_variant = izvyk,izvyk kb_options = grp:win_space_toggle,grp_led:caps,ctrl:swap_lalt_lctl,caps:escape_shifted_capslock follow_mouse = 1 touchpad { natural_scroll = yes middle_button_emulation = yes scroll_factor = 0.7 # tap-and-drag = yes drag_lock = yes } # accel_profile = custom 0.2144477506 0.000 0.280 0.560 0.980 1.401 1.823 2.281 2.921 3.561 4.200 4.840 5.480 6.119 6.759 7.399 8.038 8.678 9.318 9.957 11.279 # accel_profile = custom 0.09 0.000 0.034 0.067 0.118 0.168 0.219 0.274 0.351 0.427 0.504 0.581 0.658 0.734 0.811 0.888 0.965 1.041 1.118 1.195 1.354 accel_profile = custom 0.1 0.000 0.045 0.090 0.157 0.224 0.292 0.365 0.467 0.570 0.672 0.774 0.877 0.979 1.081 1.184 1.286 1.388 1.491 1.593 1.805 scroll_points = 0.1 0.000 0.045 0.090 0.157 0.224 0.292 0.365 0.467 0.570 0.672 0.774 0.877 0.979 1.081 1.184 1.286 1.388 1.491 1.593 1.805 # scroll_points = 0.2144477506 0.000 0.280 0.560 0.980 1.401 1.823 2.281 2.921 3.561 4.200 4.840 5.480 6.119 6.759 7.399 8.038 8.678 9.318 9.957 11.279 sensitivity = 0.05 # -1.0 - 1.0, 0 means no modification. } general { gaps_in = 3 gaps_out = 3 border_size = 2 # col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg # col.active_border = rgb(fbf1c7) rgb(d79921) 100deg col.active_border = rgb(fbf1c7) col.inactive_border = rgba(458588bb) layout = dwindle #layout = scroller } #Could help when scaling and not pixelating xwayland { force_zero_scaling = true } windowrulev2 = bordersize 5px,xwayland:1 windowrulev2 = bordercolor rgb(FF0000),xwayland:1 decoration { rounding = 5 blur { popups = true passes = 2 } drop_shadow = no #dim_inactive = yes #dim_strength = 0.25 } animations { enabled = yes #bezier = inactive_dimmer,0.3,0.4,0.6,0.7 #bezier = myBezier, 0.05, 0.9, 0.1, 1.05 animation = windows, 1, 7, default #myBezier animation = windowsOut, 1, 7, default, popin 80% animation = border, 1, 10, default animation = borderangle, 1, 8, default animation = fade, 1, 7, default #animation = fadeDim,1,5,inactive_dimmer animation = workspaces, 1, 6, default } dwindle { pseudotile = yes # master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below preserve_split = yes # you probably want this no_gaps_when_only = yes } master { new_is_master = true } # gestures { # workspace_swipe = on # workspace_swipe_forever = on # } misc { disable_hyprland_logo = yes disable_splash_rendering = yes animate_manual_resizes = yes key_press_enables_dpms = yes mouse_move_enables_dpms = no vrr = 1 focus_on_activate = yes enable_swallow = yes swallow_regex = ^(foot|footclient)$ new_window_takes_over_fullscreen = 2 font_family = Iosevka } cursor { no_warps = true } $mainMod = SUPER bind = $mainMod, return, execr, footclient bind = Alt, return, execr, if !(hyprctl -j clients | gojq -e ".[] | select(.workspace.id == $(hyprctl activeworkspace -j | gojq '.id')) | select (.class == \"terminaloverlay\")" > /dev/null); then foot --override=app-id=terminaloverlay --override=colors.alpha=0.7; fi bind = $mainMod, Q, killactive, bind = $mainMod, W, execr, firefox bind = Control&Alt, Delete, exit, bind = $mainMod, E, execr, nautilus bind = $mainMod, X, togglefloating, bind = $mainMod, R, execr, rofi -show drun bind = $mainMod, Delete, execr, ~/.config/rofi/powermenu/powermenu.sh bind = $mainMod, P, pseudo, # dwindle bind = $mainMod, J, togglesplit, # dwindle bind = $mainMod, F, fullscreen, bind = ALT, F, fakefullscreen, bind = $mainMod, K, execr, killall waybar; waybar bind = $mainMod, L, execr, loginctl lock-session # Move focus with mainMod + arrow keys bind = $mainMod, left, movefocus, l bind = $mainMod, right, movefocus, r bind = $mainMod, up, movefocus, u bind = $mainMod, down, movefocus, d # Switch workspaces with mainMod + [0-9] bind = $mainMod, 1, workspace, 1 bind = $mainMod, 2, workspace, 2 bind = $mainMod, 3, workspace, 3 bind = $mainMod, 4, workspace, 4 bind = $mainMod, 5, workspace, 5 bind = $mainMod, 6, workspace, 6 bind = $mainMod, 7, workspace, 7 bind = $mainMod, 8, workspace, 8 bind = $mainMod, 9, workspace, 9 bind = $mainMod, 0, workspace, 10 # Move active window to a workspace with mainMod + SHIFT + [0-9] bind = $mainMod SHIFT, 1, movetoworkspace, 1 bind = $mainMod SHIFT, 2, movetoworkspace, 2 bind = $mainMod SHIFT, 3, movetoworkspace, 3 bind = $mainMod SHIFT, 4, movetoworkspace, 4 bind = $mainMod SHIFT, 5, movetoworkspace, 5 bind = $mainMod SHIFT, 6, movetoworkspace, 6 bind = $mainMod SHIFT, 7, movetoworkspace, 7 bind = $mainMod SHIFT, 8, movetoworkspace, 8 bind = $mainMod SHIFT, 9, movetoworkspace, 9 bind = $mainMod SHIFT, 0, movetoworkspace, 10 # Scroll through existing workspaces with mainMod + scroll bind = $mainMod, mouse_down, workspace, e+1 bind = $mainMod, mouse_up, workspace, e-1 # Move/resize windows with mainMod + LMB/RMB and dragging bindm = $mainMod, mouse:272, movewindow bindm = $mainMod, mouse:273, resizewindow bindm = $mainMod CTRL, mouse:272, resizewindow binde = $mainMod CTRL, left, resizeactive, -20 0 binde = $mainMod CTRL, right, resizeactive, 20 0 binde = $mainMod CTRL, up, resizeactive, 0 -20 binde = $mainMod CTRL, down, resizeactive, 0 20 binde = ,xf86monbrightnessup,execr,~/.local/bin/brightness-up binde = ,xf86monbrightnessdown,execr,~/.local/bin/brightness-down binde = ,XF86AudioLowerVolume,execr,~/.local/bin/volume-down binde = ,XF86AudioRaiseVolume,execr,~/.local/bin/volume-up bind = ,XF86AudioMute,execr,amixer set Master toggle -q bind = ,XF86AudioMicMute,execr,amixer set Capture toggle -q bind = $mainMod,L,execr,loginctl lock-session bind = $mainMod,F7,execr,bash -c '(("$(hyprctl monitors | grep dpmsStatus | cut -c 14)")) && hyprctl dispatch dpms off eDP-1 > /dev/null || hyprctl dispatch dpms on eDP-1 > /dev/null' bind = ,XF86AudioPlay,execr,playerctl play-pause bind = ,XF86AudioPrev,execr,playerctl previous bind = ,XF86AudioNext,execr,playerctl next bind = ,XF86AudioStop,execr,playerctl stop #bind = ,XF86RFKill,exec, #bind = ,XF86Calculator,exec, #bind = ,XF86Favorites,exec, bind = ,Print,execr,[ -n "$(pidof slurp)$(pidof swappy)" ] && exit || grim -g "$(slurp)" - | swappy -f - bind = $mainMod,V,execr,rofi -modi Clipboard:~/.config/rofi/cliphist-rofi-img.sh -show Clipboard -show-icons bind = $mainMod,C,execr,hyprpicker --autocopy bind = $mainMod,T,execr,grim -g "$(slurp)" - | magick - -auto-level -normalize -enhance -sharpen 0x1 -resize 200% - | tesseract - - -l rus+eng+deu quiet | wl-copy # bind = CTRL, Tab, execr, ~/.local/bin/alttab.sh # Text keyboard layout switcher bind = , Insert, execr, wl-paste -np | ~/.local/bin/switch.py | wtype - # bind = , Insert, execr, ~/test.sh # Set random wallpaper with swww bind = $mainMod Ctrl, W, execr, ~/.config/hypr/scripts/change-wallpaper.sh # screen off bindl = Alt, Delete, execr, systemctl --user start screen-off.target bindl = Alt, Delete, submap, screenoff submap = screenoff bindl = ,catchall, execr, hyprctl dispatch submap reset; systemctl --user stop screen-off.target submap = reset # Passthrough submap bind = Alt, P, submap, passthrough submap = passthrough bind = Alt, Escape, submap, reset submap = reset windowrulev2 = nodim,class:firefox,title:Picture-in-Picture windowrulev2 = float,class:firefox,title:Picture-in-Picture windowrulev2 = pin,class:firefox,title:Picture-in-Picture windowrulev2 = keepaspectratio,class:firefox,title:Picture-in-Picture # windowrulev2 = nofocus,class:firefox,title:Picture-in-Picture windowrulev2 = float,class:xdg-desktop-portal windowrulev2 = size 80%,class:xdg-desktop-portal windowrulev2 = dimaround,class:xdg-desktop-portal windowrulev2 = center,class:xdg-desktop-portal windowrulev2 = stayfocused,class:xdg-desktop-portal windowrulev2 = float,initialClass:org.gnome.NautilusPreviewer windowrulev2 = size 80%,initialClass:org.gnome.NautilusPreviewer windowrulev2 = dimaround,initialClass:org.gnome.NautilusPreviewer windowrulev2 = center,initialClass:org.gnome.NautilusPreviewer windowrulev2 = stayfocused,initialClass:org.gnome.NautilusPreviewer windowrulev2 = float,class:swappy windowrulev2 = pin,class:swappy windowrulev2 = dimaround,class:swappy windowrulev2 = center,class:swappy windowrulev2 = stayfocused,class:swappy windowrulev2 = float,class:scrcpy windowrulev2 = float,class:^(waybarnmtui)$ windowrulev2 = dimaround,class:^(waybarnmtui)$ windowrulev2 = center,class:^(waybarnmtui)$ windowrulev2 = float,class:^(footclient)$,title:bluetoothmenu windowrulev2 = dimaround,class:^(footclient)$,title:bluetoothmenu windowrulev2 = size 70%,class:^(footclient)$,title:bluetoothmenu windowrulev2 = center,class:^(footclient)$,title:bluetoothmenu windowrulev2 = dimaround,class:org.kde.ark,title:(Create New*) windowrulev2 = float,class:pavucontrol windowrulev2 = dimaround,class:pavucontrol windowrulev2 = size 70%,class:pavucontrol windowrulev2 = center,class:pavucontrol windowrulev2 = float,initialClass:^(org.keepassxc.KeePassXC)$,title:^(((Unlock)(.*))|KeePassXC - Browser Access Request|Generate Password|Setup TOTP|Download Favicons)$ windowrulev2 = dimaround,initialClass:^(org.keepassxc.KeePassXC)$,title:^(((Unlock)(.*))|KeePassXC - Browser Access Request|Generate Password|Setup TOTP|Download Favicons)$ windowrulev2 = size 70%,initialClass:^(org.keepassxc.KeePassXC)$,title:^(Unlock)(.*)$ windowrulev2 = center,initialClass:^(org.keepassxc.KeePassXC)$,title:^(((Unlock)(.*))|Generate Password|Setup TOTP|Download Favicons)$ windowrulev2 = float,class:firefox,title:Firefox — Sharing Indicator windowrulev2 = pin,class:firefox,title:Firefox — Sharing Indicator windowrulev2 = noborder,class:firefox,title:Firefox — Sharing Indicator #windowrulev2 = opacity 0.8 override 0.5 override,class:firefox,title:Firefox — Sharing Indicator windowrulev2 = float,class:terminaloverlay windowrulev2 = size 90% 80%,class:terminaloverlay windowrulev2 = dimaround,class:terminaloverlay windowrulev2 = stayfocused,class:terminaloverlay windowrulev2 = center 1,class:terminaloverlay #windowrulev2 = pin,class:terminaloverlay windowrulev2 = float,initialClass:org.kde.ksshaskpass windowrulev2 = dimaround,initialClass:org.kde.ksshaskpass windowrulev2 = stayfocused,initialClass:org.kde.ksshaskpass # Screen sharing dialog windowrulev2 = float,initialClass:hyprland-share-picker windowrulev2 = dimaround,initialClass:hyprland-share-picker # windowrulev2 = stayfocused,initialClass:hyprland-share-picker layerrule = blur,rofi layerrule = ignorezero,rofi layerrule = dimaround,rofi # layerrule = animation slide,rofi layerrule = blur,swaync-control-center layerrule = ignorezero,swaync-control-center # layerrule = animation slide right,swaync-control-center #layerrule = dimaround,swaync-control-center layerrule = blur,waybar layerrule = ignorezero,waybar layerrule = animation slide,waybar group { groupbar { render_titles = false height = 3 } } # Groups bind = $mainMod, G,togglegroup bind = $mainMod, Tab, changegroupactive, f bind = $mainMod, Shift Tab, changegroupactive, b ======Config-End======== ```

Description

I have two keyboard layouts (en and ru). Sometimes I start typing with a wrong layout, so I have a script that retypes the text in another layout with wtype and switches the layout with hyprctl switchxkblayout. It worked just fine until a resent update.

Now when I press the shortcut to run the script, the layout does not switch until I refocus the window or press a modifier. Hyprctl immediately reports the layout is switched though.

I tried to bisect but I am struggling with a compilation of any version before 098ac916 which updated wlroots. With some help I could finish this. For now I know v0.40.0 is a good commit, while 098ac916 is bad already.

This is what I found out:

How to reproduce

First of all, you need two xkb layouts. Then:

  1. Bind the affixed script to a non-mod key (take a look at a minimal Hyprland config below).
  2. Open an app you can type text into.
  3. Start typing Latin characters, then press the shortcut to run the switcher script. Continue typing something. You will notice that Latin characters are typed despite of layout being switched. (Take a look at a screenshot for reference. I was pressing Latin a key, which has ф in Cyrillic layout. 123 is typed with a script, so the next characters should be ф with Cyrillic layout, not a).

Crash reports, logs, images, videos

bug

Sorry, GitHub rejects other file types so I had to add .txt extension.

hyprland.conf.txt test.sh.txt

MahouShoujoMivutilde commented 1 week ago

Seems to be still present on 58669fef77ac17ea205ce3570f48e17de736111f.

I don't see any major difference in wlr_keyboard_notify_modifiers (the thing that should fire when you press the mod keys) usage between v0.40.0 and 098ac916, nor was it itself changed in recent years in wlroots (more modern hyprland has updateModifiers() which does the same thing).

But, clearly, despite the group (your layout) being changed, wtype's creating a virtual keyboard, typing for you, and then immediately removing it messes with things.

activelayout>>hl-virtual-keyboard,English (US)
activelayout>>hl-virtual-keyboard,none
activelayout>>logitech-usb-keyboard,Russian
activelayout>>hl-virtual-keyboard,error

But I can reframe the issue:

Effective active layout being reset to us on your current keyboard when any other keyboard is removed or attached (physical (tested) or virtual like wtype). And you can press any mod key and have it switch back to what you had.

It also seems like you can't have two keyboards with the same kb_layout, but different layout currently selected. Let's say, on kbd_1 you select ru and type фффф, then pick up kbd_2 (that was on us) and type something with latin letters, then pick kbd_1. You'd expect it to keep being on ru, but effective layout silently switched to us without any event being emitted. Press mod keys and it restores itself, again.

Anyway, here is a dirty workaround (works on 58669fef77ac17ea205ce3570f48e17de736111f):

#!/usr/bin/sh

kbd="your-keyboard"
# or
# kbd="$(hyprctl devices -j | jq -r '.keyboards | .[] | select(.main == true) | .name')"

wl-paste -np | /tmp/switch.py | wtype -

# a hack to force updateModifiers() to do it's job
hyprctl switchxkblayout $kbd prev
hyprctl switchxkblayout $kbd next

I didn't investigate it for a proper fix.

Regarding bisecting - maybe you forgot git reset --hard --recurse-submodules after every HEAD switch to a new commit, before rebuilding? Or maybe modules aren't even initialized (git submodule update --init in existing repo or clone the repo with --recursive to being with)?

Roughly, what I think should happen to fix it, is in some place updateModifiers() should be called with different values of its arguments than it currently is called with, distinct from the current modifiersState values, so that it passes the updateModifiersState()'s check it, and emits the event for changed modifiers, like it apparently used to do on 0.40.0.