porres / pd-else

ELSE - EL Locus Solus' Externals for Pure Data
Do What The F*ck You Want To Public License
297 stars 35 forks source link

[keycode] tests #1461

Open porres opened 1 year ago

porres commented 1 year ago

Hi, tagging @Lucarda and @sebshader here. I asked Lucas to test keycode --> https://github.com/porres/pd-else/blob/master/Classes/Source/keycode.c newly added here.

In order to compile ELSE now you need the latest and unreleased Pd source code (cause I have a new [nchs~] object that uses the multichannel stuff. I compiled the unreleased version and, funny enough, [keycode] doesn't work if I run it in my compiled app on macOS. It works on Pd 0.53-1 nonetheless.

You can compile ELSE with Pd 0.53-1 if you don't compile [nchs~]. One can also just compile keycode itself, of course.

Lucas, please tell us what went wrong, please post screenshots and stuff.

On my ABC qwerty english keyboard I get code values of '4' for 'a', '5' for 'b', '6' for 'c' and so on...

Lucarda commented 1 year ago

this is what i get just compiling keycode.c on Pd 0.53.1

keycode1


print: 1 17 1
print: 1 17 0
print: 2 16 1
print: 2 16 0
print: 3 54 1
print: 3 54 0
print: 4 55 1
print: 4 55 0
print: 5 56 1
print: 5 56 0
print: 6 229 1
print: 6 229 0
print: 7 0 1
print: 7 0 0
print: 8 226 1
print: 8 226 0
print: 9 0 1
print: 9 0 0
print: 0 5 1
print: 0 5 0
print: q 0 1
print: q 0 0
print: w 68 1
print: w 68 0
print: e 72 1
print: e 72 0
print: r 0 1
print: r 0 0
print: t 0 1
print: t 0 0
print: y 0 1
print: y 0 0
print: u 0 1
print: u 0 0
print: i 0 1
print: i 0 0
print: o 0 1
print: o 0 0
print: p 0 1
print: p 0 0
print: a 64 1
print: a 64 0
print: s 0 1
print: s 0 0
print: d 67 1
print: d 67 0
print: f 71 1
print: f 71 0
print: g 0 1
print: g 0 0
print: h 0 1
print: h 0 0
print: j 0 1
print: j 0 0
print: k 0 1
print: k 0 0
print: l 0 1
print: l 0 0
print: ; 0 1
print: ; 0 0
print: z 0 1
print: z 0 0
print: x 69 1
print: x 69 0
print: c 66 1
print: c 66 0
print: v 0 1
print: v 0 0
print: b 65 1
print: b 65 0
print: n 0 1
print: n 0 0
print: m 0 1
print: m 0 0
print: , 0 1
print: , 0 0
print: . 0 1
print: . 0 0
print: / 0 1
print: / 0 0 
porres commented 1 year ago

Values are quite different. The order of letters show your keyboard layout, which seems to be the same as mine.

For numbers between 1 and 0 on my top row I have keycode values from 30-39

@sebshader to the rescue

sebshader commented 1 year ago

Maybe this issue https://github.com/depp/keycode/issues/5. @Lucarda we might need to use the python script in that repo to update the table (or keep both and try to support older windows too)

Lucarda commented 1 year ago

I'm totally confused and partly because of that I'm also angry.

How this is supposed to work?: and if it works why don't we just map the MIDI note in

const unsigned char KEYCODE_TO_HID[256] = {
...
}

I'm doing other stuff (and not having much time) and don't have python installed.

I'm on Win11.

if I have to regenerate the tables as in https://github.com/depp/keycode/tree/master/scripts then it wont work on a Win7 machine?

sebshader commented 1 year ago

@Lucarda sorry, I was just saying that because I'm at work but I think I may be able to do it if I get a winuser.h file

sebshader commented 1 year ago

@Lucarda basically tcl/tk sends %k values from key events and those have to be mapped to common values for all platforms

Lucarda commented 1 year ago

Ok. I see that the objects it a general purpose keycode and not a pckeyboard to MIDI as @porres is using it. :)

Lucarda commented 1 year ago

here is my mingw64 winuser.h

winuser.zip

Lucarda commented 1 year ago

