Hyprland icon indicating copy to clipboard operation
Hyprland copied to clipboard

IPC: improve activelayout event

Open cnt0 opened this issue 1 year ago • 11 comments

Description

Hello. Hyprland IPC has the following event emitted on the layout change

activelayout>>KEYBOARDNAME,LAYOUTNAME

KEYBOARDNAME and LAYOUTNAME are separated by comma. The problem is that KEYBOARDNAME can contain commas as well. At least it does in my case, it starts with mistel-co.,ltd.-.

Such behavior complicates parsing, for example, shellevents can't correctly handle it right now.

I believe that instead of polluting IPC clients with workarounds we can fix the IPC itself. For example we can introduce the activelayoutv2>>LAYOUTNAME event, because who cares about keyboard names anyway. But I'd listen to suggestion first.

cnt0 avatar Jun 01 '24 07:06 cnt0


~ 
❯ event_data='some,strange,name,layout' 

~ 
❯ echo "${event_data%,*}"                      
some,strange,name

~ 
❯ echo "${event_data#*,}" 
strange,name,layout


~ 
❯ echo "${event_data##*,}"
layout

But if we're talking about this - there are apparently layouts with commas too e.g.:

  • Czech (QWERTY, Macintosh)
  • Arabic (QWERTY, Eastern Arabic numerals)
  • Czech (US, Colemak, UCW support)

https://gist.github.com/MahouShoujoMivutilde/8a12c0d40e7b262f2c78ef6e01193542

because who cares about keyboard names anyway

I care*, because wtype, power button, my bluetooth headphones and possibly other unexpected things are "keyboards".

Here is wtype working:

activelayout>>cvirtualkeyboard,English (US)
activelayout>>cvirtualkeyboard,English (US)
activelayout>>cvirtualkeyboard,none
activelayout>>cvirtualkeyboard,error

* but it's obviously not mutually exclusive thing where we all have to settle to some ONE event to rule 'em all.

MahouShoujoMivutilde avatar Jun 01 '24 15:06 MahouShoujoMivutilde

This is indeed a very annoying issue for IPC clients. I see the event is posted in InputManager.cpp:

https://github.com/hyprwm/Hyprland/blob/22138ac259b2f4253be29311f6b60fbd675074b4/src/managers/input/InputManager.cpp#L873-L874

and two other places in this file.

We could maybe replace the ',' in this line with something like a ;, but I feel this is not a very robust as some keyboard names or layout could contain a ; as well.

Maybe a better solution could be to escape the existing commas in the keyboard name and layout with a \? Does that make sense to do?

zjeffer avatar Jul 07 '24 21:07 zjeffer

Since issue title is quite generic, i'll add another improvement request: also output layout index. Otherwise it is harder to translate name to index for use in hyprctl switchxkblayout: activelayoutv2>>KEYBOARD_NAME;LAYOUT_INDEX;LAYOUT_NAME

Vladimir-csp avatar Aug 19 '24 15:08 Vladimir-csp

encountered this , issue, but with window titles ;w;

I'd rather make separators globally use a value which can't be found in text, like \xFD, which can't be used as a character, so any conflict is avoided and its easy enough to parse, but with the possible problem which it is not a valid character, so not sure if would be handled correctly everywhere...

ENDERZOMBI102 avatar Aug 26 '24 22:08 ENDERZOMBI102

I think it's better to rewrite the way IPC events are handled in general, to never run into the same issue ever again with any other event.

How?

For example

  1. Make SHyprIPCEvent.data a vector of strings, and change all its mentions accordingly
  2. Join these strings in CEventManager::formatEvent() with some separator, (hopefully) escaping it with some replaceAll(string, 'sep', '\sep') before that.

What separator?

Considering it's going to be used in scripts too - something reasonable, but rare. I think tab (\t) works well for this purpose. It's clean, it's easy to input ($'\t' in shell), and you're unlikely to see it anywhere unintentionally.

But, since this obviously breaks the API, might as well make some "socket3" with JSON, like waybar does.

JSON is awesome, because all the (un)escaping (can be) done for you, and typically there is some library lets you parse it automatically in some native object, bypassing the need to deal with (de)serialization entirely.

MahouShoujoMivutilde avatar Aug 27 '24 01:08 MahouShoujoMivutilde

I like your second proposal: printing the data as JSON. It basically works with everything and it's very easy to parse.

zjeffer avatar Aug 28 '24 18:08 zjeffer

I'm actually surprised that this whole IPC is not a json in the first place (like in i3/sway)

