Regarding Accelerators

Just starting out? Need help? Post your questions and find answers here.
jscholes
User
User
Posts: 15
Joined: Fri Nov 28, 2014 8:38 pm

Regarding Accelerators

Post by jscholes »

Hello,

I'll begin this post by saying that I've only been learning PureBasic for a few hours, but I've hit up against a problem which, for my coding purposes, may be a bit of a deal breaker. I'm developing on Windows 7. Here's what I want to create, to demonstrate this problem:

A user authentication window with the following controls:
A label and text field for a person's username;
A label and a text field for the person's password;
A Connect button; and
a Help button.

An extremely simple window. The labels for the controls, in my code, are as follows:

Code: Select all

"&Username"
"&Password"
"&Connect"
"&Help"
In the past, I've created GUIs using wxWidgets (wxPython), C#/WinForms, AutoHotkey and AutoIt. In all of those cases, creating a form with the labels stated above would exibhit the following behaviour in terms of keyboard access:

1. Pressing Alt+U or Alt+P would focus the Username or Password field, respectively;
2. Pressing Alt+C or Alt+H would activate the Connect or Help button, respectively; and
3. If the keyboard focus was placed on one of the buttons, Alt would not need to be added to these combinations (so a user could, for example, while focussed on the Connect button, press H to activate Help or U to jump to Username).

This is completely standard behaviour in most GUIs on Windows. No additional effort is required on the part of the programmer to make these standard features of native controls work. They just... do, regardless of the language or GUI toolkit in use. However, PureBasic seems not to allow this. Visually, the letters designated as accelerators in the control labels are underlined, and if the controls are queried using accessibility APIs, the accelerators are recognised. However, trying to use any of the expected functionality outlined above results in absolutely nothing. If I press Alt+U, Alt+P, Alt+C or Alt+H, I hear a default Windows ding sound, and if I focus on one of the buttons and then press U, P, C or H, nothing happens at all.

I can't use AddKeyboardShortcut in these cases, partly because it would add tons of unnecessary boilerplate to my code, but mainly because these keyboard-based interactions are standard. They are expected to work a certain way for the end user and, despite the fact that I am primarily a keyboard user myself, it would take lots of effort on my part to replicate them. Defining hotkeys for Alt+U, Alt+P etc and using SetActiveGadget is all very well and good, but it wouldn't address the problem of single-key shortcuts when a button is focussed rather than a text field. Plus, the problems would just keep growing as I added different types of controls to my interface, and it would quickly become unmanageable. Is the user focussed on a check box or button? If so, allow single-key shortcuts. If not, don't. But then I might add radio buttons to my interface, which from a keyboard user's perspective have a completely different set of rules and expected behaviour that I then have to deal with.

Sorry for the long post, and I'll be happy to clarrify any of my points. Keyboard access is a complex topic, but the majority of my users will be keyboard-only ones, so it needs to be done right. Windows gets it right in most cases, but it seems like PureBasic isn't allowing it to.

Here is my code. Please excuse the control spacing and layout - I'm a completely blind developer so if somebody decides to change the dimensions before running my sample, I'd appreciate knowing what you've changed.

Code: Select all

EnableExplicit

Enumeration
    #WindowMain
    #UsernameText
    #UsernameField
    #PasswordText
    #PasswordField
    #ConnectButton
    #HelpButton
EndEnumeration

Procedure ConnectButtonHandler()
    MessageRequester("Connect", "The Connect button was pressed.")
EndProcedure

Procedure HelpButtonHandler()
    MessageRequester("Help", "The Help button was pressed.")
EndProcedure