@sebshader you might already know this:

$ python extract.py --platform=windows --input=./winuser.h
Writing C:/Users/lucarda/Downloads/attach/porres/keycode-master/data/windows_scancodes.csv
$ cat C:/Users/lucarda/Downloads/attach/porres/keycode-master/data/windows_scancodes.csv

Keycode,Name
1,LBUTTON
2,RBUTTON
3,CANCEL
4,MBUTTON
5,XBUTTON1
6,XBUTTON2
8,BACK
9,TAB
12,CLEAR
13,RETURN
16,SHIFT
17,CONTROL
18,MENU
19,PAUSE
20,CAPITAL
21,KANA
21,HANGEUL
21,HANGUL
22,IME_ON
23,JUNJA
24,FINAL
25,HANJA
25,KANJI
26,IME_OFF
27,ESCAPE
28,CONVERT
29,NONCONVERT
30,ACCEPT
31,MODECHANGE
32,SPACE
33,PRIOR
34,NEXT
35,END
36,HOME
37,LEFT
38,UP
39,RIGHT
40,DOWN
41,SELECT
42,PRINT
43,EXECUTE
44,SNAPSHOT
45,INSERT
46,DELETE
47,HELP
91,LWIN
92,RWIN
93,APPS
95,SLEEP
96,NUMPAD0
97,NUMPAD1
98,NUMPAD2
99,NUMPAD3
100,NUMPAD4
101,NUMPAD5
102,NUMPAD6
103,NUMPAD7
104,NUMPAD8
105,NUMPAD9
106,MULTIPLY
107,ADD
108,SEPARATOR
109,SUBTRACT
110,DECIMAL
111,DIVIDE
112,F1
113,F2
114,F3
115,F4
116,F5
117,F6
118,F7
119,F8
120,F9
121,F10
122,F11
123,F12
124,F13
125,F14
126,F15
127,F16
128,F17
129,F18
130,F19
131,F20
132,F21
133,F22
134,F23
135,F24
136,NAVIGATION_VIEW
137,NAVIGATION_MENU
138,NAVIGATION_UP
139,NAVIGATION_DOWN
140,NAVIGATION_LEFT
141,NAVIGATION_RIGHT
142,NAVIGATION_ACCEPT
143,NAVIGATION_CANCEL
144,NUMLOCK
145,SCROLL
146,OEM_NEC_EQUAL
146,OEM_FJ_JISHO
147,OEM_FJ_MASSHOU
148,OEM_FJ_TOUROKU
149,OEM_FJ_LOYA
150,OEM_FJ_ROYA
160,LSHIFT
161,RSHIFT
162,LCONTROL
163,RCONTROL
164,LMENU
165,RMENU
166,BROWSER_BACK
167,BROWSER_FORWARD
168,BROWSER_REFRESH
169,BROWSER_STOP
170,BROWSER_SEARCH
171,BROWSER_FAVORITES
172,BROWSER_HOME
173,VOLUME_MUTE
174,VOLUME_DOWN
175,VOLUME_UP
176,MEDIA_NEXT_TRACK
177,MEDIA_PREV_TRACK
178,MEDIA_STOP
179,MEDIA_PLAY_PAUSE
180,LAUNCH_MAIL
181,LAUNCH_MEDIA_SELECT
182,LAUNCH_APP1
183,LAUNCH_APP2
186,OEM_1
187,OEM_PLUS
188,OEM_COMMA
189,OEM_MINUS
190,OEM_PERIOD
191,OEM_2
192,OEM_3
195,GAMEPAD_A
196,GAMEPAD_B
197,GAMEPAD_X
198,GAMEPAD_Y
199,GAMEPAD_RIGHT_SHOULDER
200,GAMEPAD_LEFT_SHOULDER
201,GAMEPAD_LEFT_TRIGGER
202,GAMEPAD_RIGHT_TRIGGER
203,GAMEPAD_DPAD_UP
204,GAMEPAD_DPAD_DOWN
205,GAMEPAD_DPAD_LEFT
206,GAMEPAD_DPAD_RIGHT
207,GAMEPAD_MENU
208,GAMEPAD_VIEW
209,GAMEPAD_LEFT_THUMBSTICK_BUTTON
210,GAMEPAD_RIGHT_THUMBSTICK_BUTTON
211,GAMEPAD_LEFT_THUMBSTICK_UP
212,GAMEPAD_LEFT_THUMBSTICK_DOWN
213,GAMEPAD_LEFT_THUMBSTICK_RIGHT
214,GAMEPAD_LEFT_THUMBSTICK_LEFT
215,GAMEPAD_RIGHT_THUMBSTICK_UP
216,GAMEPAD_RIGHT_THUMBSTICK_DOWN
217,GAMEPAD_RIGHT_THUMBSTICK_RIGHT
218,GAMEPAD_RIGHT_THUMBSTICK_LEFT
219,OEM_4
220,OEM_5
221,OEM_6
222,OEM_7
223,OEM_8
225,OEM_AX
226,OEM_102
227,ICO_HELP
228,ICO_00
229,PROCESSKEY
230,ICO_CLEAR
231,PACKET
233,OEM_RESET
234,OEM_JUMP
235,OEM_PA1
236,OEM_PA2
237,OEM_PA3
238,OEM_WSCTRL
239,OEM_CUSEL
240,OEM_ATTN
241,OEM_FINISH
242,OEM_COPY
243,OEM_AUTO
244,OEM_ENLW
245,OEM_BACKTAB
246,ATTN
247,CRSEL
248,EXSEL
249,EREOF
250,PLAY
251,ZOOM
252,NONAME
253,PA1
254,OEM_CLEAR
sebshader commented 1 year ago

