Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

value for key.space is ' ' #609

Open
hoefkensj opened this issue Sep 4, 2024 · 9 comments
Open

value for key.space is ' ' #609

hoefkensj opened this issue Sep 4, 2024 · 9 comments

Comments

@hoefkensj
Copy link

Description
when using pynput listener , the key returned by the callback for the key , has its value set to ' ' whereas other keys use the PS/2 keycode instead (for the keys that have the value property set) think it would make more sense to either include space key with the keys that only have char defined , or leave it as it is but replace the value of the key to be 32

Platform and pynput version
Distro : Gentoo Linux 2.14 , kernel : 6.6.8
Python : Python 3.11.7 , Pynput 1.7.7

To Reproduce

from pynput import keyboard
c=keyboard.Controller()
l = keyboard.Listener(on_press=lambda p:print(repr(p.value)))
l.start()
c.tap(keyboard.Key.space)  
c.tap(keyboard.KeyCode(32))

outputs:

' '
' '

expected:

32
32
@oOosys
Copy link

oOosys commented Oct 4, 2024

What makes you expect it to be 32?

@hoefkensj
Copy link
Author

maybe i wasnt really to clear but in the case (as it is now) i would expect it to be 32 as that is the PS/2 keycode for space (the value of the key the keyboard sends ) all other keys that have the key.value properties use the ps/2 code in their value field.

however not all keys have the value property , specifically the ones with the key.char property usually dont , they instead send the character they represent, wich is what space now does but in the value property

so key.space now sends
key.value=' '

wich is not consistent with all the rest of the keys two solutions that would make it valid would be:
changing the property from value to char:
key.char=' '
changing the char to a value:
key.value=32

@hoefkensj
Copy link
Author

tired to make it clearer what i meant hope this works as my explaining it is not 100% :)
image

code used for creating that image:

from pynput import keyboard
from signal import pause

def kd(k):
	print(str(k).split('.')[-1], end='')
	if 'char' in dir(k):
		print(f'\x1b[15G\x1b[32m{k.char}\x1b[m', end='')
	else:
		print(f'\x1b[15G\x1b[31mX\x1b[m', end='')
	if 'value' in dir(k):
		print(f'\x1b[30G\x1b[32m{k.value}\x1b[m', end='')
	else:
		print(f'\x1b[30G\x1b[31mX\x1b[m', end='')
	print()

print('KEY\x1b[15GCHAR\x1b[30GVALUE')
with keyboard.Listener(on_press=kd) as s:
	while True:
		pause()

as you can see the space is the only one displaying a char in the value row... so i think it should be either showing the value there, or it should not have a value but a char(' ') instead ?

@oOosys
Copy link

oOosys commented Oct 6, 2024

My test run of the provided code gives:

ctrl          X              <65507>
<269025067>   None           X
cmd           X              <65515>
space         X              ' '
alt_gr        X              <65406>
<65027>       None           X

If I see it right there are more inconsistencies in the logic of the keycode, the character and the value than in the case of the space character.
So what? I suggest to take it as it is as granted as it is probably not worth the effort to redefine it and brake this way some code written in the past based on what is.

@hoefkensj
Copy link
Author

no it actually is pretty consistent, control keys send a value , printable characters send a char ,..
only space sends a char as a value ...
and yes it matters
also the reason for the keycode that is send as value is not just a random number but spot the connection

dunno how else to show but hopefully this will make it much more clear:

from pynput import keyboard
from signal import pause
import time,os
from contextlib import suppress


def pval(y,k):
	print(f'\x1b[{y};1H{str(k).split(".")[-1]}', end='')
	print(f'\x1b[30G\x1b[32m{k.value}\x1b[m', end='')
	# note:
	# the reason that suppress here is required is exactly the reason of my issue report
	with suppress(Exception):
		print(f'\x1b[50G\x1b[34m{hex(int(str(k.value)[1:-1]))}\x1b[m', end='',flush=True)
	print()

def send(key):
	with suppress(Exception):
		keyboard.Controller().tap(key)

def kd(k,pressed=[None,]):
	if k not in pressed and 'value' in dir(k):
		pressed+=[k]
		pval(len(pressed),k)

print('\x1b[2J\x1b[1;1HKEY\x1b[15GVALUE\x1b[50GHEX',flush=True)
with keyboard.Listener(on_press=kd) as s:
	for key in [*keyboard.Key]:
		send(key)
		time.sleep(0.1)
	pause()

result:
image
also take a look at the orange frames i put on it , if you go and look up an old ASCII table you might see some similarities, aswell as if you know ANSI escape codes like \x1b[ you see that 1b is also the code send by the actual escape key in hex ,so is the ansi tab code identical in hex value to the actual code send by the keyboard for tab... hence no the numbers are not random and therefor i was suggesting using decimal 32 or \x20 for space if it had to be a value and not a char since:

backspace = 0xFF08 -> chr(ord('\x08'))
tab = 0xFF09 -> chr(ord('\x09'))
...
space = 0xFF20 -> chr(ord('\x20'))

would also make sense inmy opinion

@oOosys
Copy link

oOosys commented Oct 7, 2024

It's all pure Python code only ... but ... somehow I failed to find the lines in code which decide about the assignment of values to the event properties and failed also to develop an idea how could it come that space is treated differently. Maybe you can try?

@hoefkensj
Copy link
Author

found it but havent found a solution that works for all cases yet, since the cause was actually a hack put in especially for space : simi-fix now looks like
image
removed char=' ' from
space = KeyCode._from_symbol('space') in _xorg.py

however this breaks every code out there that uses :
key == ' '
to match for space
a different solution could be to make space both have a char and a value set , with char=' ' and value = 0x20
have to take a deeper look into it and see if its only the case on linux as a platform or and if how its done on different platforms

@oOosys
Copy link

oOosys commented Oct 13, 2024

Yes ... breaking past code is what I have already mentioned as reason for not touching it, in spite of the fact it shoudn't be this way. Once it has happened the bug becomes a feature and with plenty of code relying on such behavior there is no way to get it right.
It's like Guido van Rossum who was not able to take away already released features in Python he thought in the long run they shouldn't be there ... if they are there, they will be used and then there is no chance to get rid of them.

@hoefkensj
Copy link
Author

yeah i have been looking into , adding both .char and .value to the space key , then overload eq to check for both, also tought other keys might benefit from that behavior, or something similar (eg enter matching both the ascii keycode , aswell as '\n' and '\cr\lf') but im running lost in the code where half he time wer passing around classes instead of objects so it seems wich kind of makes it hard for me to wrap my head around the whole

ps every key could just have a .value since it would be just the keyboardcode send by that key. just not every key has a corresponding char...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants