| 1 | #!/bin/sh |
| 2 | # Requires: rofi, xclip, xdotool, a color emoji font (Noto Color Emoji) |
| 3 | # Emoji and kaomoji picker: search by name, Enter copies the character to the |
| 4 | # clipboard and pastes it into whatever window was focused before rofi opened. |
| 5 | # Terminals don't bind plain ctrl+v to paste, so terminal window classes get |
| 6 | # ctrl+shift+v instead; override the whole thing with ROFI_EMOJI_PASTE_KEYS. |
| 7 | # Picks are remembered and float to the top, so the handful anyone actually |
| 8 | # uses stop needing to be searched for. |
| 9 | set -u |
| 10 | |
| 11 | DATA=${ROFI_EMOJI_DATA:-$(dirname "$0")/../emoji.txt} |
| 12 | RECENT="${XDG_CACHE_HOME:-$HOME/.cache}/rofi-emoji-recent" |
| 13 | RECENT_MAX=${ROFI_EMOJI_RECENT_MAX:-30} |
| 14 | |
| 15 | [ -f "$DATA" ] || { echo "rofi-emoji: no emoji data at $DATA" >&2; exit 1; } |
| 16 | touch "$RECENT" |
| 17 | |
| 18 | # Two spaces between the character and its name: a kaomoji can contain single |
| 19 | # spaces, so a single space would be ambiguous when splitting the choice back |
| 20 | # apart. Names stay in the row because that is what the search filters on. |
| 21 | rows() { |
| 22 | cat "$RECENT" "$DATA" | awk -F'\t' '!seen[$1]++ { printf "%s %s\n", $1, $2 }' |
| 23 | } |
| 24 | |
| 25 | TARGET_WIN=$(xdotool getactivewindow 2>/dev/null) || TARGET_WIN= |
| 26 | |
| 27 | CHOICE=$(rows | rofi -dmenu -i -no-custom -p "emoji" -matching normal) || exit 0 |
| 28 | [ -n "$CHOICE" ] || exit 0 |
| 29 | |
| 30 | CHAR=${CHOICE%% *} |
| 31 | NAME=${CHOICE#* } |
| 32 | |
| 33 | printf '%s' "$CHAR" | xclip -selection clipboard -i |
| 34 | |
| 35 | if [ -n "$TARGET_WIN" ]; then |
| 36 | TARGET_CLASS=$(xdotool getwindowclassname "$TARGET_WIN" 2>/dev/null || echo) |
| 37 | case "$TARGET_CLASS" in |
| 38 | *[Tt]erm*|kitty|st|st-256color|foot|footclient|tilix|konsole) |
| 39 | DEFAULT_PASTE_KEYS="ctrl+shift+v" ;; |
| 40 | *) |
| 41 | DEFAULT_PASTE_KEYS="ctrl+v" ;; |
| 42 | esac |
| 43 | PASTE_KEYS=${ROFI_EMOJI_PASTE_KEYS:-$DEFAULT_PASTE_KEYS} |
| 44 | xdotool windowactivate --sync "$TARGET_WIN" 2>/dev/null |
| 45 | xdotool key --clearmodifiers --window "$TARGET_WIN" "$PASTE_KEYS" 2>/dev/null |
| 46 | fi |
| 47 | |
| 48 | # Rewrite the recents file with this pick first and its older copy dropped. |
| 49 | tmp="$RECENT.$$" |
| 50 | printf '%s\t%s\n' "$CHAR" "$NAME" > "$tmp" |
| 51 | grep -Fxv "$(printf '%s\t%s' "$CHAR" "$NAME")" "$RECENT" >> "$tmp" 2>/dev/null |
| 52 | head -n "$RECENT_MAX" "$tmp" > "$RECENT" |
| 53 | rm -f "$tmp" |
| 54 | |
| 55 | command -v dunstify >/dev/null 2>&1 && |
| 56 | dunstify -r 7302 "Pasted $CHAR" "$NAME" || |
| 57 | notify-send "Pasted $CHAR" "$NAME" |