an update: so it looks like the table should definitely be using these virtual key codes from winuser.h: https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes and also it seems like it isn't. so we may have to investigate when these codes changed. also, where is the info for the letters and numbers stored? hopefully that repo above has some answers.

sebshader commented 1 year ago

well after all of that it seems like the windows implementation for tcl/tk is wrong (in terms of getting physical location).. they send the 'virtual key' which is in the "WPARAM" of the event and is apparently dependent on layout, when the scancode is actually stored in the "LPARAM" so we might be out of luck w/ this object unfortunately (barring tcl/tk not changing their implementation) https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names

sebshader commented 1 year ago

I think in order to see if these virtual codes are actually layout-independent we'd have to test

bind all <KeyPress> {+ puts "keycodepress: %k"}
bind all <KeyRelease> {+ puts "keycoderelease: %k"}

in wish using different layouts on windows

sebshader commented 1 year ago

tbh at this point it might be easier to detect keyboard layout at runtime and use platform-specific mappings to qwerty, if possible

porres commented 1 year ago

tbh at this point it might be easier to detect keyboard layout at runtime and use platform-specific mappings to qwerty, if possible

sounds quite hard! And I wonder how a software like VCV does this then...

porres commented 1 year ago

I wonder how a software like VCV does this

https://github.com/VCVRack/Rack/blob/05fa24a72bccf4023f5fb1b0fa7f1c26855c0926/src/keyboard.cpp#L31

porres commented 1 year ago

weird, the code says 'qwerty' and so the 'drive', but I changed the setting to 'azerty' and it still worked so I don't get how they do it in VCV

porres commented 1 year ago

maybe the juice is in here?

https://github.com/VCVRack/Rack/blob/05fa24a72bccf4023f5fb1b0fa7f1c26855c0926/src/keyboard.cpp#L126

    const auto& keyMap = deviceInfos[deviceId].keyMap;
    auto it = keyMap.find(key);
    if (it == keyMap.end())
Lucarda commented 1 year ago

they send the 'virtual key' which is in the "WPARAM" of the event and is apparently dependent on layout, when the scancode is actually stored in the "LPARAM" so we might be out of luck w/ this object unfortunately (barring tcl/tk not changing their implementation)

when I have time I'll try

https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mapvirtualkeya

Lucarda commented 1 year ago

I did:

#include "m_pd.h"

