Closed dankcushions closed 9 years ago
As I said on the forum, the fact that this works on some cores/games is a fortunate coincidence. It should not work at all.
It must be because of some timing difference on one core or another and to "fix" this the way you want it would require a lot of work on the core side or a hack in the blocking function to "whitelist" the button you want which might not be desirable.
Toggle seems desirable to me? I don't think it needs to be a complex whitelist - I'd be happy with an option just turn off hotkey blocking entirely (at least, for the hotkey itself). The intended behaviour doesn't seem to work on all but a handful of cores anyway (and only sometimes!).
The intended behavior works just fine! it blocks core inputs I don't jump while raising volume or anything like that. I'll try to add a toggle for the blocking mechanism as a whole but introducing use case specific hacks won't happen
It blocks the behaviour of [button] in hotkey + [button], for me, but never the hotkey itself, at least for the cores i've used for systems that use a select (my hotkey) button: lr-PCSXrearmed lr-nestopia lr-snes9x-next
just tried it in super mario kart: select = toggle map/rear view L shoulder button = jump select (hotkey) + L shoulder = load state select and L function as usual in game. if i hold select and press L it changes the view but does not trigger the jump function (and I get the load state failure message, as i have no states saved).
this to me is desirable behaviour. i'd always use the hotkey as a button i press rarely as i don't want to trigger accidental saves/loads/quits, but i still want that button to perform it's usual function. Likewise, any buttons that are linked to hotkey functions, I want them to function as usual UNLESS the hotkey is held.
I just tried in FBA with SFIII3 and it works like you want, also it works in snes9x so if it doesn't work in some games maybe those cores/gams react a frame later to the input or something... I don't know but I don't see a way to "fix" this
the only solution I can see is only block if it's been held for more than "X ms" and that would be a horrible hack.
I can see your problem with SF2 it happens, but RA and the core are behaving exactly the same in all the cases, I guess that particular game needs the button held for more time to register a coin input and by then it's probably already being blocked.
As you can see, this is not even core dependent but game dependent. Not really a RA issue.
but you've confirmed the behaviour designed into retroarch is to block the native function of the button assigned to the hotkey! it just so happens that seemingly the only games where this intended behaviour happens to work in, causes problems for users, and the rest of the cores seem to bypass you're intended function, by design or accident.
i don't understand why this behaviour is part of the design (specifically blocking the hotkey's function). it doesn't make any sense, and the only area it works causes a problem.
It does make sense, it was designed to use an EXTRA button as modifier.
Ii don't understand how that makes a difference? Eg, using a snes controller in a snes core. I press the select button, and it does whatever select does natively in those games. I press select + X modifier, and it opens my retroarch menu. I press select + start modifier, and it quits. All that works with no issue. Why would the intended design of RA be to block the select button doing what select does natively in that core?
It works on some cases because input on THAT frame and only on THAT frame already registered. After that frame input is in fact blocked and it seems in SF2 the coin button needs to be held, as simple as that.
Allowing what you want would require a bunch of hacks.
i understand why it sometimes works regardless, I just don't understand why it's an intended feature of all cores, when the only times it works as intended, cause a problem.
You are confusing things, this is not a core feature, input is handled by the frontend and passed into the core. Having hotkeys not block the input would cause problems like what I mentioned before.
When it doesn't work it's a problem of the program that's running inside the core, it might need the button to be held or whatever and at that point input is already blocked.
Anyway, hotkey enable blocks ALL retropad input, so it is in fact working as designed, it's not a bug, you're confusing what you want as an end user with what was actually impĺemented. A toggle to disable blocking could be implemented but an exception for a particular button is probably too much of a mess to be even considered.
I think a delay or something to regiser as a hotkey would be a viable fix - I will look into this for retropie when I next have some free time, and submit upstream if anyone is interested. But I have no knowledge of the input code, so I will need to dig etc. Hack or not, this is broken for controller users currently - but I do understand the devs too.
@joolswills i've not touched C in a decade but I think any hack/fix would be in: https://github.com/libretro/RetroArch/blob/528a020d865b6365403742e8c9631014deca4a0a/runloop.c
/**
* check_block_hotkey:
* @enable_hotkey : Is hotkey enable key enabled?
*
* Checks if 'hotkey enable' key is pressed.
**/
static bool check_block_hotkey(driver_t *driver, settings_t *settings,
bool enable_hotkey)
{
bool use_hotkey_enable;
const struct retro_keybind *bind =
&settings->input.binds[0][RARCH_ENABLE_HOTKEY];
const struct retro_keybind *autoconf_bind =
&settings->input.autoconf_binds[0][RARCH_ENABLE_HOTKEY];
/* Don't block the check to RARCH_ENABLE_HOTKEY
* unless we're really supposed to. */
driver->block_hotkey =
input_driver_keyboard_mapping_is_blocked();
/* If we haven't bound anything to this,
* always allow hotkeys. */
use_hotkey_enable =
(bind->key != RETROK_UNKNOWN)
|| (bind->joykey != NO_BTN)
|| (bind->joyaxis != AXIS_NONE)
|| (autoconf_bind->key != RETROK_UNKNOWN )
|| (autoconf_bind->joykey != NO_BTN)
|| (autoconf_bind->joyaxis != AXIS_NONE);
driver->block_hotkey =
input_driver_keyboard_mapping_is_blocked() ||
(use_hotkey_enable && !enable_hotkey);
/* If we hold ENABLE_HOTKEY button, block all libretro input to allow
* hotkeys to be bound to same keys as RetroPad. */
return (use_hotkey_enable && enable_hotkey);
}
I think the return statement needs to be false for a few milliseconds. If it's false always it might fix our problem, but possibly with some side effects.
Also - are there any cases where the enable hotkey alone should do something within retroarch ? I guess another workaround could be only to consider a hotkey being pressed if other keys are pressed with the enable hotkeys key, so pressing enable hotkey alone would just get sent to the core. (Just ideas without having studied any code etc)
I think the return statement needs to be false for a few milliseconds. If it's false always it might fix our problem, but possibly with some side effects.
ugh... just a fyi, doing something for X amount of time is just ugly and I don't see that being merged anytime.
Also, what if the game needs more than X as the time to register that particular input? Not scalable at all.
I was just floating some ideas. jools' suggestion seems more viable.
I've noticed the issue affects the pcsx core also - the select button is used in King's field 2 as a quick item select, which doesn't work if it's also the hotkey.
ok, so i've tested this - always returning false from the above check_block_hotkey function resolves the issue. obviously this is a hack! the predictable side-effect is that whatever button combo you press along with your hotkey is not blocked. eg, if you do a load state (for me this is select + L-bumper), you will load the state and then trigger whatever the the L-bumper triggers. I believe this would normally be blocked by the check_block_hotkey function.
i want to try @joolswills idea, but it's beyond my c experience (zero!). we need to return false if the hotkey is the only button currently pressed. I'm not sure how to poll the currently pressed key. i want something like:
return (use_hotkey_enable && enable_hotkey && !(OnlyKeyPressed==Hotkey))
i'll carry on playing around but any suggestions welcome :)
In fact, this affects all cores. Most NES games use the select key (e.g. bubble bobble), SNES also (Young merlin, select key is for inventory, Alien3 - select is change weapon and so on).
Please reopen that issue and fix this, it's very annoying you can't use all the keys AND hotkeys :(
The only workaround i can currently think of is handling hotkeys with an addition program like pinnacle game profiler so both the select key works and the hotkeys work as intended, but this should work out of the box.
Aren't you being a bit too demanding? It's not our fault that your controller doesn't have extra buttons
On Sat, Oct 31, 2015, 3:27 AM Talantyyr notifications@github.com wrote:
In fact, this affects all cores. Most NES games use the select key (e.g. bubble bobble), SNES also (Young merlin, select key is for inventory, Alien3 - select is change weapon and so on).
Please reopen that issue and fix this, it's very annoying you can't use all the keys AND hotkeys :(
The only workaround i can currently think of is handling hotkeys with an addition program like pinnacle game profiler so both the select key works and the hotkeys work as intended, but this should work out of the box.
— Reply to this email directly or view it on GitHub https://github.com/libretro/RetroArch/issues/2230#issuecomment-152714715 .
I also agree that this is an issue that needs to be addressed
Any possible fixes to this "issue" would involve hacks, either waiting for a few frames before blocking or like @joolswills said only block if another button is being pressed, I don't think the behavior will be changed.
too demanding to expect games work with their native controllers? :) I'm not sure there's a controller with more buttons than the PlayStation dual shock! maybe a jaguar controller? :)
I think a nice fix is possible but my local repo has a hack that is tolerable to me.
I meant this: "Please reopen that issue and fix this" This is being too demanding. I'm pretty sure you know what I mean but you're being sarcastic.
SNES works perfect with a SNES controller sans hotkeys. NES works perfect with a NES controller sans hotkeys. The DS3/ X360 controllers have the guide button which is perfect for this purpose but your pad doesn't have any extra button that can be used.
This is a perfect example of an edge case.
well I understand their frustration - have a look here and you'll find pages of people with the same issue http://blog.petrockblock.com/forums/search/coin+select/ - I don't think it's fair to call it edge case.
the 360/ds3 workaround is fine, as long as users know about this closed issue. RA defaults to hotkey as select and they'll likely set up select on their controllers as select in these cores, and have the same issue and not know why.
I get that arguing the point isn't going to help change your mind, so I'll shut up :)
It is still an edge case because the feature was not designed to be used on the same button as one of the retropad buttons.
And no it doesn't, RA doesn't have a default for hotkey.
Since it was not designed to be used on a button that as one of the retropad buttons, why block at all ? Even @objectchris hack of never blocking is more useful. So what if a button press gets through to the game - rather that than not being able to use a button correctly :) I choose a slight annoyance over non functionality.
For the sake of the RetroPie project, we will likely change it in one of the ways mentioned already, as RetroArch want to keep their current behaviour.
I think it is more about your suggestion not being satisfactory enough on a technical level and you not wanting to take the time or effort to come up with some better proposal that would meet RA's requirements. We are not above merging a PR if it's any good, but it has to scale and have multiple purposes beyond just one specific Pi distro.
thanks - will submit whatever we come up with, even if just for feedback.
Since it was not designed to be used on a button that as one of the retropad buttons, why block at all ? Even @objectchris hack of never blocking is more useful. So what if a button press gets through to the game - rather that than not being able to use a button correctly :) I choose a slight annoyance over non functionality.
You are not understanding why it blocks. The MODIFIER was supposed to be a separate button, so you could have.... say A as a retropad button and A as... SAVE STATE, then you'd press modifier to use SAVE STATE.
If there isn't blocking then you'd press MODIFIER + A to SAVE STATE and it would jump AND save (making in many cases the savestate unusable). This is just an example, it could lead to many actions in the background, jump, shoot, run, exit, whatever.
The modifier was not supposed to be a retropad button but you are setting modifier by default to be SELECT which IS a retropad button and then expecting it to be both SELECT AND MODIFIER at the same time (which actually works!) except that in some games (not even cores) it seems the GAME expects the input to be active for more than one frame and by then it's already blocked since... IT IS A RETROPAD BUTTON.
Also, as you can see you're setting some defaults (that we do not) and people are asking us for support and thinking we did which is not the case.
The only reasonable comprimises that wouldn't introduce hacks I can see are:
I see your point regarding multiple presses - my brain somehow skipped over that when I wrote my reply. However in many cases I would still prefer your broken behaviour over current due to the problems it causes with some cores. My idea to only block if another key is pressed with the modifier would work though and not cause that behaviour, which would be an improvement. Your second option might also be a good workaround.
We set the defaults of select as a modifier as it's available on most gamepads, and seemed like a good choice. Users can change it of course. We have a system that people to want to work out of the box, so we have to choose something.
You said it yourself:
I would still prefer your broken behaviour over current due to the problems it causes with some cores
I WOULD
First. It doesn't cause problems in a core, it's a feature and it's not mandatory, it's not causing problems you're just using it incorrectly. Second. It was added because of public demand, if we don't block then the users will complain, maybe not yours but ours.
My idea to only block if another key is pressed with the modifier would work though and not cause that behaviour
This could work
hmmm but looking at the code it would be a mess to implement, good luck
yes - it was my own opinion - we all have them. I am not suggesting you make that change - we need something better.
There is no way else for us to use it "correctly" - when we need to support pads that don't have a special unused button.
Yes but the default behavior you impose is in fact problematic.
If there are no extra buttons what I (yes I) would expect is to have a button combo for menu, and for users to go into the menu and save states and manage their experience, after all... they don't have enough buttons.
If you fork it and keep it "not blocking" then we'll get random reports of stuff happening when using hotkeys which is very undesirable but no-one can stop you.
Bottom line, can the "issue" be fixed? yes, or at least worked around by making the block optional.
Wow, there's some serious discussion going on ;)
Sry if you got that the wrong way but i disn't want to sound demand at all, that's why i said PLEASE reopen it. It is in fact an issue since there is a feature that breaks the whole experience (blocking other buttons). There are workarounds like using other tools to recreate that hotkey functionality (i do that for project64) but that doesn't make sense when the functionality is already built in...
I'm using both a SNES controller (usb converter) and a x360 Controller. On the snes controller i don't have a spare button and some games are unplayable with the select button blocked.
I'm starting my games from steam or at least with steam running in the background, which means that longer presses on the guide button bring up the steam big picture screen, so there's no way for me (aka ppl who use the same configuration) to use the hotkey functionality.
The dolphin emulator has hotkeys too and they work without breaking the base buttons. Don't get me wrong i just thought it could help to look how they handle this.
I also don't want to be ungrateful or such, i really came to love retroarch and using it for almost all of my systems, i just want to point out that something isn't working. (Not just in my favor but for others too, when you google for that specific problem there are a lot of people wondering why it's not working properly)
btw in check_block_hotkey() is it correct that driver->block_hotkey is set twice ? the second time will overwrite the first unless there is something else going on I've missed ?
Before I get jumped on - yes it's horribly ugly (you did say it would be a mess to implement :) ). I am not suggesting this code goes into retroarch as it is, but it works from my initial testing - only blocking if another key is pressed at the same as the hotkey enable, and that key not being the hotkey enable key. Unfortunately I am very unfamiliar with the retroarch codebase, available functions and so on. I guess a lot of the logic could be simplified if we work out if the current hotkey enable is mapped to a control key in a better way, and somewhere else and keep it for later ? Or maybe it can just be simplified anyway by someone who knows the codebase better.
I also did a much simpler change that just checks for more than 2 keys pressed - but this assumed that the hotkey enable key is the same as a control key. anyway.. here we go.
diff --git a/runloop.c b/runloop.c
index b159d0e..12f2cbc 100644
--- a/runloop.c
+++ b/runloop.c
@@ -614,10 +614,14 @@ static bool check_block_hotkey(driver_t *driver, settings_t *settings,
bool enable_hotkey)
{
bool use_hotkey_enable;
- const struct retro_keybind *bind =
- &settings->input.binds[0][RARCH_ENABLE_HOTKEY];
- const struct retro_keybind *autoconf_bind =
- &settings->input.autoconf_binds[0][RARCH_ENABLE_HOTKEY];
+ const struct retro_keybind *binds[1];
+ const struct retro_keybind *autoconf_binds[1];
+ enum input_device_type device = INPUT_DEVICE_TYPE_NONE;
+ bool state = false;
+ int key;
+
+ binds[0] = settings->input.binds[0];
+ autoconf_binds[0] = settings->input.autoconf_binds[0];
/* Don't block the check to RARCH_ENABLE_HOTKEY
* unless we're really supposed to. */
@@ -627,20 +631,42 @@ static bool check_block_hotkey(driver_t *driver, settings_t *settings,
/* If we haven't bound anything to this,
* always allow hotkeys. */
use_hotkey_enable =
- (bind->key != RETROK_UNKNOWN)
- || (bind->joykey != NO_BTN)
- || (bind->joyaxis != AXIS_NONE)
- || (autoconf_bind->key != RETROK_UNKNOWN )
- || (autoconf_bind->joykey != NO_BTN)
- || (autoconf_bind->joyaxis != AXIS_NONE);
+ (binds[0][RARCH_ENABLE_HOTKEY].key != RETROK_UNKNOWN)
+ || (binds[0][RARCH_ENABLE_HOTKEY].joykey != NO_BTN)
+ || (binds[0][RARCH_ENABLE_HOTKEY].joyaxis != AXIS_NONE)
+ || (autoconf_binds[0][RARCH_ENABLE_HOTKEY].key != RETROK_UNKNOWN )
+ || (autoconf_binds[0][RARCH_ENABLE_HOTKEY].joykey != NO_BTN)
+ || (autoconf_binds[0][RARCH_ENABLE_HOTKEY].joyaxis != AXIS_NONE);
driver->block_hotkey =
input_driver_keyboard_mapping_is_blocked() ||
(use_hotkey_enable && !enable_hotkey);
- /* If we hold ENABLE_HOTKEY button, block all libretro input to allow
- * hotkeys to be bound to same keys as RetroPad. */
- return (use_hotkey_enable && enable_hotkey);
+ /* If we hold ENABLE_HOTKEY button and another modifier is pressed,
+ * block all libretro input to allow hotkeys to be bound to same keys
+ * as RetroPad. */
+ if (use_hotkey_enable && enable_hotkey)
+ {
+ /* check for a modifier being pressed if it isn't the same as the enable_hotkey button */
+ for (key = 0; key < RARCH_FIRST_CUSTOM_BIND; key++)
+ {
+ if
+ ((binds[0][key].key != RETROK_UNKNOWN && binds[0][key].key == binds[0][RARCH_ENABLE_HOTKEY].key)
+ || (binds[0][key].joykey != NO_BTN && binds[0][key].joykey == binds[0][RARCH_ENABLE_HOTKEY].joykey)
+ || (binds[0][key].joyaxis != AXIS_NONE && binds[0][key].joyaxis == binds[0][RARCH_ENABLE_HOTKEY].joyaxis)
+ || (autoconf_binds[0][key].key != RETROK_UNKNOWN && autoconf_binds[0][key].key == autoconf_binds[0][RARCH_ENABLE_HOTKEY].key)
+ || (autoconf_binds[0][key].joykey != NO_BTN && autoconf_binds[0][key].joykey == autoconf_binds[0][RARCH_ENABLE_HOTKEY].joykey)
+ || (autoconf_binds[0][key].joyaxis != AXIS_NONE && autoconf_binds[0][key].joyaxis == autoconf_binds[0][RARCH_ENABLE_HOTKEY].joyaxis)) {
+ continue;
+ }
+
+ state = driver->input->key_pressed(driver->input_data, key, &device);
+ if (state)
+ return true;
+ }
+ }
+
+ return false;
}
/**
so any help you can give me to clean it up would be great thanks :)
Actually it doesn't look that bad I can't test now and @twinaphex would have to review it. So basically this blocks only if one of the other pressed buttons is mapped as a hotkey?
it only blocks if the hotkey enable + any other controller button (key 0-15) is pressed. Still means that in say an arcade game, if select is the hotkey enable, and you press that and up, a coin in could be triggered, but the up wont trigger. so it's still a workaround, but would certainly improve things for cases where select is a hotkey (and most games select doesn't do anything bad like jump etc)
Hi all, any bind of the hotkey function on a non-extra button will cause you problems soon or late. It's obvious that there are so much games out there that use internal combos (for example Final Fantasy's SELECT+START+L1+R1) that your use of the hotkey will block a functionnality in the game.
That's why in Lakka we don't use that hotkey bind by default, and we suggest users to invest in joypads with enough keys (16 keys). The quick menu offers enough contextual actions like savestates and is easily extensible, unlike the input system.
If you know another better way to handle this without loosing any functionnality on any game, I may follow you. But I doubt such a solution exists.
I agree there is no perfect solution, however, I do believe my changes make it better than it is currently at least for RetroPie and anyone else who is stuck with a limited controller (and the changes shouldn't make a difference at all if the hotkey enable is an unused button - it will just block once the modifier is pressed at the same time). Should the changes not be suitable for RetroArch we can always maintain our own fork/patchset at RetroPie etc.
If the workaround is clean and it works I'm all for it, I have controllers with enough buttons but I have some NES30s / SNES30s and it might prove useful (retro controllers are popular)
I have thought about this. How about registering the hotkey press when the hotkey button is pushed down. So as long as it's pushed down and any other mapped hotkey button is pressed -> Hotkey fires. when only the hotkey is pressed AND released -> default button.
Would make sense cause no one will press the hotkeybutton without any other button for hotkey button except for default behaviour (like select) and when you want to load state or whatever, just keep it pushed down?
Don't have a clue about that's possible or difficult to implement but that would be an awesome and clean solution for everyone!
I've tested the above code and these are my thoughts:
I was testing with my snes controller with donkey kong country. On teamplay the select button switches players so it can be a bit of a nuisance if the select key provides some function but its much less of a nuisance than not working at all to input coins on mame games. (this is my personal preference though, it may drive other people bonkers.)
With games like super mario world with two player mode the right shoulder button in the menu lets you give lives to the other player so if you are in the world map and your hotkeys are select+right shoulder, every time you save it will open up that menu:
so as far as I see it either we deal with the inconvenience of keys firing when using hotkeys or we deal with the key not firing because its a hotkey (in cases like mame not inputting coins)
The only middle ground I can think of is if we block the second keypress in game if the hotkey is pressed (as discussed above) I'm not sure if that is what the code was intending to do and just isn't working as intended- if so it isn't blocking the second keypress as it should and that part of the code needs to be addressed. seems it's currently working the same way as @objectchris hack is in always returning false. feel free to verify.
It's intended to block EVERYTHING (the original code)
Hi :)
With all non-arcade cores I've tested, there appears to be no issue with having the hotkey bound to a button with a normal function. For example, I use SNES USB controllers and use the select button as my hotkey. In SNES/NES cores, the select button functions in the game as usual (eg, to select 1 or 2 player in Super Mario), but also does all the extra hotkey functions, like select+start = quit, select+Y= retroarch GUI.
However, with every single MAME/FBA core I'm able to run (Raspberry Pi 2 + Retropie), the select button does not do its insert coin function in SOME games. Insert coin works fine if I bind it to a different button to the hotkey, but with an 8 button controller that just means you have a new problem (eg, in SFII I get a new credit every time I heavy kick :))
There are previously raised issues with the cores themselves: https://github.com/libretro/mame2003-libretro/issues/8 https://github.com/libretro/fba-libretro/issues/46 https://github.com/libretro/imame4all-libretro/issues/9 ...but according to your forums, it sounds like this is intentional (http://libretro.com/forums/showthread.php?t=4184&p=29268)? This seems wrong to me as it would mean users would not be able to use NES/SNES/PSX etc controllers in their respective cores, because you wouldn't have a spare button for a hotkey.
So my thought is that this is a core retroarch issue, where apparently the hotkey intentionally blocks the hotkey button's regular function (at least, in some cores/scenarios). Can this be changed?