Page 1 of 1

Global shortcut

Posted: Wed Feb 08, 2012 7:33 am
by mk-soft
I use a globale shortcut for my program. (ALT-C)
Have any where a sample?

Thanks
Michael

Re: Global shortcut

Posted: Wed Feb 08, 2012 12:39 pm
by Guimauve
Hi,

To add a Shortcut inside a program you will have to do this :

Code: Select all

AddKeyboardShortcut(#Your_window, #PB_Shortcut_ALT | #PB_ShortCut_C, #Related_Menu_Event_ID)
Best regards.
Guimauve

Re: Global shortcut

Posted: Wed Feb 08, 2012 1:28 pm
by mk-soft
It´s only for active application...

Re: Global shortcut

Posted: Wed Feb 08, 2012 8:03 pm
by Guimauve
What do you mean ?

You would like to use a Global shortcut to call another program ?

Best regards.
Guimauve

Re: Global shortcut

Posted: Wed Feb 08, 2012 8:24 pm
by ts-soft
A hotkey that works on the system like

Code: Select all

RegisterHotKey_(WindowID(Window), HotkeyID, fsModifiers, Keys)
in windows.
http://msdn.microsoft.com/en-us/library ... 85%29.aspx

Re: Global shortcut

Posted: Wed Feb 08, 2012 10:34 pm
by remi_meier
You can find an example in C for a global hotkey here:
http://lists.freedesktop.org/archives/x ... 51567.html

Re: Global shortcut

Posted: Thu Feb 09, 2012 5:25 pm
by Shardik
Thank you Remi for your link. My first own Google searches only found global hotkey examples
which are bound to the desktop manager. So I thought the only way to realize a solution would
have been to write separate routines for the desktop managers KDE 3 + 4, Gnome 2 + 3 + Unity,
Xfce, LXDE...

But since all distributions are currently still using XWindow (until some of them will change to
Wayland) using XWindow API functions should be the most practical approach. Therefore I tried
to convert the posted C code to PB. Currently I have tested this code to detect the newly
established hotkey <Ctrl> + <Shift> + <K> successfully in Ubuntu 11.10, Kubuntu 11.10 and Linux
Mint 12. For non-Ubuntu based distributions (or pre 11.04 Ubuntu distributions) the path to the
Xlibs has to be changed!

Code: Select all

; Converted from cheshirekow's C-Code:
; http://lists.freedesktop.org/archives/xorg/2010-October/051373.html

EnableExplicit

#ControlMask = 1 << 2
#GrabModeAsync = 1
#KeyPress = 2
#KeyPressMask = 1
#ShiftMask = 1
#XK_K = $004B

ImportC "-lX11"
  XCloseDisplay(*Display)
  XDefaultRootWindow(*Display)
  XGrabKey(*Display, KeyCode.I, Modifiers.I, GrabWindow.I, OwnerEvents.i, PointerMode.I, KeyboardMode.I)
  XKeysymToKeycode(*Display, KeySym.I)
  XNextEvent(*Display, *XEvent)
  XOpenDisplay(*Display)
  XSelectInput(*Display, Window.I, EventMask.I)
  XUngrabKey(*Display, KeyCode.I, Modifiers.I, GrabWindow.I)
EndImport

ImportC "-lxcb" : EndImport
ImportC "-lXau" : EndImport
ImportC "-lXdmcp" : EndImport

Structure XEvent
  EventType.I
  SendEvent.I
  *Display
  EventWindow.I
  RootWindow.I
  ChildWindow.I
  Time.I
  x.I
  y.I
  x_root.I
  y_root.I
  Mask.I
  KeyCode.I
  SameScreen.I
EndStructure

Define *Display
Define Event.XEvent
Define KeyCode.I
Define RootWindow.I

*Display = XOpenDisplay(0)

If *Display
  RootWindow = XDefaultRootWindow(*Display)

  If RootWindow
    KeyCode = XKeysymToKeycode(*Display, #XK_K)
    XGrabKey(*Display, KeyCode, #ControlMask | #ShiftMask, RootWindow, #False, #GrabModeAsync, #GrabModeAsync)
    XSelectInput(*Display, RootWindow, #KeyPressMask)

    Repeat
      XNextEvent(*Display, @Event)

      If Event\EventType = #KeyPress
        MessageRequester("Info", "Global Hotkey <Ctrl> + <Shift> + <K> detected and removed!")
        XUngrabKey(*Display, KeyCode, #ControlMask | #ShiftMask, RootWindow)
        Break
      EndIf
    ForEver

    XCloseDisplay(*Display)
  EndIf
EndIf
Update: I have changed the ImportC statements so that the example code should run without modification on different Linux distributions. And keep in mind that during the test the NumLock key has to be switched off because otherwise the HotKey combination won't be recognized because the NumLock key will be recognized as "pressed"!
Furthermore I had to modify the link to the C source code of the original author.

Re: Global shortcut

Posted: Fri Feb 10, 2012 8:29 am
by mk-soft
Thanks to all

GT :wink:

Re: Global shortcut

Posted: Sat Oct 19, 2013 5:22 am
by nikoniko
Hello,

I tried this code on Ubuntu 12.04 LTS x64. It is not stable working. Sometimes works, sometimes show message debugger exception.

And How to install grab for all keys? Is it possible with this code?

Re: Global shortcut

Posted: Sat Oct 19, 2013 5:53 am
by nikoniko
Oopss. Sorry. It's working only MessageRequester is still invisible or doesn't call at all.

Re: Global shortcut

Posted: Fri Aug 11, 2017 3:38 am
by vwidmer
Anyone have an updated version of this? Doesnt seem to work for me.

Re: Global shortcut

Posted: Mon Aug 14, 2017 1:38 pm
by Shardik
vwidmer wrote:Anyone have an updated version of this? Doesnt seem to work for me.
You should always report your Linux distribution, desktop environment and whether you are using a 32 bit (x86) or 64 bit (x64) distribution.

I have modified my example from above because of some variable declaration errors for 64 bit systems and posted it below. I have tested this example with PB 5.60 on these different distributions (a plus denotes it's working and a minus that the polling loop is hanging at XNextEvent() and doesn't detect the hot key):
+ Bodhi Linux 4.1.0 x86 with Moksha
+ Debian 8.9 x86 with Xfce
+ Elementary OS 0.3.2 x86 'Freya' with Pantheon
+ Fedora 25 x86 with Gnome
+ Kubuntu 16.04 x86 with KDE
+ Linux Mint 17.3 x64 'Rosa' with Cinnamon
- Linux Mint 18.0 x86 'Sarah' with Cinnamon
- Linux Mint 18.1 x64 'Serena' with Cinnamon
+ Lubuntu 14.04 x86 with LXDE
+ Lubuntu 16.04 x86 with LXDE
- OpenSuSE 13.2 x86 with KDE
- Ubuntu 12.04 x86 with Unity
- Ubuntu 16.04 x86 with Unity
+ Xubuntu 16.04 x86 with Xfce

As I already wrote more than 5 years ago this solution is only for distributions using XWindow as window server. In Fedora 25 you have to explicitly click onto the gear wheel beneath "Sign In" and choose "Gnome on Xorg" in order to not use the default Wayland. And in Fedora 25 you also have to install the X11 developer tools:
> su root
> dnf install "X Software Development"

In OpenSuSE 13.2 you have to additionally install libXdmcp-devel using Yast2.

I currently don't know why the hot key example doesn't work in some distributions. Very interesting is the difference between Linux Mint 17.3 x64 (hot key is working) and Linux Mint 18.1 x64 (hot key doesn't work).

Code: Select all

; Converted from cheshirekow's C-Code:
; http://lists.freedesktop.org/archives/xorg/2010-October/051373.html

EnableExplicit

#ControlMask = 1 << 2
#GrabModeAsync = 1
#KeyPress = 2
#KeyPressMask = 1
#ShiftMask = 1
#XK_K = $004B

ImportC "-lX11"
  XCloseDisplay(*Display)
  XDefaultRootWindow(*Display)
  XGrabKey(*Display, KeyCode.L, Modifiers.L, GrabWindow.I, OwnerEvents.L,
    PointerMode.L, KeyboardMode.L)
  XKeysymToKeycode(*Display, KeySym.L) ; KeySyms are 29-bit integer values
                                       ; identifying characters or functions
                                       ; associated with each key
  XNextEvent(*Display, *XEvent)
  XOpenDisplay(*Display)
  XSelectInput(*Display, Window.I, EventMask.I)
  XUngrabKey(*Display, KeyCode.L, Modifiers.L, GrabWindow.I)
EndImport

ImportC "-lxcb" : EndImport
ImportC "-lXau" : EndImport
ImportC "-lXdmcp" : EndImport

Structure XEvent
  StructureUnion
    type.L
    *XAnyEvent
    *XKeyEvent
    *XButtonEvent
    *XMotionEvent
    *XCrossingEvent
    *XFocusChangeEvent
    *XExposeEvent
    *XGraphicsExposeEvent
    *XNoExposeEvent
    *XVisibilityEvent
    *XCreateWindowEvent
    *XDestroyWindowEvent
    *XUnmapEvent
    *XMapEvent
    *XMapRequestEvent
    *XReparentEvent
    *XConfigureEvent
    *XGravityEvent
    *XResizeRequestEvent
    *XConfigureRequestEvent
    *XCirculateEvent
    *XCirculateRequestEvent
    *XPropertyEvent
    *XSelectionClearEvent
    *XSelectionRequestEvent
    *XSelectionEvent
    *XColormapEvent
    *XClientMessageEvent
    *XMappingEvent
    *XErrorEvent
    *XKeymapEvent
    *XGenericEvent
    *XGenericEventCookie
    pad.L[24]
  EndStructureUnion
EndStructure

Define *Display
Define Event.XEvent
Define KeyCode.L
Define RootWindow.I

*Display = XOpenDisplay(0)

If *Display
  RootWindow = XDefaultRootWindow(*Display)

  If RootWindow
    KeyCode = XKeysymToKeycode(*Display, #XK_K)
    XGrabKey(*Display, KeyCode, #ControlMask | #ShiftMask, RootWindow, #False,
      #GrabModeAsync, #GrabModeAsync)
    XSelectInput(*Display, RootWindow, #KeyPressMask)
    MessageRequester("Info", "Global Hotkey <Ctrl> + <Shift> + <K> is enabled!")

    Repeat
      XNextEvent(*Display, @Event)
 
      Select Event\type
        Case #KeyPress
          MessageRequester("Info", "Global Hotkey <Ctrl> + <Shift> + <K> detected and removed!")
          XUngrabKey(*Display, KeyCode, #ControlMask | #ShiftMask, RootWindow)
          Break
      EndSelect
    ForEver

    XCloseDisplay(*Display)
  EndIf
EndIf

Re: Global shortcut

Posted: Mon Aug 14, 2017 8:05 pm
by vwidmer
Thanks for the updated code it seems to work. I am using Manjaro Linux x64 "Linux 4.9.40-1-MANJARO #1 SMP PREEMPT Fri Jul 28 09:24:52 UTC 2017 x86_64 GNU/Linux"

When I just added the debug on the key as such:

Code: Select all

; Converted from cheshirekow's C-Code:
; http://lists.freedesktop.org/archives/xorg/2010-October/051373.html
;http://www.purebasic.fr/english/viewtopic.php?f=15&t=49107&hilit=global+shortcut

EnableExplicit

#ControlMask = 1 << 2
#GrabModeAsync = 1
#KeyPress = 2
#KeyPressMask = 1
#ShiftMask = 1
#XK_K = $004B

ImportC "-lX11"
  XCloseDisplay(*Display)
  XDefaultRootWindow(*Display)
  XGrabKey(*Display, KeyCode.I, Modifiers.I, GrabWindow.I, OwnerEvents.i, PointerMode.I, KeyboardMode.I)
  XKeysymToKeycode(*Display, KeySym.I)
  XNextEvent(*Display, *XEvent)
  XOpenDisplay(*Display)
  XSelectInput(*Display, Window.I, EventMask.I)
  XUngrabKey(*Display, KeyCode.I, Modifiers.I, GrabWindow.I)
EndImport

ImportC "-lxcb" : EndImport
ImportC "-lXau" : EndImport
ImportC "-lXdmcp" : EndImport

Structure XEvent
  EventType.I
  SendEvent.I
  *Display
  EventWindow.I
  RootWindow.I
  ChildWindow.I
  Time.I
  x.I
  y.I
  x_root.I
  y_root.I
  Mask.I
  KeyCode.I
  SameScreen.I
EndStructure

Define *Display
Define Event.XEvent
Define KeyCode.I
Define RootWindow.I

*Display = XOpenDisplay(0)

If *Display
  RootWindow = XDefaultRootWindow(*Display)
  
  If RootWindow
    KeyCode = XKeysymToKeycode(*Display, #XK_K)
    XGrabKey(*Display, KeyCode, #ControlMask | #ShiftMask, RootWindow, #False, #GrabModeAsync, #GrabModeAsync)
    XSelectInput(*Display, RootWindow, #KeyPressMask)
    
    Repeat
      XNextEvent(*Display, @Event)
      Debug Event\EventType
      If Event\EventType = #KeyPress
        MessageRequester("Info", "Global Hotkey <Ctrl> + <Shift> + <K> detected and removed!")
        XUngrabKey(*Display, KeyCode, #ControlMask | #ShiftMask, RootWindow)
        Break
      EndIf
    ForEver
    
    XCloseDisplay(*Display)
  EndIf
EndIf
if I press the key combo I get a number like:

Code: Select all

140454020513794
140454020513795
I dont get anything if I press anything else I think its trig on the up and down of the key though it seems to just keep going between the two if I hold it down. It also changes everytime it runs so I am guessing its a memory address. It never gets into the #KeyPress event.

The new one appears to work fine though.

Not sure if that helps diagnose anything for the other versions of linux not working.

Thanks

Re: Global shortcut

Posted: Sun Mar 02, 2025 9:31 pm
by AZJIO
It is impossible to insert a window processor into this cycle. The XnextEvent () function stops the code and continues it only if the event has arrived. Moreover, if I call the function with the cycle after "Case #KeyPress", then my code is violated, the NewList list becomes broken.

Code: Select all

Repeat
	XNextEvent(*Display, @Event)
	Debug Event\EventType
	If Event\EventType = #KeyPress
		MessageRequester("Info", "Global Hotkey <Ctrl> + <Shift> + <K> detected and removed!")
		XUngrabKey(*Display, KeyCode, #ControlMask | #ShiftMask, RootWindow)
		Break
	EndIf
ForEver