Is it possible to add accelerators (hotkeys) to a custom control?

Diagnstico Reporte Fecha: 12/23/18
Now that bevel buttons are unusable in 2019r2, I wanted to resume the development of a custom button, however, a big show stopper it is the lack of accelerator keys in a custom canvas. The Bevel button has this function, and the Label does a great job having a AcceleratorKey Event and drawing the underscored character on the Text.

Is there any way to currently implement them in a custom canvas control?

I typically fix this by drawing the accelerator signifier then creating a MenuItem for the key combination. Not the most accurate answer, but it does work.

would seem that Xojo likely already calls either LoadAccelerators or CreateAcceleratorTable
but that seems the route to poke at to get access to the accelerator table then you could maybe add one ?

I just havent sorted this stuff out but that seems the way to go

https://docs.microsoft.com/en-ca/windows/win32/menurc/using-keyboard-accelerators#loading-the-accelerator-table-resource

For a canvas, as far as I understand it, drawing the accelerator underline using DirectWrite will be impossible as we don’t have a access the internals of the IDWriteFactory.

Pop in a feature request in, if the Label is already rendering accelerators using DirectWrite it might be a quick fix to allow it in Graphics.DrawText

The way around it is to drop a label onto your canvas and set the label to transparent. MouseDown on the canvas will ignore the label in front of it.

You could also use a container control with a label on it and set it all up nicely so you’re none the wiser that its a container other than all your buttons will have twice the number of controls and your UI will be a bit slower due to transparency being used.

You could use the Keyboard class to detect key combinations and trigger actions in a multiple timer.

http://documentation.xojo.com/api/hardware/keyboard.html

Wow, I didnt know that I can put a menu handler on a window even if the window has the menu bar as “None” . For a custom button, sounds impractical, create all the menu items, adding the event handdlers in the windows, calling the action event of the button. Any change on the buttons requiere a change in the menu items/handdlers.
It is a great hack, can solve some other issues, thanks.

[quote=461119:@Norman Palardy]would seem that Xojo likely already calls either LoadAccelerators or CreateAcceleratorTable
but that seems the route to poke at to get access to the accelerator table then you could maybe add one ?

I just havent sorted this stuff out but that seems the way to go

https://docs.microsoft.com/en-ca/windows/win32/menurc/using-keyboard-accelerators#loading-the-accelerator-table-resource[/quote]

I think of that, but Xojo is not saving the accelerator table as a resource like a native app, maybe they create the table on the fly so I think it is not posible to add more accelerators without breaking the current table and adding subclassing to the window.

[quote=461127:@Michel Bujardet]You could use the Keyboard class to detect key combinations and trigger actions in a multiple timer.
http://documentation.xojo.com/api/hardware/keyboard.html[/quote]

Doable, but sounds like a waste having a timer running all the time to check the keyboard status. Plus, the same problem of having all the actions in one place and then calling the Action event of the buttons from there even to another window, not flexible and a ightmare to mantain. But thanks for the idea.

Already done: <https://xojo.com/issue/57970>[quote=461126:@]The way around it is to drop a label onto your canvas and set the label to transparent. MouseDown on the canvas will ignore the label in front of it.

You could also use a container control with a label on it and set it all up nicely so you’re none the wiser that its a container other than all your buttons will have twice the number of controls and your UI will be a bit slower due to transparency being used.[/quote]

For a custom control it should be a container, not pretty, but maybe the best option. thanks

[quote=461129:@Ivan Tellez]
I think of that, but Xojo is not saving the accelerator table as a resource like a native app, maybe they create the table on the fly so I think it is not posible to add more accelerators without breaking the current table and adding subclassing to the window.[/quote]
I wasnt sure if there was a way to get the ones that already exist in an in memory table or not
I’m not a Win32 API expert and never claimed to be
It was just some reading I was doing to see about supporting them in my bevelbutton replacement class

It is not that difficult to implement in a custom control, and the notion of “waste” when it comes to event handlers is debatable. Such timer would fire every 200 ms or so. I don’t understand what you mean by “not flexible and a ightmare to mantain.”. The timer being part of it, the custom control would be self contained. Clean, simple.

It is not as if you had dozens of solutions available …

Polling the keyboard status, instead of receiving just an event sent by the keyboard controller, makes an intensive use of CPU, never getting idle, that IF you can avoid, is the best solution.

Sure, when the OS makes the work and your app only gets the event (like with the native accelerators) there is no waste, but polling the state is not an event. As @Rick Araujo said, polling the state, check if the correct keys are pressed, having variables and more checks to control how ofthen the event should be fired and avoid accidental double events, etc.

All of that takes cpu time, to be self contained, will take a timer for each button, those 200 ms, times 20 or more buttons active at a time not only will affect the app performace, it could lead to missing events, especially on the not threaded Xojo. The only way to minimize the waste of cpu is having a single timer procesing ALL the accelerators and dispatching the event to its corresponding button that is the “Nightmare to mantain part” adding buttons and separated handlers for the accelerators.

OK OK OK

The ideal solution would be to hook the keyboard event the same way menus and keyboard shortcuts do.

It seems quite feasible with a declare. Now it’s up to brilliant declare coders to do the job.

Can’t the intended behavior have a menu item also? So, pressing the button. or firing the shortcut keys. or selecting the menu option, does the same?

I already suggested this and it was dismissed.

So, only Xojo can help in the proper way.

Not really. I’ve been playing with WFS and it works to register and catch the hotkey. Just needs to be modified to support canvas objects rather than windows.

If I had the time to do it right now, I would, because this is something I have to do for a future project.

Of course, the same functionality would need to be built for the other targets.

The problem here is that not all apps have a menu, specially if it is not intendended for mac. In my main app, there are more than 150 bevel buttons with accelerators, but zero menus, So, creating the 150+ MenuItems adding the equal number of handdlers in the many windows, link them to the action events of the buttons and doing all that each time a button has to be changed/replaced/added, it is far from ideal.

The problem with WFS is that those are system wide HotKeys, they will fire even if your app is not visible. If another app has an accelerator with the same key combination and you are in that app and press those keys, it will fire the one in your app, so unles your app is the only one running, it could lead to very problematic situations.

Correct, but you could easily check for window focus in your hotkey event, no? If the window isn’t activated, do nothing. The key event on the other window will still fire, IIRC, as long as you return False (I’m pretty sure, I don’t have the project open any longer and don’t remember).

Wow. I would prefer to click on those things than remembering the “shortkeys”. :smiley:

Do we have the possibility of creating 150 alt-letters?

You have no idea the speed gain in the work with those in this case.

ROFL, last time i checked, there are not 150 letters. The window with more buttons at a time has 15.

Yes, the message is also received in the focused app that way. Te missing part is and what I dont know is if it can be self contained with its own WndProc in the custom control.