← 返回首页

GNOME Wayland 全局快捷键模糊搜目录、Nautilus 打开:fuzzel/rofi 抓不到键盘,最后用 Ptyxis+fzf

2026-06-03 · LinuxGNOMEWaylandfzfNautilus

环境: Ubuntu 26.04、GNOME(Wayland 会话)、Mutter 合成器、默认终端 Ptyxis、文件管理器 Nautilus,分数缩放 167%。fzf 由 source <(fzf --zsh) 提供,终端里 Alt+C 已能模糊搜目录并 cd

终端里 fzf 的 Alt+C 很顺手:模糊搜当前目录下的子目录,回车就 cd 进去。自然就想要一个桌面级的等价物——在任何地方按一个全局快捷键,弹出模糊选择器从主目录 $HOME 往下找目录,选中后直接用 Nautilus 打开(而不是 cd)。

听上去十分钟的事。实际在 GNOME Wayland 上连撞两堵墙,记录一下,免得别人(和未来的我)重踩。

目标拆解

桌面级触发,跟终端无关,所以分两半:

  1. 一个模糊选择器:列出 $HOME 下所有目录,让我打字过滤、选一个。
  2. 把选中的目录交给 Nautilus 打开。
  3. GNOME 全局快捷键(比如 Super+E)把整件事串起来。

第 2、3 步都好办。难的全在第 1 步:在 GNOME Wayland 上找一个能用的 dmenu 式 GUI 模糊选择器。

第一条死路:fuzzel —— Mutter 不支持 layer-shell

fuzzel 是 Wayland 原生的轻量 dmenu 启动器,看着是首选。装上,把目录列表喂给它:

fdfind --type d --hidden --exclude .git --exclude .cache --exclude node_modules . "$HOME" \
  | fuzzel --dmenu --prompt 'dir❯ '

窗口没弹出来,直接报错:

err: wayland.c:2321: compositor is missing support for the Wayland layer surface protocol
err: fdm.c:133: no such FD: 7

根因:fuzzel(以及 wofi、tofi、rofi-wayland 等一票 Wayland 原生菜单)靠 wlr-layer-shell 协议把自己叠在屏幕最上层。这个协议是 wlroots 系合成器(sway、Hyprland)的东西,GNOME 的 Mutter 从不实现它。在 GNOME 上,这些工具一个都起不来。

第二条死路:rofi —— 走 XWayland 弹出来却抓不到键盘

那退一步用老牌的 rofi?Ubuntu 26.04 的 rofi 包已经是 Wayland 原生构建,同样要 layer-shell:

$ printf 'a\nb\nc\n' | rofi -dmenu -matching fuzzy
(process:177616): Wayland-ERROR **: Rofi on wayland requires support for the layer shell protocol

但 rofi 还带 X11 后端。清掉 WAYLAND_DISPLAY,逼它走 XWayland:

printf 'a\nb\nc\n' | env -u WAYLAND_DISPLAY rofi -dmenu -matching fuzzy

这次窗口确实弹出来了(XWayland 在 GNOME 下是现成的),没有报错。看着像成了——直到你开始打字:

光标在 rofi 里闪,但敲的字一个都进不去,全跑到背后那个原来有焦点的窗口里了。

这是 XWayland 应用在 GNOME Wayland 下的经典毛病:rofi 想做键盘 grab(独占抓取),而 Mutter 不给 XWayland 客户端这种全局抓取。窗口画出来了,却拿不到键盘输入。对一个"靠打字过滤"的选择器来说,等于废了。

结论:GNOME Wayland 上 dmenu 式 GUI 选择器基本没戏

把两条路并一起看,结论很干脆:

方案结果原因
fuzzel / wofi / tofi / rofi-wayland起不来wlr-layer-shell,Mutter 不支持
rofi(X11)/ dmenu 走 XWayland弹得出、打不进字Mutter 不给 XWayland 键盘 grab

想在 GNOME Wayland 上要一个"悬浮的、能打字过滤的 GUI 菜单",原生这条路目前是堵死的。

那就别跟它较劲。一个普通的终端窗口,是能正常拿到键盘焦点的——那就在终端窗口里跑 fzf,跟我本来就喜欢的 Alt+C 同款手感,只是结尾换成开 Nautilus。

可行方案:开一个终端窗口跑 fzf

思路两段式:

用当前默认终端 Ptyxis 就行,它支持 ptyxis --new-window -- 命令

启动器 ~/.local/bin/nautilus-fuzzy-dir.sh:

