ID:2694120
 
Resolved
Keyboard macros have gone back to assuming a US layout for purposes of mapping key codes to letter names, because trying to use Windows' internal functionality for this was causing problems with winset-defined macros for Russian users.
BYOND Version:513
Operating System:Windows 10 Pro
Web Browser:Firefox 89.0
Applies to:Dream Seeker
Status: Resolved (515.1628)

This issue has been resolved.
Descriptive Problem Summary:

If the current keyboard layout is RU, then the winset does not work correctly for letters

Numbered Steps to Reproduce Problem:

1. Set RU keyboard layout
2. Use winset to set macros

Code Snippet (if applicable) to Reproduce Problem:
/client/verb/loocc()

/client/verb/reset_macros()
erase_all_macros()
for(var/key in list("F4", "L"))
winset(src, "macro-\ref[key]", "parent=macro;name=[key];command=loocc")
world.log << "[winget(src, "macro-\ref[key]", "command;name;")]"

/client/proc/erase_all_macros()
var/erase_output = ""
var/list/macro_set = params2list(winget(src, "macro.*", "command")) // The third arg doesnt matter here as we're just removing them all
for(var/k in 1 to length(macro_set))
var/list/split_name = splittext(macro_set[k], ".")
var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
erase_output = "[erase_output];[macro_name].parent=null"
winset(src, null, erase_output)


Expected Results:

command=loocc;name=F4
command=loocc;name=L


Actual Results:

command=loocc;name=F4
command=;name=



Does the problem occur:
Every time? Or how often?
In other games?
In other user accounts?
On other computers?

When does the problem NOT occur?

Change manually keyboard layout to EN and reset macros again
Byond not allow cyrillics key binds but most times does conversion to corresponding latin layout key on client side. And maybe problem that it doesn't always work.

Mostly is when users start game while in RU layout, looks like as if DS is losing ЙЦУКЕН/QWERTY key binds and they don't work regardless of layout.
But if user start game while in ENG layout, then everything works on both layouts.

Something similar with DreamMaker macros editor "Find key" button, maybe can be used for tests.
I think your winget may simply be broken. \ref[string] will produce a value that may change if the string you used goes out of scope. I don't think there's a bug here.

You shouldn't use \ref on a text value to name your macros. Instead I would use ckey() on the key name.
In response to Lummox JR
ckey() doesn't help or am I doing something wrong?

/client/verb/loocc()
world.log << "loocc"

/client/verb/reset_macros()
for(var/key in list("F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","Q","F"))
winset(src, "macro-[ckey(key)]", "parent=macro;name=[key];command=loocc")
world.log << "[winget(src, "macro-[ckey(key)]", "command;name;")]"


command=;name=
command=;name=
command=loocc;name=F3
command=loocc;name=F4
command=loocc;name=F5
command=loocc;name=F6
command=loocc;name=F7
command=loocc;name=F8
command=loocc;name=F9
command=loocc;name=F10
command=loocc;name=F11
command=loocc;name=F12
command=;name=
command=;name=
/client/verb/loocc()
world.log << "loocc"

/client/verb/reset_macros()
winset(src, "macro-F1", "parent=macro;name=F1;command=loocc")
world.log << "[winget(src, "macro-F1", "command;name;")]"
winset(src, "macro-F2", "parent=macro;name=F2;command=loocc")
world.log << "[winget(src, "macro-F2", "command;name;")]"
winset(src, "macro-F3", "parent=macro;name=F3;command=loocc")
world.log << "[winget(src, "macro-F3", "command;name;")]"
winset(src, "macro-Q", "parent=macro;name=Q;command=loocc")
world.log << "[winget(src, "macro-Q", "command;name;")]"


command=;name=
command=;name=
command=loocc;name=F3
command=;name=
/client/verb/loocc()
world.log << "loocc"

/client/verb/reset_macros()
for(var/key in list("Q","W","F1","F2"))
winset(src, "macro.[key]", "parent=macro;name=[key];command=loocc")
world.log << "[winget(src, "macro.[key]", "command;name;")]"


// RU keyboard layout on
command=;name=
command=;name=
command=loocc;name=F1
command=loocc;name=F2
// EN keyboard layout on
command=loocc;name=Q
command=loocc;name=W
command=loocc;name=F1
command=loocc;name=F2


You might try using _ instead of - in the ID. Better to stick with characters that would be valid in a var name.

The keyboard layout has no impact whatsoever on the code that handles macro winsets/wingets; it would at most be relevant to the way macros triggered.
This is not naming Problem.

Macros do not work if the client has the Russian layout enabled at the time of the winset run

/client/verb/loocc()
world.log << "loocc"


/client/New()
..()
winset(src, "macro_Q", "parent=macro;name=Q;command=loocc")
world.log << "[winget(src, "macro_Q", "command;name;")]"


command=;name=

Well one of the major problems here is that you can't use winset() or winget() reliably in client/New(). Those should be done at the mob/Login() stage.

But the way macros are set on the client via winset(), and retrieved via winget(), is completely agnostic as to the current keyboard layout. The only thing that would make a lick of sense here would be if there were some really bizarre parsing or character conversion issue in play with how the command is handled, but that doesn't make a ton of sense, plus it also isn't something I can readily test.
In response to Lummox JR
Above, I gave examples when I set macros using verbs when the Russian layout is active. And at the mob/Login() stage doesn't work either

I'm still having a lot of trouble diagnosing this. I may not be able to do it without downloading a Russian keyboard layout, which I'm kinda loath to do.

I was thinking your locale might matter in terms of parsing the winset and some uppercase/lowercase conversion that the macro code does. The backend code however actually switches out of your default locale right away, and switches to the internal "C" locale that produces more predictable results. The only time your original locale should be taken into account is when using certain date/time functions or when converting between "ANSI" text (8-bit for whatever code page your system uses) and UTF-8. So ultimately I can't explain the results you're getting.
I can approve that this issue is highly reproducible with all our Russian players on our Russian server for years.
Also, I just have found, that some players reported that their custom macroses are reset when they join the game with the Russian layout turned on:

https://github.com/ChaoticOnyx/OnyxBay/issues/5400
(report in Russian)





They managed to fix it by pressing "Cancel", reopening macroses menu with English layout, and pressing "Ok".
I'm beginning to suspect the use of VkKeyScan() is causing this issue. Can you tell me if the problem first appeared in 513 or if it was earlier?

I'm not sure why 513 would have changed this of course, except for switching on Unicode functionality.
In response to Lummox JR
Lummox JR wrote:
I'm beginning to suspect the use of VkKeyScan() is causing this issue. Can you tell me if the problem first appeared in 513 or if it was earlier?

I'm not sure why 513 would have changed this of course, except for switching on Unicode functionality.

This bug exists for ages tbh
Yeah, that's true. It's not the 513's issue, it has been existing long before.
I'm beginning to suspect the use of VkKeyScan() is causing this issue.

The VkKeyScan() documentation says:

Translates a character to the corresponding virtual-key code and shift state for the current keyboard.

...

Return value

...

If the function finds no key that translates to the passed character code, both the low-order and high-order bytes contain -1.

Try using LoadKeyboardLayout() and VkKeyScanEx() instead?

https://stackoverflow.com/questions/29426129/ why-does-vkkeyscanw-return-1-for-unicode-characters
So, not fixed, seems like. Any hopes on a fix in foreseeable future?
I've ripped out the VkKeyScan() code in hopes that this will improve things. Let me know how this works out in 515.1628.
Tested on 515.1630, works awesome.
Page: 1 2