Procedure WindowCreate()
    Protected Flags
    Flags = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget| #PB_Window_TitleBar
    OpenWindow(#WindowMain, 50, 50, 450, 400, "Accelerator Test", Flags)
    TextGadget(#UsernameText, 5, 10, 10, 10, "&Username")
    StringGadget(#UsernameField, 10, 10, 10, 10, "")
    TextGadget(#PasswordText, 5, 10, 10, 10, "&Password")
    StringGadget(#PasswordField, 10, 10, 10, 10, "", #PB_String_Password)
    ButtonGadget(#ConnectButton, 10, 10, 10, 10, "&Connect")
    BindGadgetEvent(#ConnectButton, @ConnectButtonHandler())
    ButtonGadget(#HelpButton, 30, 10, 10, 10, "&Help")
    BindGadgetEvent(#HelpButton, @HelpButtonHandler())
    SetActiveGadget(#UsernameField)
EndProcedure

Procedure WindowDestroy()
    CloseWindow(#WindowMain)
EndProcedure

Define.l Event, EventWindow, EventGadget, EventType, EventMenu
WindowCreate()

Repeat
    Event = WaitWindowEvent()
    EventWindow = EventWindow()
    EventGadget = EventGadget()
    EventType = EventType()
    
    Select Event
        Case #PB_Event_CloseWindow
            If EventWindow = #WindowMain
                WindowDestroy()
                Break
            EndIf
    EndSelect
Forever
User avatar
skywalk
Addict
Addict
Posts: 4219
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Regarding Accelerators

Post by skywalk »

Far less code than your post to implement 4 AddKeyboardShortcut()'s.
While it may appear as standard action in other development tools, in PB you must program exactly what you need. You will find this level of control much more powerful as you build larger apps. :wink:
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Zebuddi123
Enthusiast
Enthusiast
Posts: 796
Joined: Wed Feb 01, 2012 3:30 pm
Location: Nottinghamshire UK
Contact:

Re: Regarding Accelerators

Post by Zebuddi123 »

Hi jscholes & welcome :) look up AddKeyboardShortcut( I`ve added shortcut Alt+U below and hi-lighted I think you`ll pick it up pretty easily

Zebuddi.

Code: Select all

EnableExplicit

Enumeration
	#WindowMain
	#UsernameText
	#UsernameField
	#PasswordText
	#PasswordField
	#ConnectButton
	#HelpButton
EndEnumeration

Procedure ConnectButtonHandler()
	MessageRequester("Connect", "The Connect button was pressed.")
EndProcedure

Procedure HelpButtonHandler()
	MessageRequester("Help", "The Help button was pressed.")
EndProcedure

Procedure WindowCreate()
	Protected Flags
	Flags = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget| #PB_Window_TitleBar
	OpenWindow(#WindowMain, 50, 50, 450, 400, "Accelerator Test", Flags)
	TextGadget(#UsernameText, 5, 10, 10, 10, "&Username")
	StringGadget(#UsernameField, 10, 10, 10, 10, "")
	TextGadget(#PasswordText, 5, 10, 10, 10, "&Password")
	StringGadget(#PasswordField, 10, 10, 10, 10, "", #PB_String_Password)
	ButtonGadget(#ConnectButton, 10, 10, 10, 10, "&Connect")
	BindGadgetEvent(#ConnectButton, @ConnectButtonHandler())
	ButtonGadget(#HelpButton, 30, 10, 10, 10, "&Help")
	BindGadgetEvent(#HelpButton, @HelpButtonHandler())
	SetActiveGadget(#UsernameField)
EndProcedure

Procedure WindowDestroy()
	CloseWindow(#WindowMain)
EndProcedure

Define.l Event, EventWindow, EventGadget, EventType, EventMenu, event_menu
WindowCreate()


;--------------------------------------------------------------------   add the shortcut
AddKeyboardShortcut(#WindowMain,#PB_Shortcut_Alt | #PB_Shortcut_U,15) 
;--------------------------------------------------------------------

Repeat
	Event = WaitWindowEvent()
	
	Select Event
		Case #PB_Event_CloseWindow
			If EventWindow = #WindowMain
				WindowDestroy()
				Break
			EndIf
	EndSelect

	;-------------------------------------------------------------  test for menu event  event number will be 15  as assigned in AddKeyboardShortcut(
	Select EventMenu()					
		Case 15
			MessageRequester("hey","you selected Alt+U")
	EndSelect
	;-------------------------------------------------------------

ForEver
malleo, caput, bang. Ego, comprehendunt in tempore
jscholes
User
User
Posts: 15
Joined: Fri Nov 28, 2014 8:38 pm

Re: Regarding Accelerators

Post by jscholes »

skywalk wrote:Far less code than your post to implement 4 AddKeyboardShortcut()'s.
While it may appear as standard action in other development tools, in PB you must program exactly what you need. You will find this level of control much more powerful as you build larger apps. :wink:
Thanks for your reply, but allow me to clarrify a few points.

I appreciate PureBasic's flexibility, but the functionality I am talking about is a part of the native controls that PureBasic's gadgets wrap. This behaviour is as standard as the clicking of a button to activate it, or the pressing of Space on a check box to toggle it. This behaviour is not left up to the programmer to implement unless they absolutely wish to, and it is this way for a reason. Because accessibility support already exists and is standardised to provide a native, accessible look-and-feel.

Secondly, I outlined in my post why AddKeyboardShortcut is unsuitable, but let me try to make it a bit less convoluted.

When I open a program, I can tab through the controls of its windows. In my example user authentication window, I can tab from the Username field, to the Password one, to the Connect button, and finally to Help and then back around. However, if I have a large window with a lot of controls, this can take a lot of time, so keyboard shortcuts can be added to native controls to allow a user to quickly jump to them. In this example, Alt+P should move focus to the Password field. As you say, it would be trivial to add that facility myself, but that is just scraping the surface of keyboard access. Because, if I am focussed on controls which do not accept direct user input, e.g. a button or a check box, i.e. controls you cannot type into, according to standard platform behaviour, Alt becomes unnecessary. So, if keyboard focus is placed on the Connect button, and then I press the letter U, focus should move to the Username field.

This isn't a feature that the programmer should need to add, this is a feature which PureBasic is missing. I say this because, according to accessibility tools and the visual display, my text fields and buttons already have accelearators. But PureBasic is not allowing them to do anything.

The final point I'll make as that if you write a Win32 GUI-based program in C or C++, you achieve the ultimate in code flexibility. You can make or break things as you wish, even more so than you can in PureBasic. But this behaviour is a part of native controls by default, even when using those languages, because it is expected and widely known. It's also, incidentally, why PureBasic's IDE offers no Alt+X (where X is any letter) shortcuts in places like the Preferences dialog, because presumably it is far too much work to add them and have them work correctly.

Here is a quote from the Wikipedia page on the Ampersand:
In Microsoft Windows menus, labels and other captions, the ampersand is used to denote the keyboard shortcut for that option (Alt + that letter, which appears underlined). A double ampersand is needed in order to display a real ampersand. This convention originated in the first WIN32 api, and is used in Windows Forms,[25] and is also copied into many other toolkits on multiple operating systems.
User avatar
skywalk
Addict
Addict
Posts: 4219
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Regarding Accelerators

Post by skywalk »

I don't really see a question? :|
It is true there are many dialogs in the IDE that have no keyboard action.
But, these are only a pain if used in rapid succession like a Find dialog. Here you absolutely need a "&Next" or "&Replace" keystroke to save mouse positioning and clicking.
They are not critical in a seldom used preferences dialog.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
jscholes
User
User
Posts: 15
Joined: Fri Nov 28, 2014 8:38 pm

Re: Regarding Accelerators

Post by jscholes »

skywalk wrote:I don't really see a question? :|
It is true there are many dialogs in the IDE that have no keyboard action.
But, these are only a pain if used in rapid succession like a Find dialog. Here you absolutely need a "&Next" or "&Replace" keystroke to save mouse positioning and clicking.
They are not critical in a seldom used preferences dialog.
Okay, I'll try to explain, one more time, with a simpler demonstration. I don't mind providing explanation, because this is something which, for users who don't rely on the keyboard 100% of the time, is quite hard to grasp. I respect that.

Look at this code:

Code: Select all

Result = MessageRequester("Hello", "Would you like to continue?", #PB_MessageRequester_YesNo)
If Result = #PB_MessageRequester_Yes
    MessageRequester("Hello", "You pressed Yes!")
Else:
    MessageRequester("Hello", "You pressed No!")
EndIf
End
All this does is prompt the user to press either Yes or No, using a MessageRequester. But MessageRequester makes a call to the underlying MessageBox function of the Windows API, which is responsible for displaying the dialog.

The Windows API is accessibility-aware, so in this dialog, you can press either Alt+Y or simply Y on its own to activate the Yes button. Similarly, Alt+N or N to activate No. Internally, when you press one of these keys, the appropriate event is fired. Crucially, it's the same event which would be fired if you activated the button by clicking your mouse or pressing Space or Return.

Now, I see tons of these dialogs every day when deleting files, closing text editors, etc. And instinctively, I press Y, or N. Straight away. I don't stop to think about whether the dialog supports such an operation, because if it is displayed as a native Windows API message box, it will, no question.

So, why is this demonstration relevant to my problem? Because, if you run the above code on, say, a system with the OS language set to Spanish, the button label for "Yes" will automatically show as "Sí". So a Spanish end user, without any extra effort on my part, can press S, or Alt+S, to activate that button. Do you see where I'm going with this? My final product, regardless of what language I choose to write it in, needs to be multilingual. It's keyboard shortcuts need to reflect the interface language. A Spanish user will not press Alt+P to activate a password field, they will press Alt+C for "contraseña" (the Spanish for password). When I ask my translators to prepare message files for the application, I will instruct them to place an ampersand before the letter which should become the keyboard shortcut for the control with the particular message ("&contraseña"). In every other system I can think of, or at least, every other system I have worked with even in passing, this would be the best, and most accepted, workflow. This is how mainstream software developers do keyboard shortcuts. This is how Microsoft Word and Adobe Photoshop have language-aware shortcut keys. In PureBasic, the more languages I add, the more hotkeys I have to bind. I have to bind different events based on different languages, different keyboard focus states, and tons of other factors. It's inefficient and completely not viable.
User avatar
skywalk
Addict
Addict
Posts: 4219
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Regarding Accelerators

Post by skywalk »

So are you asking if multi-language support is accomplished without code but a feature request?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
jscholes
User
User
Posts: 15
Joined: Fri Nov 28, 2014 8:38 pm

Re: Regarding Accelerators

Post by jscholes »

skywalk wrote:So are you asking if multi-language support is accomplished without code but a feature request?
No. I am asking if keyboard accelerators can be made to work properly in PureBasic. UI translation was just an example I was using to try to make the problem a bit clearer.
User avatar
skywalk
Addict
Addict
Posts: 4219
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Regarding Accelerators

Post by skywalk »

Of course they can. You will have to map out languages in a separate include or datasection.
Concentrate on the mechanics of PB event loops and menu events which are related to keyboard shortcuts. It is not as burdensome as you imply.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
jscholes
User
User
Posts: 15
Joined: Fri Nov 28, 2014 8:38 pm

Re: Regarding Accelerators

Post by jscholes »

skywalk wrote:Of course they can. You will have to map out languages in a separate include or datasection.
Concentrate on the mechanics of PB event loops and menu events which are related to keyboard shortcuts. It is not as burdensome as you imply.
Thanks again for your input, but you're simply not understanding the problem. I'll keep investigating.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Regarding Accelerators

Post by PB »

> When I ask my translators to prepare message files for the application,
> I will instruct them to place an ampersand before the letter which should
> become the keyboard shortcut for the control

See here for a way to do that:

http://www.purebasic.fr/english/viewtop ... 12&t=61087

Hope it helps!
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Regarding Accelerators

Post by PB »

> This is how Microsoft Word and Adobe Photoshop have language-aware shortcut keys

Word and Photoshop just do something similar to my tip above.
As an end-user, you just don't get to see it. PureBasic doesn't
do as much hand-holding as other coding languages, which is
both its strength, and its weakness in your particular eyes. ;)

But as I've shown, it's easy to set it up with a simple loop.
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
jscholes
User
User
Posts: 15
Joined: Fri Nov 28, 2014 8:38 pm

Re: Regarding Accelerators

Post by jscholes »

PB wrote:> When I ask my translators to prepare message files for the application,
> I will instruct them to place an ampersand before the letter which should
> become the keyboard shortcut for the control

See here to do that:

http://www.purebasic.fr/english/viewtop ... 12&t=61087

Hope it helps!
Many thanks for your code, clearly, you know the language thoroughly and that is a decent crack at solving the problem. But the simple fact is, you're reinventing the wheel. Win32 already provides this functionality, and unless I can get access to it using PB, the language won't be viable for me. Maybe for some projects, but the one I'm working on at the moment requires keyboard accessibility to be spot on. Windows already has it spot on, and has been refining it since the very first iteration of the Win32 API. I don't feel comfortable reimplementing something that's had twenty years of user feedback and enhancement, nor do I think I should have to. I do consider this a PB bug.
jscholes
User
User
Posts: 15
Joined: Fri Nov 28, 2014 8:38 pm

Re: Regarding Accelerators

Post by jscholes »

PB wrote:> This is how Microsoft Word and Adobe Photoshop have language-aware shortcut keys

Word and Photoshop just do something similar to my tip above.
As an end-user, you just don't get to see it. PureBasic doesn't
do as much hand-holding as other coding languages, which is
both its strength, and its weakness in your particular eyes. ;)

But as I've shown, it's easy to set it up with a simple loop.
Please read my post above in which I state, quite accurately, that if you write an application completely from scratch using the Win32 API in a language like C, which doesn't even understand the concept of "hand holding", accelerators still work properly. They are a core part of the Windows native GUI experience. They are not something to be bolted on by every programmer. wxWidgets, WinForms, Delphi, AutoHotkey... none of these systems implement specific logic like yours to make this functionality work, because it should work out of the box. I would like to drill down into why, with PureBasic, it does not.
PB
PureBasic Expert
PureBasic Expert
Posts: 7581
Joined: Fri Apr 25, 2003 5:24 pm

Re: Regarding Accelerators

Post by PB »

> Win32 already provides this functionality

You can always directly call any Win32 API command in that case.

PureBasic is NOT for Windows. It's for Windows, Linux, and Mac.

This is probably where your frustration lies. Anything that you expect to
work because of Win32 is not the case here. Each and every command
and gadget has to work the same way on all three platforms, or it simply
isn't supported. This doesn't make it a PureBasic bug, though. It's a design
decision/limitation/whatever.

If you want/expect Win32 functionality, then either use those commands
directly in your PureBasic source (they are supported), or just use another
language. Sorry to be the bearer of this bad news. :(

> I would like to drill down into why, with PureBasic, it does not.

Now you know. ;)
I compile using 5.31 (x86) on Win 7 Ultimate (64-bit).
"PureBasic won't be object oriented, period" - Fred.
Post Reply