Shortcut Key That Works Globally

How can I make a shortcut key that works across the whole of the application. What I have tried so far is making a menubar, setting the app’s menubar as that menubar, adding the items with the shortcut keys and then adding a menu handler to the app.

I have noticed that if the window has a menubar however, this will interfere with the app’s menubar.

How can I workaround this issue?

Thanks

[quote=185691:@Oliver Scott-Brown]How can I make a shortcut key that works across the whole of the application. What I have tried so far is making a menubar, setting the app’s menubar as that menubar, adding the items with the shortcut keys and then adding a menu handler to the app.

I have noticed that if the window has a menubar however, this will interfere with the app’s menubar.

How can I workaround this issue?

Thanks[/quote]

Timer to monitor Keyboard.AsyncKeydown ? That would be global and would supersede menus.

use only 1 menubar, and use EnableMenuitems if you want to exclude certain menus in certain windows.

I was going to attempt that. I have written a system for basic shortcut key use. What kind of technique would you recommend to implement pioritised keys. Does it really matter which key is pressed first as long as all of the keys included in the shortcut key are pressed. What I mean is for example, if you are using Chrome you can press Ctrl+1 to navigate to the first tab on Windows. But if you press 1 and then while holding 1, you press control then the shortcut key will not occur.

Thanks

But I want to design more than one menubar. Are you saying I should make the menubar code-based rather than using the menubar designer?

Thanks

No, If you want MenuXXX not in Window1 you add EnableMenuitems Event to Window1 and then

MenuXXX.Enabled = False
MenuXXX.Visible = False

I would stay away from that kind of subtleties. The average user has enough trouble with regular shortcuts as it is.

Ctrl then number is rather unusual, and completely out of Windows Design guidelines.

That’s not correct. See Keyboard (Windows) where Ctrl+any number is recommended:

[quote]Choosing shortcut keys
For well-known shortcut keys, use the standard assignments.
For non-standard key assignments, use the following recommended shortcut keys for more frequently used commands. These shortcut keys are recommended because they don’t conflict with the well-known shortcuts and are easy to press.
Ctrl+G, J, K, L M, Q, R, or T
Ctrl+any number
F7, F8, F9, or F12
Shift+F2, F3, F4, F5, F7, F8, F9, F11, or F12
Alt+any function key except F4[/quote]

Think about it. When you punch 1 in a Text control, how are you going to know if it will be a hot key or 1 ? That is the reason why the modifier always comes first. You could deal with that by holding somehow the “1” in keydown until within a given time frame Ctrl is depressed or not, then release it if Ctrl has not been punched, but over the fact that this kind of key manipulation is as rare as a two dollars bill, it is probably a hellish piece of code to program. Keep it simple, go Ctrl+key.

Eli,

The OP asked about holding number, THEN press Ctrl. That is absolutely not part of Microsoft guidelines, especially not the document you link to. I even wonder if it would be feasible.

Microsoft recommends what has always been the case, Ctrl+key, which means in most cases holding the modifier then punch the key. Or press them simultaneously.

[quote=185733:@Michel Bujardet]Think about it. When you punch 1 in a Text control, how are you going to know if it will be a hot key or 1 ? That is the reason why the modifier always comes first. You could deal with that by holding somehow the “1” in keydown until within a given time frame Ctrl is depressed or not, then release it if Ctrl has not been punched, but over the fact that this kind of key manipulation is as rare as a two dollars bill, it is probably a hellish piece of code to program. Keep it simple, go Ctrl+key.

Eli,

The OP asked about holding number, THEN press Ctrl. That is absolutely not part of Microsoft guidelines, especially not the document you link to. I even wonder if it would be feasible.

Microsoft recommends what has always been the case, Ctrl+key, which means in most cases holding the modifier then punch the key. Or press them simultaneously.[/quote]
I don’t know if I miss wrote it or you misunderstand what I wrote but what I meant was if you press a number key and then press control, this shouldn’t activate the shortcut key.

It does not. The number key is taken into account immediately, and pressing the control key afterward does nothing.

In terms of coding your global hot key, what you got to do is check if the modifier is already depressed when you check the AsyncKeydown.

Something like (taken from the LR examples)

If keyboard.ControlKey then If Keyboard.AsyncKeyDown(&h12) then //Here comes what you want to do with Ctrl-1 Msgbox "Ctrl+1" end if end if

[quote=185759:@Michel Bujardet]It does not. The number key is taken into account immediately, and pressing the control key afterward does nothing.

In terms of coding your global hot key, what you got to do is check if the modifier is already depressed when you check the AsyncKeydown.

Something like (taken from the LR examples)

If keyboard.ControlKey then If Keyboard.AsyncKeyDown(&h12) then //Here comes what you want to do with Ctrl-1 Msgbox "Ctrl+1" end if end if[/quote]
You still seem to have misunderstood what I was saying. I meant that what SHOULD NOT happen if you press the number key before pressing the control key is the functionality for the shortcut key gets executed. As far as I am aware, this code will not achieve that.

Thanks

[quote=185767:@Oliver Scott-Brown]You still seem to have misunderstood what I was saying. I meant that what SHOULD NOT happen if you press the number key before pressing the control key is the functionality for the shortcut key gets executed. As far as I am aware, this code will not achieve that.

Thanks[/quote]

Read the code. If the Ctrl key is not down first, nothing happens.

If the Ctrl Key is down, then if it is the 1 key, code executes.

If you first press 1, it simply cannot trigger the hot key.

Why don’t you simply put the code I posted in a multiple timer with period 17-100, and see for yourself ?

