Page 1 of 1

Shift+Click in gtkdialog. Possible?

Posted: Wed Jan 03, 2024 10:49 am
by MochiMoppel

In ROX-Filer, when a script file is clicked, the script is executed. However when the Shift key is pressed while clicking, the script is opened in an editor.
Same with text based image files like SVG or XPM. Shift+Click would open them in the designated editor.

I wonder if such functionality can be achieved with gtkdialog. It would greatly increase the possibilities to execute commands or start applications.
Though gtkdialog knows key events and mouse button events, there is no way to combine both. Or is it?

I tried my luck reading /proc/bus/input/devices and the output of xinput. The challenge is to find the correct name of the attached keyboard before examining the status of the Shift keys. On a laptop with attached external keyboard or with keyboards attached to a USB hub this can be a bit tricky.

I managed to write a function that works for me, but I'm not sure how robust this function is. I'm keen to know if this works for other users and also if there are better ways. I'm especially interested to know where it does not work (In this case I would need output of cat /proc/bus/input/devices and xinput

The following demo fills a tree with XPM icon files. Double clicking should trigger the usual ROX handler (normally an image viewer) and Shift+Doubleclick should trigger leafpad with the XPM source code. Instead of using mouse pressing Spacebar and Shift+Spacebar also works. Pressing Enter works, Shift+Enter does not.

Code: Select all

