Key presses
Key presses
I need a way to get which key is pressed even when a window is not in focus (not using a screen though). I need this because I am designing an application for windows that allows you to press keys to execute certain commands, which you will be able to do when other windows are in focus. (for example, pressing F10 to hide all windows, and then again to show them)
Thanks,
Matt
Thanks,
Matt
You can use the RegisterHotKey_ API
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.

Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.

- Kaeru Gaman
- Addict
- Posts: 4826
- Joined: Sun Mar 19, 2006 1:57 pm
- Location: Germany
- Kaeru Gaman
- Addict
- Posts: 4826
- Joined: Sun Mar 19, 2006 1:57 pm
- Location: Germany
it returns the complete keyboardstate to a 256byte buffer you pass byRef.
never did it before, but it should work this way:...or without the @.. not sure... the pointer to the array anyways...
the buffer then holds the state of every key,
the index should be the virtual keycode,
eventually it's the same as the #PB_Key_ Constants...
never did it before, but it should work this way:
Code: Select all
Dim KeyBuf.b(255)
GetKeyboardState_(@KeyBuf())
the buffer then holds the state of every key,
the index should be the virtual keycode,
eventually it's the same as the #PB_Key_ Constants...
oh... and have a nice day.
Matt,
The program below uses RegisterHotKey_() and is similar to the code you need.
It is not exactly what you want, as it hides/unhides only windows visible at the moment of the program starting, whereas you really need to update the list of windows every time the F11 key is pressed in case some new windows have been created or destroyed in the meantime. This is actually harder to do than it seems, as there is a danger of losing track of windows currently hidden by the program but which were originally visible.
The program below uses RegisterHotKey_() and is similar to the code you need.
It is not exactly what you want, as it hides/unhides only windows visible at the moment of the program starting, whereas you really need to update the list of windows every time the F11 key is pressed in case some new windows have been created or destroyed in the meantime. This is actually harder to do than it seems, as there is a danger of losing track of windows currently hidden by the program but which were originally visible.
Code: Select all
; Hide Windows AKJ 23-Apr-07
; Enable F10 key to hide/unhide visible windows
#program$ = "Hide Windows"
#version$ = "1.0"
EnableExplicit
Declare AlreadyRunning()
Declare BuildWindowList(winmain)
Declare.s WindowTitle(h)
Declare FlipWindows()
Enumeration
#winMain
#lstWindows
#butFlip
#butExit
EndEnumeration
Structure windowdata
handle.l
title$
EndStructure
Global NewList window.windowdata() ; Window handles and titles
Global gHidden = #False ; True iff visible windows are hidden
AlreadyRunning()
; GUI interface
Define.l gap, butw, buth, lstw, lsth, winw, winh, flags
gap = 20
butw = 120: buth = 30
lstw = butw*2+gap: lsth=200
winw = butw*2+gap*3: winh = lsth+buth+gap*3
flags = #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered
OpenWindow(#winMain, 0, 0, winw, winh, #Program$+" v"+#Version$, flags)
CreateGadgetList(WindowID(#winMain))
flags = #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect
ListIconGadget(#lstWindows, gap, gap, lstw, lsth, "Handle", 56, flags)
AddGadgetColumn(#lstWindows, 1, "Visible Window Title", lstw-56-4) ; The -4 is a kludge
ButtonGadget(#butFlip, gap, lsth+gap*2, butw, buth, "F l i p (F10 key)")
ButtonGadget(#butExit, butw+gap*2, lsth+gap*2, butw, buth, "E x i t")
; Initialise
StickyWindow(#winMain, #True)
BuildWindowList(#winMain)
ForEach window()
With window()
AddGadgetItem(#lstWindows, -1, "$"+Hex(\handle)+Chr(10)+\title$)
EndWith
Next window()
RegisterHotKey_(#Null, 0, 0, #VK_F10) ; Register F10 as a hot key
; Event loop 15-Feb-06
Define.l done=#False, ev, reply
Repeat
ev = WaitWindowEvent()
If ev=#PB_Event_Menu: ev=#PB_Event_Gadget: EndIf ; To map shortcut keys to gadgets
Select ev
Case #WM_HOTKEY ; = $312 = 786.
Debug "Hotkey pressed"
FlipWindows()
StickyWindow(#winMain, #True)
Case #PB_Event_Gadget
Select EventGadget()
Case #butFlip
FlipWindows()
StickyWindow(#winMain, #True)
Case #butExit
done=#True
EndSelect
Case #PB_Event_CloseWindow
done=#True
EndSelect
Until done
; Windup
If gHidden: FlipWindows(): EndIf ; Ensure windows are visible
UnregisterHotKey_(#Null, 0)
CloseWindow(#winMain)
End
Procedure AlreadyRunning() ; AKJ 30-Jan-07
; Ensure the current program is not already running
; Terminate this process if it is
; Uses #Program$
Protected app, msg$
app=CreateSemaphore_(0,0,1,"AKJ "+#Program$)
If app<>0 And GetLastError_()=#ERROR_ALREADY_EXISTS
CloseHandle_(app) ; This line can be omitted
msg$="The "+#Program$+" program is already running."+#CRLF$+#CRLF$
msg$+"This process will terminate."
MessageRequester(#Program$+" Error", msg$, #MB_ICONERROR)
End
EndIf
EndProcedure
Procedure BuildWindowList(winmain) ; AKJ 22-Apr-07
; Build list of handles of visible top-level [owned] windows
; Exclude the window given in the parameter
Protected hWin, h, cn$, title$
ClearList(window())
hWin = WindowID(winmain)
; GetDesktopWindow_() handle differs from the window entitled "Program Manager"
h = GetWindow_(GetDesktopWindow_(), #GW_CHILD) ; Handle
While h
If h<>hWin ; If not window for this program
If IsWindowVisible_(h)=#True
If IsIconic_(h)=0 ; If not minimised
cn$ = Space(33) : GetClassName_(h, cn$, 32) ; Window class name
If Left(cn$,8)<>"CursorXP" And FindString(LCase(cn$),"tooltips_class",1)=0 ; Ignore mouse cursor and tooltips
If cn$<>"Shell_TrayWnd" ; Ignore system tray and taskbar
title$ = WindowTitle(h)
If title$<>"Program Manager" ; Ignore Desktop
; Remember the window
AddElement(window())
window()\handle = h
window()\title$ = title$
EndIf ; Desktop
EndIf ; System tray
EndIf ; Mouse cursor, tooltips
EndIf ; Minimised
EndIf ; Visible
EndIf ; winMain
h = GetWindow_(h, #GW_HWNDNEXT) ; Handle
Wend
EndProcedure
Procedure.s WindowTitle(h) ; AKJ 07-Mar-06
; Return the title (caption) for the window with handle h
Protected lth, title$
If h=0: ProcedureReturn "": EndIf
lth=GetWindowTextLength_(h)+1
title$=Space(lth)
GetWindowText_(h, title$, lth)
ProcedureReturn title$
EndProcedure
Procedure FlipWindows() ; AKJ 22-Apr-07
; Toggle the hidden state for all originally visible windows
gHidden = ~gHidden ; Toggle state
ForEach window()
If gHidden ; If to be hidden
ShowWindow_(window()\handle, #SW_HIDE)
Else
ShowWindow_(window()\handle, #SW_SHOW)
EndIf
Next window()
EndProcedure
Last edited by akj on Mon Apr 23, 2007 1:18 am, edited 1 time in total.
Anthony Jordan
Thanks guys, really what I am looking for is something like this:
If (currentKeyDown() == theF10Key)
<do this>
endif
so something will return whatever key is down... if this makes anysense, because i have the user select their own key to use and using ini files read what key it was and then compare it.
If (currentKeyDown() == theF10Key)
<do this>
endif
so something will return whatever key is down... if this makes anysense, because i have the user select their own key to use and using ini files read what key it was and then compare it.
- Kaeru Gaman
- Addict
- Posts: 4826
- Joined: Sun Mar 19, 2006 1:57 pm
- Location: Germany
sure you could test
you could also setup a table first and let the user chose the key, as you can replace the constant by a variable.
for that, getting the whole table maybe oversized....
PS:
note that if you just test it for #True, it will return #True repetively as long the key is pressed.
you should stop testing while execution or work with a flag,
or find out wich bit in the returnvalue is for "first press"...
Code: Select all
If GetAsyncKeyState_(#VK_F10)
for that, getting the whole table maybe oversized....
PS:
note that if you just test it for #True, it will return #True repetively as long the key is pressed.
you should stop testing while execution or work with a flag,
or find out wich bit in the returnvalue is for "first press"...
oh... and have a nice day.
- Kaeru Gaman
- Addict
- Posts: 4826
- Joined: Sun Mar 19, 2006 1:57 pm
- Location: Germany
I think Matt is able to implement a Delay the correct way, isn't he?Continually polling all key presses as you are suggesting will add a lot of CPU overhead to your system.
give that a test and monitor the CPU usage:
Code: Select all
Repeat
Delay(200)
Until GetAsyncKeyState_(#VK_F10)
CPU will also be used for that, it's only more difficult to monitor...

oh... and have a nice day.
- Kaeru Gaman
- Addict
- Posts: 4826
- Joined: Sun Mar 19, 2006 1:57 pm
- Location: Germany
well, this is when it is #False again, so for that you need a flag to test #True before.
btw: firstpress is -32767, hold is -32768
if you really just want to wait for a key, perhaps an unusual wating loop is quite a good suggestion:
I realized that the debug-window seems not to be updated immediately...
strange...
PS:
of course, that is nothing one would do in a normal eventloop,
but when you're really only wating for one special key, it is ok.
btw: firstpress is -32767, hold is -32768
if you really just want to wait for a key, perhaps an unusual wating loop is quite a good suggestion:
Code: Select all
Repeat
Repeat
Delay(200)
Until GetAsyncKeyState_(#VK_F10)
Debug "pressed"
While GetAsyncKeyState_(#VK_F10)
Delay(100)
Wend
Debug "released"
Until GetAsyncKeyState_(#VK_F11)
strange...
PS:
of course, that is nothing one would do in a normal eventloop,
but when you're really only wating for one special key, it is ok.
oh... and have a nice day.