ID:1626119
 
Resolved
Verbs with an implied argument, such as an obj in the player mob's contents, would reset the list of pressed keys and cause non-repeat macros to behave like repeats.
BYOND Version:506.1247
Operating System:Windows 7 Home Premium 64-bit
Web Browser:Chrome 35.0.1916.153
Applies to:Dream Seeker
Status: Resolved (507.1248)

This issue has been resolved.
Descriptive Problem Summary:
This is a very strange and annoying bug. For a while I thought it was an error in my own code, but now that I tested it, I am sure that it is in fact a BYOND bug.

For some reason, macros that call verbs inherited through objects in the contents list behave differently than those that call verbs defined directly for the user's type.

Macros that call verbs inherited through contents act as if they are set to +REP, even if they are not, while macros that call the users own defined verbs function normally.

Numbered Steps to Reproduce Problem:
1. Compile and run this code:
obj/key/verb/a_down()
set hidden = 1
usr << "You pressed a."

mob
verb
z_down()
set hidden = 1
usr << "You pressed z."

Login()
..()
contents += new /obj/key
winset(usr, "a_down", "parent=Macro;name=a;command=a-down")
winset(usr, "z_down", "parent=Macro;name=z;command=z-down")

2. Try holding down both "a" and "z", and see how "a" repeats, and "z" doesn't.

Expected Results:
Macros that are not made to repeat, never repeat in any case.

Actual Results:
Macros that call verbs inherited through the contents list repeat whether you want them to or not.

Did the problem NOT occur in any earlier versions? If so, what was the last version that worked? (Visit http://www.byond.com/download/build to download old versions for testing.)
The last version that worked was 447.1028. Something broke right at 448.1029.

Workarounds:
Just avoid using any /obj verbs...
I'm confused what you mean by this.

Try holding down both "a" and "z", and see how "a" repeats, and "z" doesn't.

Do you mean both keys together? That would explain a ton about what's going on, as it could just be the key-repeat code is getting confused with two letter keys held down (perhaps for just your keyboard, perhaps generally).

The macro code is completely indifferent to the verb, so without the two-key combination I'm puzzled as to how the verb's origin could possibly matter.
In response to Lummox JR
Lummox JR wrote:
I'm confused what you mean by this.

Try holding down both "a" and "z", and see how "a" repeats, and "z" doesn't.

Do you mean both keys together?

I'm sorry. I should have made it more clear. I didn't mean hold them down simultaneously. What I meant was to test each one separately, to see the difference between them.

Hold down "a" by itself, and it will repeat. Then try holding down "z" by itself and it will not, as should be the case. So "z" works correctly, but "a" doesn't.

This bug has nothing to do with my keyboard. I am not talking about combinations at all. This has nothing to do with combining different keys.

The macro code is completely indifferent to the verb, so without the two-key combination I'm puzzled as to how the verb's origin could possibly matter.

Then unfortunately it will puzzle you even more, because this appears to be the case. The origin of the verb has determined whether or not the macro will repeat!
I did some testing with older versions and have narrowed the problem down.

The last version that worked was 447.1028. Something broke right at 448.1029.
Wow, that's quite a way back, but it's definitely helpful to know. The key repeat code has changed many times, though not very recently.

I'm still scratching my head as to why the verb origin would matter at all, because if the keyboard code is doing this for one verb, it has to be doing it for both and one just isn't following through somehow.
Even stranger things start to happen when you throw in a key-up macro.
obj
key
verb
a_down()
set hidden = 1
usr << "You pressed a."

a_up()
set hidden = 1
usr << "You released a."

mob
Login()
..()
contents += new /obj/key
winset(usr, "a_down", "parent=Macro;name=a;command=a-down")
winset(usr, "a_up", "parent=Macro;name=a+UP;command=a-up")

Here is an example of the output that I get just from holding down "a":
You released a.// Yes, key-up really gets triggered first!
You pressed a.
You released a.
You pressed a.
You released a.
You pressed a.
You released a.// After 3 iterations, key-down just decides to quit.
You released a.
You released a.
You released a.
You released a.
You released a.
You released a.
You released a.
You released a.
You released a.
You released a.
You released a.
You released a.// This goes on forever, until you actually release the key.

Looking at the release notes for version 448, I noticed this:
Calls to alert() and input() caused by a macro press could result in the macro not being used the next time its key combination was pressed. Now the key is considered released, and triggers any related up-key macros, before the popup box appears. (Fugsnarf)
That makes me wonder if something went wrong there with key-up, which might also affect key-down. I'm not sure if that could have anything to do with a verb's origin though.

Have you been able to see the bug in action?
I won't be doing any testing on this till at least Monday.
Found the issue. The problem is that there is an implied argument to a-down because of the fact that it belongs to an obj and its default "set src" is view(1) (as I recall). The choice list that would normally pop up is not shown because there's only one valid choice, but UnstickKeys() was being called before the choice list ran the logic that said if it should show up at all.

This has implications for the webclient, so I'm glad to have found the cause here.
Lummox JR resolved issue with message:
Verbs with an implied argument, such as an obj in the player mob's contents, would reset the list of pressed keys and cause non-repeat macros to behave like repeats.
I'm glad this will be fixed. Thanks for the info. It revealed a workaround that I was not aware of, and actually should have been using the whole time.

I wasn't using the full, strict command syntax, so it fell through the cracks and triggered this very obscure BYOND bug.

For the workaround, you just have to place a double quote at the beginning of the command (you should always do this), and when the src isn't the user, you have to specify the object's name as an implied argument. Doing this results in everything functioning normally.
mob
Login()
..()
contents += new /obj/key
winset(usr, "a_down", "parent=Macro;name=a;command=\"a-down key")
winset(usr, "a_up", "parent=Macro;name=a+UP;command=\"a-up key")

I will be doing this from now on, as this strict syntax is far more robust, since it works even when there are multiple, unique instances in the user's contents that share the same verb.