#!/bin/sh
function shift_is_down {
	if xinput | grep -q Keyboard0 ;then
		KEYBDNAME=Keyboard0	
	else
		KEYBDNAME=$(< /proc/bus/input/devices)
		KEYBDNAME=${KEYBDNAME%\"*LED*}
		KEYBDNAME=${KEYBDNAME##*\"}
	fi
	xinput query-state "$KEYBDNAME" | grep -Eq "\[(50|62)\]=down"	#should return 0 if keycode 50 or 62 (left/right Shift key) is down
}; export -f shift_is_down

echo '
<window width-request="500" height-request="500">
	<tree>
		<variable>vTREE</variable>
		<input>'find /usr/share -type f -name "*.xpm"'</input>
		<action>shift_is_down && (leafpad "$vTREE" &) || rox "$vTREE"</action>
	</tree>
</window>'|gtkdialog -sc

Re: Shift+Click in gtkdialog. Possible?

Posted: Wed Jan 03, 2024 5:59 pm
by HerrBert
MochiMoppel wrote: Wed Jan 03, 2024 10:49 am

...
I managed to write a function that works for me, but I'm not sure how robust this function is. I'm keen to know if this works for other users and also if there are better ways. I'm especially interested to know where it does not work (In this case I would need output of cat /proc/bus/input/devices and xinput
...

So sad i can not help, because it works for me, too :lol:


Re: Shift+Click in gtkdialog. Possible?

Posted: Sun Nov 24, 2024 3:57 pm
by HerrBert

@MochiMoppel
Unfortunately, I was too happy too soon.

I have been using a modified function to get CTRL key when dropping files onto a ROX Application directory, so i can copy files into it or just let it open them.
Last week i got a new keyboard and the function stopped working :(
So i had to do some search.

Keyboard is ISY IGK 4000 TKL Gaming Keyboard

lsusb identifies it as Bus 005 Device 003: ID 320f:50ac Evision RGB Keyboard

Also, finding its name seems to work:

Code: Select all

# cat /proc/bus/input/devices 
I: Bus=0003 Vendor=1bcf Product=0005 Version=0110
N: Name="USB Optical Mouse"
P: Phys=usb-0000:00:1a.2-1/input0
S: Sysfs=/devices/pci0000:00/0000:00:1a.2/usb5/5-1/5-1:1.0/0003:1BCF:0005.0001/input/input2
U: Uniq=
H: Handlers=mouse0 event0 
B: PROP=0
B: EV=17
B: KEY=1f0000 0 0 0 0
B: REL=1943
B: MSC=10

I: Bus=0003 Vendor=320f Product=50ac Version=0111
N: Name="Evision RGB Keyboard"
P: Phys=usb-0000:00:1a.2-2/input0
S: Sysfs=/devices/pci0000:00/0000:00:1a.2/usb5/5-2/5-2:1.0/0003:320F:50AC.0002/input/input3
U: Uniq=
H: Handlers=sysrq kbd leds event1 
B: PROP=0
B: EV=120013
B: KEY=1000000000007 ff9f207ac14057ff febeffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=1f

I: Bus=0003 Vendor=320f Product=50ac Version=0111
N: Name="Evision RGB Keyboard"
P: Phys=usb-0000:00:1a.2-2/input1
S: Sysfs=/devices/pci0000:00/0000:00:1a.2/usb5/5-2/5-2:1.1/0003:320F:50AC.0003/input/input4
U: Uniq=
H: Handlers=kbd event2 
B: PROP=0
B: EV=10001f
B: KEY=3f000307ff 0 0 483ffff17aff32d bfd4444600000000 1 130ff38b17d000 ffe77bfad941dfed 81beffcd01cfffff febffbffdffffffe
B: REL=1040
B: ABS=100000000
B: MSC=10

I: Bus=0003 Vendor=320f Product=50ac Version=0111
N: Name="Evision RGB Keyboard"
P: Phys=usb-0000:00:1a.2-2/input1
S: Sysfs=/devices/pci0000:00/0000:00:1a.2/usb5/5-2/5-2:1.1/0003:320F:50AC.0003/input/input5
U: Uniq=
H: Handlers=event3 
B: PROP=0
B: EV=9
B: ABS=10000000000

%< cut off...

Problem with xinput is, that it appears twice in keyboard and also in pointer:

Code: Select all

# xinput
⎡ Virtual core pointer                    	id=2	[master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
⎜   ↳ USB Optical Mouse                       	id=8	[slave  pointer  (2)]
⎜   ↳ Evision RGB Keyboard                    	id=10	[slave  pointer  (2)]
⎣ Virtual core keyboard                   	id=3	[master keyboard (2)]
    ↳ Virtual core XTEST keyboard             	id=5	[slave  keyboard (3)]
    ↳ Power Button                            	id=6	[slave  keyboard (3)]
    ↳ Power Button                            	id=7	[slave  keyboard (3)]
    ↳ Evision RGB Keyboard                    	id=9	[slave  keyboard (3)]
    ↳ Dell WMI hotkeys                        	id=11	[slave  keyboard (3)]
    ↳ Evision RGB Keyboard                    	id=12	[slave  keyboard (3)]
# 

xinput returns an error when trying to address the device with its name:

Code: Select all

# xinput query-state 'Evision RGB Keyboard'
Warning: There are multiple devices named 'Evision RGB Keyboard'.
To ensure the correct one is selected, please use the device ID instead.

unable to find device 'Evision RGB Keyboard'
# xinput query-state keyboard:'Evision RGB Keyboard'
unable to find device 'keyboard:Evision RGB Keyboard'
# 

So far i got it working again:

Code: Select all

#!/bin/bash
function ctrl_is_down {
	if xinput | grep -q Keyboard0 ;then
		KEYBDNAME=Keyboard0	
	else
		KEYBDNAME=$(< /proc/bus/input/devices)
		KEYBDNAME=${KEYBDNAME%\"*LED*}
		KEYBDNAME=${KEYBDNAME##*\"}
	fi
	for ID in $(xinput | sed "/keyboard/!d;/$KEYBDNAME/!d;s/.*id=\([0-9]\+\).*/\1/"); do
		xinput query-state "$ID" | grep -Eq "\[(37|105)\]=down" && break
	done
}
ctrl_is_down && echo CTRL is down...

Re: Shift+Click in gtkdialog. Possible?

Posted: Sun Nov 24, 2024 6:56 pm
by JakeSFR

I'm little late to the party, but it's actually possible. Hacky and messy, as usual, but still.

The KEY_SYM GtkDialog variable can be used directly only (I think?) in key-{press,release}-event actions, but apparently it's also visible to other widgets when the aforementioned signal happens, so it can be reused by a regular action later.

Code: Select all

#!/bin/sh

echo '
<window width-request="500" height-request="500">
	<vbox>
		<entry visible="true" editable="false" has-focus="false" can-focus="false">
			<variable>vENTRY</variable>
			<input>echo $KEY_SYM | grep -v space</input>
		</entry>
		<tree>
			<variable>vTREE</variable>
			<input>'find /usr/share -type f -name "*.xpm"'</input>
			<action signal="key-press-event">refresh:vENTRY</action>
			<action signal="key-release-event">clear:vENTRY</action>
			<action>case "$vENTRY" in Shift*) (leafpad "$vTREE" &) ;; *) rox "$vTREE" ;; esac</action>
		</tree>
	</vbox>
</window>'|gtkdialog -sc

grep -v space is to make it work also with spacebar, like the original.

KEY_MOD instead of KEY_SYM doesn't seem to work great in this example, though - pressing and holding Shift doesn't set the least significant bit, at least as long as you don't press an additional key.

Well, it's a start...

Greetings!


Re: Shift+Click in gtkdialog. Possible?

Posted: Thu Nov 28, 2024 11:37 am
by MochiMoppel
HerrBert wrote: Sun Nov 24, 2024 3:57 pm

@MochiMoppel
Unfortunately, I was too happy too soon.

Fortunately! :lol:
Because now we know when the function may fail. Your workaround made me wonder if retrieving the keyboard name from /proc/bus/input/devices is necessary at all. I never liked this anyway. Scanning all "likely to be a keyboard" device IDs seems much more robust, especially when more than 1 keyboard is connected (e.g. laptop + external keyboard).

I rewrote the function. Based on the supplied argument C,S or A it returns true if Ctrl, Shift or Alt key or any combination thereof is pressed, e.g key_is_down CS returns true when Ctrl+Shift is pressed.

Code: Select all

function key_is_down {
	case $1 in
		C)     PAT='37|105' ;;	#Left/Right Ctrl
		S)     PAT='50|62'  ;;	#Left/Right Shift
		A)     PAT='64|108' ;;	#Left/Right Alt
		CS|SC) PAT='37|105|50|62'  ;;
		CA|AC) PAT='37|105|64|108' ;;
		SA|AS) PAT='50|62|64|108'  ;;
		*C*)   PAT='37|105|50|62|64|108' ;; #matches CSA|CAS|SCA|SAC|ACS|ASC et alia
		*) return 1 ;; #no or invalid argument
	esac
	for ID in $(xinput | sed -r '/slave *keyboard/!d;/hotkey|webcam|button|virtual|video/Id;s/.*=([0-9]+).*/\1/'); do
		(( $(xinput query-state $ID | grep -Ec "($PAT).=down")==${#1} )) && return
	done
}

This is useful not only for gtkdialog but even more so for other applications like yad, gxmessage, Xdialog etc.. Makes it possible to perform max 8 different actions with a single button :o , depending on the status of the Ctrl, Shift and Alt keys.

@JakeSFR In principle a good idea and it works ....with some caveats, as always :lol:
I ran into problems when using it in my own applications. It can be tricky to ensure the clearance of the entry widget, especially when other key-{press,release}-event signals are involved. I see the most potential for fairly simple widget actions and for widgets that don't allow or ignore mouse actions other than left click.