#!/usr/bin/env bash
# 全局快捷键入口:开一个 Ptyxis 新窗口跑 fzf 选择器。
# (GNOME/Mutter 不支持 layer-shell,fuzzel/rofi 等 GUI 选择器无法抓键盘,
#  故走终端窗口内的 fzf —— 与 Alt+C 同款体验。)
exec ptyxis --new-window -T "模糊搜目录 → Nautilus" \
  -- "$HOME/.local/bin/nautilus-fuzzy-pick.sh"

用别的终端也一样:ghostty 是 ghostty -e 命令,gnome-terminal/kgx 是 -- 命令。挑你顺手、字体锐利的那个即可。

选择器脚本,以及 Nautilus 打不开的坑

第一版选择器很直白:fd 列目录 → fzf 选 → nautilus "$sel"。结果选完回车,Nautilus 没弹窗

问题出在生命周期。fzf 一退出,选择器脚本也就跑完,Ptyxis 立刻关掉这个窗口,给整个进程组发 SIGHUP——刚被拉起来的 Nautilus 子进程还没把"开窗"的 D-Bus 请求发完,就被一起收走了。

两处一起改才稳:

  1. setsid 把 Nautilus 拉进新会话,脱离 Ptyxis 那棵进程树,关窗的 SIGHUP 打不到它。
  2. gio open 而不是 nautilus 路径——前者走 D-Bus 让已有的 Nautilus 服务开窗,最稳;再 sleep 1 给请求一点发出去的时间。

选择器 ~/.local/bin/nautilus-fuzzy-pick.sh:

#!/usr/bin/env bash
# 在终端窗口内运行:fzf 模糊搜 $HOME 下的目录,选中后用 nautilus 打开。
set -uo pipefail

# 列目录:优先 fd/fdfind(快、自动忽略 .git/gitignore),否则 find + prune
if command -v fd >/dev/null 2>&1; then
  FD=fd
elif command -v fdfind >/dev/null 2>&1; then
  FD=fdfind
else
  FD=""
fi

if [ -n "$FD" ]; then
  list=$("$FD" --type d --hidden \
    --exclude .git --exclude .cache --exclude node_modules \
    . "$HOME")
else
  list=$(find "$HOME" \
    \( -type d -name .git -o -type d -name .cache -o -type d -name node_modules \) -prune -o \
    -type d -print)
fi

# fzf 在终端窗口内交互;Esc/Ctrl-C 取消 → 退出码非 0 → 静默退出
sel=$(printf '%s\n' "$list" | fzf --prompt 'dir❯ ' --reverse --height 100% \
        --header '回车=用 nautilus 打开  Esc=取消') || exit 0
[ -z "$sel" ] && exit 0

# setsid 脱离会话后台运行,避免 ptyxis 关窗时 SIGHUP 打断;
# gio open 走 D-Bus 让 Nautilus 开窗;sleep 1 给请求发出去的时间。
setsid gio open "$sel" >/dev/null 2>&1 < /dev/null &
sleep 1
exit 0

两个脚本都记得 chmod +x

fdfind 是 Ubuntu 上 fd-find 包的二进制名(不叫 fd)。脚本两个名都探测,装不装都能跑,不装则回退到 find 并 prune 掉 .cache/.git/node_modules--hidden 会把一堆隐藏配置目录也列进来,嫌杂就去掉它,只搜可见目录。

绑定 GNOME 全局快捷键

最后用 gsettings 在第一个自定义槽 custom0 上建一条快捷键,指向启动器。这里用 Super+E(“E for Explorer”,Win 键即 Super):

KEY=/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/
gsettings set org.gnome.settings-daemon.plugins.media-keys custom-keybindings "['$KEY']"
gsettings set "org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:$KEY" \
  name 'Fuzzy dir → Nautilus'
gsettings set "org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:$KEY" \
  command "$HOME/.local/bin/nautilus-fuzzy-dir.sh"
gsettings set "org.gnome.settings-daemon.plugins.media-keys.custom-keybinding:$KEY" \
  binding '<Super>e'

注意第二行是直接把 custom-keybindings 覆盖成单元素列表。如果你已经有别的自定义快捷键,先 gsettings get 出来,把新路径追加进去,别覆盖。槽位也相应换成 custom1custom2……

按下 Super+E:Ptyxis 弹出一个小窗,里面是 fzf 列表;打字过滤、回车,窗口关闭、Nautilus 在选中目录开窗。和终端的 Alt+C 同一套手感,只是落点从"cd"变成了"文件管理器"。

Super+E 没反应,多半是被系统占用了——去「设置 → 键盘 → 查看及自定义快捷键」里换个键,或改上面 binding 那行(比如 '<Super><Shift>F')。

小结

绕了一圈,最朴素的方案反而最稳:别跟合成器抢悬浮窗,开个终端窗口就完事。