#ifdef _WIN32
#include <Windows.h>
#endif
static void object_list_iterate(t_objectlist *x, t_symbol *s, int argc, t_atom *argv) {
    t_listelem *e;
#ifdef _WIN32
    int v;
    v = MapVirtualKey(argv[1].a_w.w_float, MAPVK_VK_TO_VSC);
    argv[1].a_w.w_float = keycode_to_hid(v);
#else
    argv[1].a_w.w_float = keycode_to_hid(argv[1].a_w.w_float);
#endif
    for (e = x->b_list; e; e = e->e_next)
        pd_list(e->e_who, s, argc, argv);
}

and now I'm getting nicer output (had to check if this is what we want)

print: 1 30 1
print: 1 30 0
print: 2 31 1
print: 2 31 0
print: 3 32 1
print: 3 32 0
print: 4 33 1
print: 4 33 0
print: 5 34 1
print: 5 34 0
print: 6 35 1
print: 6 35 0
print: 7 36 1
print: 7 36 0
print: 8 37 1
print: 8 37 0
print: 9 38 1
print: 9 38 0
print: 0 39 1
print: 0 39 0
print: q 20 1
print: q 20 0
print: w 26 1
print: w 26 0
print: e 8 1
print: e 8 0
print: r 21 1
print: r 21 0
print: t 23 1
print: t 23 0
print: y 28 1
print: y 28 0
print: u 24 1
print: u 24 0
print: i 12 1
print: i 12 0
print: o 18 1
print: o 18 0
print: p 19 1
print: p 19 0
print: a 4 1
print: a 4 0
print: s 22 1
print: s 22 0
print: d 7 1
print: d 7 0
print: f 9 1
print: f 9 0
print: g 10 1
print: g 10 0
print: h 11 1
print: h 11 0
print: j 13 1
print: j 13 0
print: k 14 1
print: k 14 0
print: l 15 1
print: l 15 0
print: ; 51 1
print: ; 51 0
print: z 29 1
print: z 29 0
print: x 27 1
print: x 27 0
print: c 6 1
print: c 6 0
print: v 25 1
print: v 25 0
print: b 5 1
print: b 5 0
print: n 17 1
print: n 17 0
print: m 16 1
print: m 16 0
print: , 54 1
print: , 54 0
print: . 55 1
print: . 55 0
sebshader commented 1 year ago

@Lucarda do the outputs change for certain keys if you change the keyboard layout? I think the right solution is to use a different table for windows if we can figure it out, not use the MapVirtualKey. In the keycode repository they switched from virtual keycodes (which tcl sends) to scancodes and in the commit message it said that the virtual keycodes aren't layout-independent.

sebshader commented 1 year ago

@Lucarda Edit: actually maybe this is ok as long as the virtual keycode -> scan code mapping changes w/ layout as well..

Lucarda commented 1 year ago

this is the "]" us key

us
print: ] 48 1
print: ] 48 0

es (spanish)
print: + 46 1
print: + 46 0

this is the ";" us key

us
print: ; 51 1
print: ; 51 0

es (spanish)
print: ñ 53 1
print: ñ 53 0
porres commented 1 year ago

that's bad :( I tried it here and obviously got the same code (48 / 51) in both US and 'spanish ISO'

Lucarda commented 1 year ago

may be you are using a notebook keyboard?

i'm using this one but the spanish version

keyboard

sebshader commented 1 year ago

@Lucarda I believe he's on Mac (right @porres? you weren't testing windows, right?)

Lucarda commented 1 year ago

@sebshader yes I took for granted that he is on Mac.

Edit: actually maybe this is ok as long as the virtual keycode -> scan code mapping changes w/ layout as well..

so we are happy with it? is still unclear to me.

sebshader commented 1 year ago

@Lucarda no, not yet. All keys should be (basically) the same across locales and platforms. I'm hoping we can find a similar function in the windows API that does what we need, I'm looking into it right now. (I see there's one that accepts a locale/layout handle or something, maybe there's one for current locale/layout) Also we may have to compromise a bit on left and right 'shift' keys and windows keys and such because it seems like the virtual keycode doesn't distinguish between them

porres commented 1 year ago

@Lucarda I believe he's on Mac (right @porres? you weren't testing windows, right?)

yes, macbook air, just changed the keyboard setting

Screen Shot 2023-02-02 at 16 57 54

sebshader commented 1 year ago

