Key presses

Just starting out? Need help? Post your questions and find answers here.
Matt
Enthusiast
Enthusiast
Posts: 447
Joined: Sat May 21, 2005 1:08 am
Location: USA

Key presses

Post by Matt »

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
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Post by ts-soft »

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.
Image
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

also GetAsyncKeystate_ or GetKeyboardState_ may help....
oh... and have a nice day.
Matt
Enthusiast
Enthusiast
Posts: 447
Joined: Sat May 21, 2005 1:08 am
Location: USA

Post by Matt »

How do I use the GetKeyboardState function
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

it returns the complete keyboardstate to a 256byte buffer you pass byRef.

never did it before, but it should work this way:

Code: Select all

Dim KeyBuf.b(255)
GetKeyboardState_(@KeyBuf())
...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...
oh... and have a nice day.
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

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.

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
Matt
Enthusiast
Enthusiast
Posts: 447
Joined: Sat May 21, 2005 1:08 am
Location: USA

Post by Matt »

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.
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

sure you could test

Code: Select all

If GetAsyncKeyState_(#VK_F10)
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"...
oh... and have a nice day.
Matt
Enthusiast
Enthusiast
Posts: 447
Joined: Sat May 21, 2005 1:08 am
Location: USA

Post by Matt »

Yeah, thats why I wasn't sure of using that, but I guess I'll go with that.
Is there like a reverse of that function that would return #VK_F10
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

Matt,

Continually polling all key presses as you are suggesting will add a lot of CPU overhead to your system. If you think about it carefully you should discover that hot keys really will do what you want and they can be selected based on the contents of your .INI file.
Anthony Jordan
Matt
Enthusiast
Enthusiast
Posts: 447
Joined: Sat May 21, 2005 1:08 am
Location: USA

Post by Matt »

alright, I'll look into those
thanks
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

Continually polling all key presses as you are suggesting will add a lot of CPU overhead to your system.
I think Matt is able to implement a Delay the correct way, isn't he?

give that a test and monitor the CPU usage:

Code: Select all

Repeat
  Delay(200)
Until GetAsyncKeyState_(#VK_F10)
sure, the hotkey thing will also work, the test will be performed by the OS.
CPU will also be used for that, it's only more difficult to monitor... ;)
oh... and have a nice day.
Matt
Enthusiast
Enthusiast
Posts: 447
Joined: Sat May 21, 2005 1:08 am
Location: USA

Post by Matt »

I'll be using the getasynckeystate i guess than

thanks guys
Matt
Enthusiast
Enthusiast
Posts: 447
Joined: Sat May 21, 2005 1:08 am
Location: USA

Post by Matt »

How do I check if the key was released, instead of being held down?
User avatar
Kaeru Gaman
Addict
Addict
Posts: 4826
Joined: Sun Mar 19, 2006 1:57 pm
Location: Germany

Post by Kaeru Gaman »

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:

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)
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.
oh... and have a nice day.
Post Reply