1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
#!/usr/bin/env bash
# /* ---- 💫 https://github.com/JaKooLit 💫 ---- */ ##
# searchable enabled keybinds using rofi (supports bindd descriptions)
# kill yad to not interfere with this binds
pkill yad || true
# check if rofi is already running
if pidof rofi > /dev/null; then
pkill rofi
fi
# define the config files
keybinds_conf="$HOME/.config/hypr/configs/Keybinds.conf"
user_keybinds_conf="$HOME/.config/hypr/UserConfigs/UserKeybinds.conf"
laptop_conf="$HOME/.config/hypr/UserConfigs/Laptops.conf"
rofi_theme="$HOME/.config/rofi/config-keybinds.rasi"
msg='☣️ NOTE ☣️: Clicking with Mouse or Pressing ENTER will have NO function'
# collect raw bind lines (strip end-of-line comments) from available files
files=("$keybinds_conf" "$user_keybinds_conf")
[[ -f "$laptop_conf" ]] && files+=("$laptop_conf")
# Parse binds/unbinds from files, detect overrides, and keep unique effective binds
declare -A binding_map # combo -> bind line (effective)
declare -A source_map # combo -> source file
declare -A user_bind_map # combo -> user bind line
declare -A unbound_user # combo -> 1 if explicitly unbound in user file
declare -A seen_any_bind # combo -> 1 if any bind seen (for iteration)
declare -A default_seen # combo -> 1 if default bind exists
declare -a missing_unbind_suggestions_arr
normalize_combo() { echo "$1" | sed -E 's/[[:space:]]//g'; }
extract_combo() {
# arg: a bind/unbind line; returns "mods,key" via echo
local s="$1"
s="$(echo "$s" | sed -E 's/[[:space:]]+#.*$//')"
if [[ "$s" =~ = ]]; then
local rhs="${s#*=}"
local mods="$(echo "$rhs" | awk -F',' '{gsub(/^[ \t]+|[ \t]+$/,"",$1); print $1}')"
local key="$(echo "$rhs" | awk -F',' '{gsub(/^[ \t]+|[ \t]+$/,"",$2); print $2}')"
echo "${mods},${key}"
fi
}
for file in "${files[@]}"; do
[[ ! -f "$file" ]] && continue
while IFS= read -r line; do
[[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
if [[ "$line" =~ ^[[:space:]]*bind[a-z]*[[:space:]]*= ]]; then
combo_raw="$(extract_combo "$line")"
[[ -z "$combo_raw" ]] && continue
combo="$(normalize_combo "$combo_raw")"
seen_any_bind["$combo"]=1
if [[ "$file" != "$user_keybinds_conf" ]]; then
default_seen["$combo"]=1
fi
# prefer user bind, else first seen
if [[ -z "${source_map[$combo]}" ]]; then
binding_map["$combo"]="$line"
source_map["$combo"]="$file"
fi
if [[ "$file" == "$user_keybinds_conf" ]]; then
user_bind_map["$combo"]="$line"
binding_map["$combo"]="$line"
source_map["$combo"]="$file"
fi
elif [[ "$line" =~ ^[[:space:]]*unbind[[:space:]]*= ]]; then
combo_raw="$(extract_combo "$line")"
[[ -z "$combo_raw" ]] && continue
combo="$(normalize_combo "$combo_raw")"
if [[ "$file" == "$user_keybinds_conf" ]]; then
unbound_user["$combo"]=1
fi
fi
done < "$file"
done
# Build raw_keybinds for display and collect missing unbind suggestions
raw_keybinds=""
for combo in "${!seen_any_bind[@]}"; do
eff_line="${binding_map[$combo]}"
src="${source_map[$combo]}"
[[ -z "$eff_line" ]] && continue
raw_keybinds+="$eff_line"$'\n'
# If user overrides a default but didn't unbind in user file, suggest unbind
if [[ "$src" == "$user_keybinds_conf" && -n "${default_seen[$combo]}" && -z "${unbound_user[$combo]}" ]]; then
suggest="$(echo "$eff_line" | sed -E 's/^[[:space:]]*bind[a-z]*/unbind/')"
missing_unbind_suggestions_arr+=("$suggest")
fi
done
# If there are missing unbinds, write suggestions to a temp file and note in message
if (( ${#missing_unbind_suggestions_arr[@]} > 0 )); then
suggestions_file="$(mktemp -t hypr-unbind-suggestions.XXXX.conf)"
printf '%s\n' "${missing_unbind_suggestions_arr[@]}" > "$suggestions_file"
msg="$msg | Overrides missing unbind: ${#missing_unbind_suggestions_arr[@]} (suggestions: $suggestions_file)"
fi
# check for any keybinds to display
if [[ -z "$raw_keybinds" ]]; then
echo "no keybinds found."
exit 1
fi
# transform into a readable list: MODS+KEY — DESCRIPTION (for bindd) or DISPATCHER [PARAMS] (for bind)
display_keybinds=$(echo "$raw_keybinds" | awk -F'=' '
function trim(s){ gsub(/^[ \t]+|[ \t]+$/,"",s); return s }
/^[[:space:]]*bind/ {
binder=$1; gsub(/[ \t]/, "", binder);
hasdesc = (index(binder, "d")>0);
rhs=$2; rhs=trim(rhs);
n=split(rhs, a, /[ \t]*,[ \t]*/);
mods=trim(a[1]); key=(n>=2?trim(a[2]):"");
desc=""; dispatcher=""; params="";
if (hasdesc) {
desc=(n>=3?trim(a[3]):"");
dispatcher=(n>=4?trim(a[4]):"");
start=5;
} else {
dispatcher=(n>=3?trim(a[3]):"");
start=4;
}
for(i=start;i<=n;i++){ if(length(a[i])){ p=trim(a[i]); if(p!="") params = (params?params", ":"") p } }
gsub(/\$mainMod/,"SUPER",mods);
gsub(/[ \t]+/,"+",mods);
combo = (mods && key) ? mods "+" key : (key?key:mods);
if (hasdesc && desc != "") {
print combo, " — ", desc;
} else {
if (dispatcher != "" && params != "")
print combo, " — ", dispatcher, " ", params;
else if (dispatcher != "")
print combo, " — ", dispatcher;
else
print combo;
}
}
')
# use rofi to display the keybinds
printf '%s\n' "$display_keybinds" | rofi -dmenu -i -config "$rofi_theme" -mesg "$msg"
|