When I post something, it is tested ! True science is not about speculation only. It is also about experimentation. Then you will be truly aware.

Michel, the code does fire if you hold the 1 and then press ctrl… It needs a check to see if control was pressed first. Here’s a revised version.

[code] Static lastCheckControlKeyOnly As Boolean=false

If lastCheckControlKeyOnly then
If Keyboard.AsyncKeyDown(&h12) then
//Here comes what you want to do with Ctrl-1
Msgbox “Ctrl+1”
end if
end if

lastCheckControlKeyOnly=keyboard.ControlKey and not Keyboard.AsyncKeyDown(&h12)
[/code]
This would get messy fast if you had multiple shortcuts to implement as you would need to check each key. You could however created a timer subclass with an array of keys to check (in a loop) that would then fire an event when ctrl-somekey is pressed in the right sequence.

I should add though, that this technique does not allow you to prevent menuitems/system shortcuts from being fired and making a mess later when Apple/Microsoft/etc decides that a new keystroke should bring up some new interface they just think everyone really needs.

And remember to stop/start the timer when your app activates/deactivates… otherwise the user may find that your app did a bunch of stuff while they were busy facebooking.

To do it the “right” way in Windows, you might look at SetWindowsHookEx and Accelerators . Not a simple task, but it can be done…

Indeed, since the universe produces idiots in large orders of magnitude, one can imagine one punching 1 then pressing Ctrl. In a TextField or anywhere text is used, the mess will be grandiose. Thank you for adding the check.

As for “right” and “wrong”, if one has to spend one week on doing it painfully through declares the “right” way when a simple pure Xojo method achieves the goal, is it not a bit extreme ? Unless a good soul provides the declare ready to roll, I’ll go Xojo code anytime.

Ok, since I suggested it…

You could either use a module or a class (slightly more complicated)

in a module…

add a property

Hook as integer

add a structure

KBDLLHOOKSTRUCT
{
  keyCode as uint32
  scanCode as uint32
  flags as uint32
  time as uint32
  extraInfo as ptr
}

and 4 methods

[code]Sub Start()
#if TargetWin32

const WH_KEYBOARD_LL=13
soft Declare function SetWindowsHookExA lib "User32" (idHook as integer, lpfn as ptr, hMod as integer,dwThreadId as integer) as integer
if hook<>0 then return
hook= SetWindowsHookExA(WH_KEYBOARD_LL,AddressOf KeyCallback,0,0)

#endif
End Sub

Function HandleKeyPress(keyCode as integer,down as Boolean) As Boolean
System.DebugLog(str(keyCode))
Return false
End Function

Function KeyCallBack(code as int32, wParam as uint32, byref lParam as KBDLLHOOKSTRUCT) As int32
#if TargetWin32
const WM_KEYDOWN =&h100
soft Declare function CallNextHookEx lib “User32” (hhk as integer,nCode as int32,wParam as uint32,byref lParam as KBDLLHOOKSTRUCT) as int32
if code<0 or (not HandleKeyPress(lParam.keyCode,wParam=WM_KEYDOWN)) then Return CallNextHookEx(0,code,wParam,lParam)
Return -1
#endif
End Function

Sub Stop()
#if TargetWin32

soft Declare function UnhookWindowsHookEx lib "User32" (idHook as integer) as integer
call UnhookWindowsHookEx(hook)
hook=0

#endif
End Sub
[/code]

To start monitoring key events call

WinKeyStrokeMonitor.Start

To stop call

WinKeyStrokeMonitor.Stop

now, in the handleKeyPress method, you can return true to prevent the event from moving up the call chain by returning true.
eg.

if keyboard.AsyncControlKey and keyCode=&h12 then //do stuff return true //prevents "a" from being typed.. should also supersede any menus end if

Oh, and for this example name the module “WinKeyStrokeMonitor”

Yoou can programmatically edit MenuBars. So create a method that’ll add the menuitems you want to be on all menubars, then in App.Open call it with each menubar.

[code]Sub Open() //App

addGlobalMenuItems(MainMenuBar)
addGlobalMenuItems(MenuBar1)

End Sub

Private Sub addGlobalMenuItems(mb As MenuBar)

dim m As MenuItem

m = new MenuItem(“Test1”)
m.KeyboardShortcut = “Shift-Cmd-P”
m.Enabled = true
AddHandler m.Action, AddressOf App.handleTest1
mb.Child(“FileMenu”).Append m

m = new MenuItem(“Test2”)
m.KeyboardShortcut = “Shift-Cmd-L”
m.Enabled = true
AddHandler m.Action, AddressOf App.handleTest2
mb.Child(“FileMenu”).Append m

End Sub

Private Function handleTest1(sender As MenuItem) As Boolean
MsgBox “triggered App.handleTest1”
End Function

Private Function handleTest2(sender As MenuItem) As Boolean
MsgBox “triggered App.handleTest2”
End Function[/code]

This works on Mac, for Windows change “Cmd” to “Cntl”. see http://documentation.xojo.com/index.php/MenuItem.KeyboardShortCut

I may be wrong, but…

In a Menu handler, Return True means “I handled the Menu Event” while Return False let the event continue and be handled by some other code…

Example:

If you test a condition in a MenuHandler located in App andthe test failed, you can Return False and in Windiw1 MenuHandler, you can also test on the condition and if met, Return True. [the menu handler is for the same MenuItem).

Wouldn’t the most natural thing be to simply implement the shortcut in all your menus? Use a common method in a module to implement the code for them all.