cnt0 avatar Aug 29 '24 04:08 cnt0

Json isn't all that handy to deal with in shell (unless you just string a bunch of external tools on a pipe and call it a day). Radical notion: unit separator rules:

Oct   Dec   Hex   Char                        Oct   Dec   Hex   Char
───────────────────────────────────────────────────────────────────────
034   28    1C    FS  (file separator)        134   92    5C    \  '\\'
035   29    1D    GS  (group separator)       135   93    5D    ]
036   30    1E    RS  (record separator)      136   94    5E    ^
037   31    1F    US  (unit separator)        137   95    5F    _

Vladimir-csp avatar Aug 29 '24 06:08 Vladimir-csp

Json isn't all that handy to deal with in shell

But the goal is to use it in IPC, I don't see any problems with JSON in that context? As far as external tools go for handling it in a shell, simply using jq can get you most of the way there.

Unit seperators are pretty cool but I feel like JSON is much more universally supported and understood.

zjeffer avatar Aug 29 '24 20:08 zjeffer

Unit seperators are pretty cool but I feel like JSON is much more universally supported and understood.

But, since this obviously breaks the API, might as well make some "socket3" with JSON

Unit separators could be an [initially] optional upgrade to socket2.

Vladimir-csp avatar Aug 30 '24 09:08 Vladimir-csp

Btw, as a workaround, you could use

Details

#!/usr/bin/env bash

event_data="some-weird,keyboard,Some,Layout"

# so like
# hyprctl devices -j | jq -r '.keyboards.[] | select(.main == true).name'
kbd1="some-weird,keyboard"

case "$event_data" in
    "$kbd1"*)
        echo "matched keyboard"
        echo "Layout is '${event_data##"$kbd1",}'"
        ;;
    *)
        echo "not our keyboard, skipping"
    ;;
esac

to get

matched keyboard
Layout is 'Some,Layout'

This could be expanded to something generic, like

Details

#!/usr/bin/env bash

attached_keyboards=('some,kbd,(1)' 'some,kbd,(2)' 'some,kbd,(3)' 'some-kbd-4')

parse_layout() {
    local event_data="$1"

    for kbd in "${attached_keyboards[@]}"; do
        case "$event_data" in
            "$kbd"*)
                echo "-> keyboard = '$kbd'"
                echo "-> layout = '${event_data##"$kbd",}'"
                ;;
        esac
    done
}

## TEST VALUES

event_datas=(
'some,kbd,(1),Aawdmkawdm,(Phonetic)'
'some,kbd,(2),Atrhjhyt Bryjytjjy,,wemrmmggr 4t43 t34t43 t3t54'
'some,kbd,(2),English (US)'
'some,kbd,(3),error'
'some-kbd-4,AAAAAA,AAAAAAAAA'
'some-kbd-4,YES'
)


for data in "${event_datas[@]}"; do
    echo "$data"
    parse_layout "$data"
done


Resulting in

Details

some,kbd,(1),Aawdmkawdm,(Phonetic)
-> keyboard = 'some,kbd,(1)'
-> layout = 'Aawdmkawdm,(Phonetic)'
some,kbd,(2),Atrhjhyt Bryjytjjy,,wemrmmggr 4t43 t34t43 t3t54
-> keyboard = 'some,kbd,(2)'
-> layout = 'Atrhjhyt Bryjytjjy,,wemrmmggr 4t43 t34t43 t3t54'
some,kbd,(2),English (US)
-> keyboard = 'some,kbd,(2)'
-> layout = 'English (US)'
some,kbd,(3),error
-> keyboard = 'some,kbd,(3)'
-> layout = 'error'
some-kbd-4,AAAAAA,AAAAAAAAA
-> keyboard = 'some-kbd-4'
-> layout = 'AAAAAA,AAAAAAAAA'
some-kbd-4,YES
-> keyboard = 'some-kbd-4'
-> layout = 'YES'

attached_keyboards could be populated like so

attached_keyboards=($(hyprctl devices -j | jq -r '.keyboards.[].name'))

And updated on ....device(added|removed) events that doesn't exist. Well. Updated on every function call then.

MahouShoujoMivutilde avatar Sep 10 '24 01:09 MahouShoujoMivutilde

Hello there!

This issue has been closed, as we are moving from issues to discussions. More about this can be found here and in #9854.

Firstly, please make sure this issue is still relevant in latest Hyprland. If so, we ask you to open a discussion (please read the discussion guidelines first, in the pinned post)

Thank you for your understanding!

vaxerski avatar Apr 05 '25 19:04 vaxerski