good lord this api is a mess (typical windows). it seems like we can get the current locale somehow at least (maybe GetKeyboardLayout), and use it w/ MapVirtualKeyEx family somehow

Lucarda commented 1 year ago

virtual-keys have the notion of left/right control/shift

VK_LSHIFT 0xA0 Left SHIFT key
VK_RSHIFT 0xA1 Right SHIFT key
VK_LCONTROL 0xA2 Left CONTROL key
VK_RCONTROL 0xA3 Right CONTROL key

it seems that keycode have them map to be the same:

print: Shift_L 225 1
print: Shift_L 225 0
print: Shift_R 225 1
print: Shift_R 225 0
sebshader commented 1 year ago

@Lucarda could you please test with MapVirtualKeyEx(argv[1].a_w.w_float, MAPVK_VK_TO_VSC, GetKeyboardLayout(0)); instead when you get a free minute?

sebshader commented 1 year ago

we may have to live with not being able to deal with layout changing after keycode is loaded, but that probably isn't too big of an issue

porres commented 1 year ago

that probably isn't too big of an issue

no :)

sebshader commented 1 year ago

also imo we should put that in the Windows keycode_to_hid function since they're already system-dependent but we can sort that out later

Lucarda commented 1 year ago

could you please test with MapVirtualKeyEx(argv[1].a_w.w_float, MAPVK_VK_TO_VSC, GetKeyboardLayout(0)); instead when you get a free minute?

same as in: https://github.com/porres/pd-else/issues/1461#issuecomment-1414227477

i'll be AFK for 2 hours.

sebshader commented 1 year ago

hmmmmm. maybe we have to use the qwerty layout code??

Lucarda commented 1 year ago

i think we can force a layout for translation instead of getting it with GetKeyboardLayout(0).

continue in 2hs ...

sebshader commented 1 year ago

ok when you get back we could also try MapVirtualKeyEx(argv[1].a_w.w_float, MAPVK_VK_TO_VSC, 0); (going off https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names)

Lucarda commented 1 year ago

ok when you get back we could also try MapVirtualKeyEx(argv[1].a_w.w_float, MAPVK_VK_TO_VSC, 0);

same as in: https://github.com/porres/pd-else/issues/1461#issuecomment-1414227477

:(

sebshader commented 1 year ago

.. I'm sure there must be a way but I have no idea what it might be then

sebshader commented 1 year ago

maybe they're 'extended keys'?

porres commented 1 year ago

thanks guys for the effort, really lucky to have you collaborating here

sebshader commented 1 year ago

well I've been looking at some example code and

HKL  layout = GetKeyboardLayout(0);
MapVirtualKeyEx((UINT)argv[1].a_w.w_float, MAPVK_VK_TO_VSC, layout);

should work.. maybe there's some kind of cache that needs to be disabled..

sebshader commented 1 year ago

@Lucarda if you try the above what is the value if you print 'layout'?

Lucarda commented 1 year ago
    HKL  layout = GetKeyboardLayout(0);
    post("layout %d", layout);
    v =MapVirtualKeyEx((UINT)argv[1].a_w.w_float, MAPVK_VK_TO_VSC, layout);
    argv[1].a_w.w_float = keycode_to_hid(v);

gives me pressing the same key first english then spanish:

layout 67699721
print: ; 51 1
layout 67699721
print: ; 51 0
layout 67699721
print: ñ 53 1
layout 67699721
print: ñ 53 0

this is my Windows lang options (the UK stuff came by default in the win installer):

lang

sebshader commented 1 year ago

@Lucarda are you closing pd in between switching layouts? because it doesn't look like the layout is changing, and we are unable to receive the 'change layout' messages (I think?) You have to test one, then close pd, then test the other

Lucarda commented 1 year ago

if i start pd in spanish i get another layout (i'm not sure if this is an %d or a %s)

layout 67766281
print: ñ 51 1
layout 67766281
print: ñ 51 0

EDIT: it's a %d

porres commented 1 year ago

But now you get 51

sebshader commented 1 year ago

ok so it looks like it's working then (if those are the same physical key)

Lucarda commented 1 year ago

Looks that is working.

I get 51 for the same fisical key. But It messes up if you change the keyboard while Pd is open.

Good catch @porres !!!