Page 1 of 1

doing a 'launchy'... how to grab a hotkey

Posted: Sun Oct 31, 2010 9:20 pm
by blueznl
Tools like Enso and Launchy 'steal' a hotkey, and I would like to copy that behaviour, ie.

If the user presses [Alt]+[Space] I want my program to pop up, no matter what else is going on, just like Launchy does. How can I do that?

What I plan to write (and if you already know about a tool that does this then please tell me so I don't have to write it myself :-)) is a small application launcher, in the style of launchy, however with a twist.

If pressing [Alt]+[Space] it should bring up a menu, ie. a screen with multiple Single key shortcuts. Thus, to quickly launch a browser, one would do [Alt]+[Space] followed by, for example, [F]. To enter more complex 'Launchy' style commands one would launch the tool using [Alt]+[2xSpace].

It's easier to talk about it than to write it I guess :-)

One of the things that I did NOT like about Launchy etc. is how much memory those things consume. Why should a keyboard launcher consume 10 MB (!) for a simple execute program call or pop up window call? Not a good thing on netbooks (like the one I'm typing this on right now :-)) so PureBasic to the rescue?

Suggestions welcome.

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Sun Oct 31, 2010 9:57 pm
by LuCiFeR[SD]
I've got a bit of code from RASHAD IIRC :), should find it on here with a search "Global Keyboard Hook" I think

Code: Select all

Procedure CheckForHotKey(Delete.i = #True)
  Message.MSG
  If Delete
    If PeekMessage_(@Message, -1, #WM_HOTKEY,#WM_HOTKEY, #PM_REMOVE)
      ProcedureReturn Message\wParam
    EndIf  
  Else
    If PeekMessage_(@Message, -1, #WM_HOTKEY,#WM_HOTKEY, #PM_NOREMOVE)
      ProcedureReturn Message\wParam
    EndIf  
  EndIf

  ProcedureReturn #False
EndProcedure

#PB_Event_ShortCut = 1337

Procedure WindowEventHook(Wait.i = #False)
  Message.MSG
  If CheckForHotKey(#False)
    ProcedureReturn #PB_Event_ShortCut
  EndIf
  
  If Wait
    ProcedureReturn WaitWindowEvent()  
  Else 
    ProcedureReturn WindowEvent()
  EndIf
EndProcedure

Macro WindowEvent()
  WindowEventHook()
EndMacro

Macro WaitWindowEvent()
  WindowEventHook(#True)
EndMacro

Procedure RegisterSystemHotkey(ID.i, Key1.i, Key2.i)
  RegisterHotKey_(0,ID, Key1, Key2)  
EndProcedure

Procedure UnregisterSystemHotkey(ID.i)
  UnregisterHotKey_(0,ID)
EndProcedure

RegisterSystemHotkey(1,#MOD_CONTROL, #VK_SPACE) ;CTRL + Space
RegisterSystemHotkey(2,#MOD_CONTROL, #VK_Q) ;CTRL + Q


OpenWindow(0,0,0,300,300,"TestWindow")

Repeat
  Delay(1)
  Event = WindowEvent()
  If Event = #PB_Event_ShortCut
    Hotkey = CheckForHotKey()
    If Hotkey = 1
      Debug "CTRL + Space"
    ElseIf Hotkey = 2
      Debug "CTRL + Q pressed"
    EndIf
  ElseIf Event = #PB_Event_CloseWindow
    End
  EndIf
ForEver
This should get you started :P

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Sun Oct 31, 2010 10:07 pm
by idle
Just use a use a low level keyboard hook with a timer to queue the key sequences
If that doesn't work properly all the time or some other app responds to the keys then you could try eating the keys triggered on the alt key by setting a timer and store the key messages and if after x milliseconds the sequence doesn't match a target pattern flush the stored keys back into the system.

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Sun Oct 31, 2010 10:08 pm
by blueznl
Ah! GlobalKeyboardHook, I knew it was there somewhere! Thanks, let's see how large my own 'launchy' will be, I bet it's going to be quite a bit short of 10 Mb :-)

(Though, to be honest, even WallX takes 5 Mb when running, even though the code is so silly small it's amazing how Windows manages to blow it up :-))

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Sun Oct 31, 2010 11:23 pm
by Vera
The smallest (87.5kb)
and best launcher I've ever come across, is written in pure PureBasic ~ PopSel by Horst.

Now - can this be a challenge :mrgreen:

And I'm already anxious what it'll be going to be - in case we'll get a look one day :D

greetings ~ Vera

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Mon Nov 01, 2010 12:28 am
by Mistrel

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Mon Nov 01, 2010 1:09 am
by blueznl
Lucifer's code seems to be a bit complex, wouldn't the next snippet pretty much do the same, or am I overlooking something?

Code: Select all

Enumeration
  #w_main_nr
  #hk_altspace
  #hk_ctrlspace
EndEnumeration
;
w_main_h = OpenWindow(#w_main_nr,300,300,300,300,"Thype",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
hk_altspace = RegisterHotKey_(w_main_h,#hk_altspace,#MOD_ALT,#VK_SPACE)
hk_ctrlspace = RegisterHotKey_(w_main_h,#hk_ctrlspace,#MOD_CONTROL,#VK_SPACE)
;
Repeat
  event = WaitWindowEvent()
  Select event
  Case #PB_Event_CloseWindow
  Case #PB_Event_MoveWindow
  Case #WM_HOTKEY
    Select EventwParam()
    Case #hk_altspace
      Debug "alt"
    Case #hk_ctrlspace
      Debug "ctrl"
    EndSelect
  EndSelect
Until event = #PB_Event_CloseWindow
;
UnregisterHotKey_(w_main_h,hk_altspace)
UnregisterHotKey_(w_main_h,hk_ctrlspace)
Slightly improved version (seems to work fine though :-))

Code: Select all

Enumeration
  #w_invisible_nr
  #w_main_nr
  #hk_altspace
EndEnumeration
;
w_invisible_h = OpenWindow(#w_invisible_nr,300,300,300,300,"Thype",#PB_Window_Invisible)
hk_altspace = RegisterHotKey_(w_invisible_h,#hk_altspace,#MOD_ALT,#VK_SPACE)
;
Repeat
  event = WaitWindowEvent()
  window = EventWindow()
  ;
  Select window
  Case #w_invisible_nr
    Select event
    Case #WM_HOTKEY
      Select EventwParam()
      Case #hk_altspace
        If Not IsWindow(#w_main_nr)
          w_main_h = OpenWindow(#w_main_nr,300,300,300,300,"Thype",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
        Else
        EndIf
      EndSelect
    EndSelect
  Case #w_main_nr
    Select event
    Case #PB_Event_CloseWindow
      CloseWindow(#w_main_nr)
    EndSelect
  EndSelect
Until event = 1234
;
hk_altspace = RegisterHotKey_(w_invisible_h,#hk_altspace,#MOD_ALT,#VK_SPACE)
Edit: Mistrel, I checked your email after I worked out my own code. Question: why are you not using the regular WindowEvent() messages in your example?

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Mon Nov 01, 2010 1:57 am
by Mistrel
blueznl wrote:Question: why are you not using the regular WindowEvent() messages in your example?
Because my code isn't using any windows.

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Mon Nov 01, 2010 7:49 pm
by marc_256
hi,

if I try to download the 'PopSel by Horst'
I receive a VIRUS warning by NOD32 anti-virus program.

Is there someone else who have this warning ??

Marc

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Mon Nov 01, 2010 8:37 pm
by Michael Vogel
Not sure if you found already a solution, I did a launcher which uses "only" a key combination with the windows. This can be done easily with something like this which results in WM_HOTKEY events:

Code: Select all

Procedure ActivateHotkeys()
    If OptHotkeyFlag
        If OptHotkey<#HotKeyAlternateSet
            RegisterHotKey_(HandleMyWin,$9999,#MOD_WIN,#VK_A+OptHotkey)
            RegisterHotKey_(HandleMyWin,$9898,#MOD_WIN|#MOD_SHIFT,#VK_A+OptHotkey)
        Else
            RegisterHotKey_(HandleMyWin,$9999,#MOD_CONTROL|#MOD_SHIFT,#VK_A+OptHotkey-#HotKeyAlternateSet)
            RegisterHotKey_(HandleMyWin,$9898,#MOD_ALT|#MOD_SHIFT,#VK_A+OptHotkey-#HotKeyAlternateSet)
        EndIf
    EndIf
EndProcedure

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Mon Nov 01, 2010 10:36 pm
by blueznl
Got a bit further, here's my current code:

Code: Select all

; thype v0.1

EnableExplicit
Declare init()
Declare main()
init()
main()

Procedure init()
  ;
  ; *** setup constants, structures and global variables
  ;
  Enumeration
    ;
    ; windows
    ;
    #w_invisible_nr   ; window used to capture hk_launch events
    #w_visible_nr     ; main window nr when visible
    ;
    ; gadgets
    ;
    #g_command        ; gadget to input launch string
    ;
    ; hotkeys
    ;
    #hk_launch        ; constant identifying hk_launch in use
    ;
    ; actions
    ;
    #f_none           ; do nothing
    #f_exit           ; exit program
    #f_escape         ; escape, abort
    #f_enter          ; confirm selection
    ;
  EndEnumeration
  ;
  ; *** globals
  ;
  ; gui elements
  ;
  Global w_invisible_h.i
  Global w_visible_h.i
  ;
  ; shortcuts
  ;
  Global hk_launch.i
  ;
  ; events
  ;
  Global action.i
  Global event.i
  Global event_window.i
  Global event_menu.i
  ;
  ; other
  ;
  Global mode.i
  Global command.s
  ;
EndProcedure

Procedure draw(mode.i)
  ;
  ; *** draw window
  ;
  Select mode
  Case 0
    ;
    ; mode 0 brings up single key shortcuts
    ;
  Case 1
    ;
    ; mode 1 allows typing multiple letters
    ;
    StringGadget(#g_command,10,10,280,20,"")
    SetActiveGadget(#g_command)
    AddKeyboardShortcut(#w_visible_nr,#PB_Shortcut_Escape,#f_escape)
    AddKeyboardShortcut(#w_visible_nr,#PB_Shortcut_Return,#f_enter)
    ;
  EndSelect
  ;
EndProcedure

Procedure main()
  ;
  ; *** main routine
  ;
  w_invisible_h = OpenWindow(#w_invisible_nr,300,300,300,300,"Thype",#PB_Window_Invisible)
  hk_launch = RegisterHotKey_(w_invisible_h,#hk_launch,#MOD_ALT,#VK_SPACE)
  ;
  ; *** event loop
  ;
  Repeat
    action = #f_none
    ;
    event = WaitWindowEvent()
    event_window = EventWindow()
    event_menu = EventMenu()
    ;
    Select event_window
    Case #w_invisible_nr
      ;
      ; *** process all events arriving at the invisible window
      ;
      Select event
      Case #WM_HOTKEY
        Select EventwParam()
        Case #hk_launch
          If Not IsWindow(#w_visible_nr)
            ;
            ; open the visible window
            ;
            w_visible_h = OpenWindow(#w_visible_nr,300,300,300,300,"Thype",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
            mode = 0
            draw(mode)
            ;
          Else
            ;
            ; visible window is open, toggle mode
            ;
            ; mode 0 brings up a single key menu, ie. [Alt]+[Space] then [W] should launch 'word' etc.
            ; mode 1 allows entering a text, ie. [Alt]+[Space] then [W][O][R][D] should launch 'word'
            ;
            mode = 1 - mode
            draw(mode)
            ;
          EndIf
        EndSelect
      Case #PB_Event_CloseWindow
        ;
        ; close window / exit program message
        ;
        action = #f_exit
      EndSelect
      ;
    Case #w_visible_nr
      ;
      ; *** process all events arriving at the visible window
      ;
      Select event
      Case #PB_Event_Menu
        ;
        ; process menu events and shortcut keys
        ;
        Select event_menu
        Case #f_escape
          ;
          ; hitting the escape key aborts the sequence and closes the window
          ;
          CloseWindow(#w_visible_nr)
        Case #f_enter
          ;
          ; hitting enter confirms the input
          ;
          command = LCase(GetGadgetText(#g_command))
          Select command
          Case "quit"
            action = #f_exit
          EndSelect
          ;
        EndSelect
        ;
      Case #PB_Event_CloseWindow
        ;
        ; close the visible window
        ;
        CloseWindow(#w_visible_nr)
        ;
      Default
        ;
        ; all other events (debugging)
        ;
      EndSelect
      ;
    EndSelect
  Until action = #f_exit
  ;
  ; *** all completed, free up, close, exit
  ;
  hk_launch = UnregisterHotKey_(w_invisible_h,#hk_launch)
  ;
EndProcedure
It's the basic framework for a 'launchy' style of application. On we go... next challenge: search through the start menu. Suggestions? :-)

http://www.purebasic.fr/english/viewtop ... 13&t=44151

Re: Grabbing a hotkey (how to do a 'launchy')

Posted: Tue Nov 02, 2010 8:00 am
by horst
marc_256 wrote: if I try to download the 'PopSel by Horst'
I receive a VIRUS warning by NOD32 anti-virus program.
This is the full :!: source code of the "program" RunDemo.exe that caused the alert (tested with Jotti: about half a dozen scanners reported positive).

Code: Select all

ShellExecute_(0,0,"PopSel.exe","Demo.lst",0,#SW_SHOWNORMAL)
I compiled it again with PB 4.51, and all but one ("VBA32") scanner reported "found nothing".
Download archive updated; new "official" version soon.

Sorry, if off topic

Re: doing a 'launchy'... how to grab a hotkey

Posted: Tue Nov 02, 2010 9:20 pm
by marc_256
To Horst,

Thanks,
all the downloads are ok now.
No virus detection anymore...

Marc

Re: doing a 'launchy'... how to grab a hotkey

Posted: Wed Nov 03, 2010 1:39 am
by idle
An idea to facilitate blueznl mode 1
mode 1 allows entering a text, ie. [Alt]+[Space] then [W][O][R][D] should launch 'word'

Notes

It will save a file "launchy.lbn" where ever you run it from.
Either let is scan all drives or scan a drive
start to type in an exe name list will populate
click on an item in the list to run

Questions

should it be trawling the drives for exe's or the registry?
how can you tell the difference between a windows and console application? read the PE header I suppose
how can you tell if an app is a worker app of some other app?

Code: Select all


;an idea for to facilitate blueznl mode 1  
;mode 1 allows entering a text, ie. [Alt]+[Space] then [W][O][R][D] should launch 'word'

;quick hacky launchy app - code at line 197
Structure edge
   edge.i[256] 
EndStructure

Structure TrieNode;
   Value.i;
   Count.i;
   Vertex.edge
EndStructure;

Structure Trie
  *vt.i
  *root.TrieNode;
EndStructure;

Declare FreeNodes(*node.TrieNode)
Declare NewTrie(*obj.Trie)
Declare FreeTrie(*this.Trie)
Declare AddTrie(*this.Trie,key.s,value.i=1)
Declare lookupTrie(*this.Trie,key.s)
Declare iEnumTrie(*this.Trie,*node.TrieNode,key.s,*fn)
Declare EnumTrie(*this.Trie,key.s,*fn.i)

Interface clsTrie
  Free()
  Add(key.s,item.i=1)
  LookUp(key.s)
  Enum(key.s,*fn.i)
EndInterface   


Procedure FreeNodes(*node.TrieNode)
  ;Free all Trie Nodes
  Protected a.i
   If Not *node
      ProcedureReturn;
   EndIf
   
   For a=0 To 255
      FreeNodes(*node\Vertex\edge[a]);
   Next
   
   If *node
     FreeMemory(*node)
   EndIf 
   
EndProcedure

Procedure NewTrie(*obj.Trie)
  *obj = AllocateMemory(SizeOf(Trie))
  If *obj
   *obj\vt=?vt_Trie
  EndIf
  *obj\root = AllocateMemory(SizeOf(TrieNode))
 
  ProcedureReturn *obj
EndProcedure

Procedure FreeTrie(*this.Trie)
  ;free the Trie
  FreeNodes(*this\root)
  FreeMemory(*this)
 
EndProcedure

Procedure AddTrie(*this.Trie,key.s,value.i=1)
  ;Add item to the Trie, value is optional
  Protected *tnode.TrieNode,*node.TrieNode,len.i,tkey.i,lkey.i,pos.i
  len = Len(key)
   lkey.i
   
   If Not len
     ProcedureReturn;
   EndIf

   *node = *this\root;
   
   While pos < Len+1
    
     tkey = PeekB(@key+pos) & $FF
    
     If Not *node          
      *node = AllocateMemory(SizeOf(TrieNode))
        *tnode\Vertex\edge[lkey] = *node
      EndIf

      *node\count + 1
        
     If pos = len 
       *node\value = value
      EndIf
      
      *tnode = *node
      *node = *node\Vertex\edge[tkey]
      lkey = tkey
      pos+1
      
   Wend
   
EndProcedure

Procedure lookupTrie(*this.Trie,key.s)
  ;Find the value of the key returns the value or 0
  Protected *node.TrieNode,*bkey.byte,result.i   
    
  *node = *this\root
  *bkey = @key 
  *node = *node\Vertex\edge[*bkey\b & $FF]
 
  While *bkey\b <> 0 
   
      If Not *node
         ProcedureReturn 0
      EndIf
      *bkey+1
      result = *node\value
      *node = *node\Vertex\edge[*bkey\b & $FF]
      
   Wend
   
   ProcedureReturn result
   
EndProcedure

Procedure iEnumTrie(*this.Trie,*node.TrieNode,key.s,*fn)
  ;internal Enum trie 
  Protected a.i,tkey.s
 
  If Not *node
      ProcedureReturn;
   EndIf
   
   ;build the key   
   For a=0 To 255
     If *node\Vertex\edge[a]
       tkey = key + Chr(a)
       iEnumTrie(*this,*node\Vertex\edge[a],tkey,*fn);
     Else
       tkey = key
     EndIf 
   Next
   
   ;lookup the key
   If lookupTrie(*this,tkey)
     CallFunctionFast(*fn,@tkey)
     key=tkey
     ProcedureReturn *node
   EndIf   
      
EndProcedure

Procedure EnumTrie(*this.Trie,key.s,*fn.i)
  ;enumerate all the entries below given root key
  Protected *node.TrieNode,*tnode.TrieNode,tkey.i,len.i,pos.i
 
  *node = *this\root;
  tkey = PeekB(@key) & $FF;
  len = Len(key)
  *node = *node\Vertex\edge[tkey]
 
  ;find the root   
  While *node
   
    If *node
       *tnode =*node
     EndIf
    
     pos+1
     tkey = PeekB(@key+pos) & $FF
     *node = *node\Vertex\edge[tkey]
        
   Wend
   ;enum the root
   While *tnode
    
     *tnode = iEnumTrie(*this,*tnode,key,*fn)
     tkey = PeekB(@key+pos) & $FF
    
     If *tnode
      *tnode = *tnode\Vertex\edge[tkey]
     EndIf   
    
   Wend
   
EndProcedure

DataSection: vt_Trie:
  Data.i @FreeTrie()
  Data.i @AddTrie()
  Data.i @lookupTrie()
  Data.i @EnumTrie()
EndDataSection   



; Hacky Test code_____________________________________________________________________
 Global result.s 
 Procedure MyTreeCallBack(*item)
;    
   result + PeekS(*item) + " "  
;  
 EndProcedure   
; 
Global mt.clsTrie = NewTrie(@mt)
Global Dim gApps.s(100)
Global gAppCnt,gScanDone,gappSize
Global gWinScan,gKillScan,gScanDone,gscanpos,gloaded,gTotalDriveSize.q,gScanSum.q,gmwind,gmvis
Structure fDat 
  file.s{256} 
  app.s {64}
EndStructure   
Structure scaninf
  mode.i 
  dir.s 
EndStructure 

Enumeration
  #Window_Media
  #LV_APPS
  #S_APP
   
  #M_ReScan
  #PBar
  #TDrive
  #TFile
  #TCount
  #M_Help
  #M_About
  #M_port 
EndEnumeration

Procedure addapp(filePath.s,name.s,fn)
  
  If Not mt\LookUp(name) 
    If gAppCnt >= gAppSize 
      gAppSize + 100 
      ReDim gapps.s(gAppSize) 
    EndIf   
    
    gapps(gAppCnt) = filepath 
    mt\Add(name,gAppCnt)
    gAppCnt+1
    If IsFile(fn)
      dat.fDat
      dat\app = name
      dat\file = filePath 
      FileSeek(fn,Lof(fn))
      WriteData(fn,@dat,SizeOf(fdat))
    EndIf 
  EndIf
  
EndProcedure   

Procedure.s dirlist(dir.s,bRec,ofn):
  Static strFiles.s,ct1
  Protected sumf.f,tot.f
  mDir=ExamineDirectory(#PB_Any,dir,"*.*")  
  
  If mDir ;And Not gKillScan
    While NextDirectoryEntry(mDir)
      gScanSum + DirectoryEntrySize(mDir)
      If gTotalDriveSize <> 0 And gScanSum <> 0 And gWinScan  
        sumf = gScanSum
        tot = gTotalDriveSize
        Scanpos = Int((sumf / tot) * 100.0) 
        SetGadgetState(#pbar,Scanpos)
      EndIf  
      If DirectoryEntryType(mDir)=#PB_DirectoryEntry_File
        FN.s=DirectoryEntryName(mDir):
        exe.s = GetExtensionPart(FN)
        If exe = "exe"   
           FFN.s= dir+"\"+FN
           If IsWindow(gWinScan)
             SetGadgetText(#Tfile,FFN)
           EndIf  
           ts.s = LCase(Left(FN,Len(FN)-4))
           addApp(FFN,ts,ofn)
           ct1+1
         EndIf
       Else
         td$=DirectoryEntryName(mDir)
         If td$<>"." And td$<>".."
           If bRec=0
             dirlist(Dir+"\"+td$,bRec,ofn)
           EndIf
         EndIf
      EndIf
    Wend
    FinishDirectory(mDir)
  EndIf
EndProcedure:


Procedure AddToDB(*scan.scaninf)
  Protected filn,fn.i,ts.s,dir.s
  Protected fb.q,tb.q,tfb.q,titlecount.i 
    
  dir=*scan\dir
  
   
  SetErrorMode_(#SEM_FAILCRITICALERRORS)
  

  
  If *scan\mode=1 Or *scan\mode=2
    
    fn = OpenFile(-1,"launchy.lbn")
    
    If dir = "\"
          
      For d = 'A' To 'Z' 
        gScanSum=0
        dir = Chr(d) + ":\"
        SetGadgetText(#TDrive,dir)
        GetDiskFreeSpaceEx_(dir,@fb,@TB,@TFB)
        gTotalDriveSize = (TB - TFB) 
        dirlist(dir,0,fn)
      Next  
     
    Else 
             
      drive.s  = Left(dir,3)
      
      GetDiskFreeSpaceEx_(drive,@fb,@TB,@TFB)
      gTotalDriveSize = (TB - TFB) 
      SetGadgetText(#TDrive,drive)
      dirlist(dir,0,fn)
    EndIf   
     
  ElseIf *scan\mode=0 
    fn=ReadFile(#PB_Any,"launchy.lbn")
    If fn
      While Not Eof(fn)
        indat.fdat ;ts=Space(512)
        ReadData(fn,@indat,SizeOf(fdat))
        addapp(indat\file,indat\app,0)
      Wend
      If IsFile(fn)
       CloseFile(fn)
      EndIf   
    EndIf 
 EndIf
  gScanDone = 1
  
  SetErrorMode_(0)
  
EndProcedure  

Procedure Open_ScanGui(mode)
 Protected title.s,evs.i,dir.s,scan.scaninf,result 
 title = "Launchy Scaner"  
 fn = OpenFile(-1,"launchy.lbn")
 homedir.s = Left(GetCurrentDirectory(),3)
 
  
 tlen = Lof(fn) 
 CloseFile(fn)
 
 If tlen = 0 Or mode   
   
   If tlen = 0 
     result = MessageRequester("Launcy Scan - Add Links","Would like to scan your entire system?",#PB_MessageRequester_YesNo)
     If result = #PB_MessageRequester_Yes
       bScanAll=1
       dir = "\"
     EndIf
     mode=1
   EndIf   
     
   If Not bScanAll 
      dir.s = PathRequester("Please choose a directory To scan", InitialPath$)
      ;dir = Left(dir,Len(dir)-1)
   EndIf     
   
   scan\mode = mode
   scan\dir = dir 
   
   If dir <> ""
   
   gWinScan = OpenWindow(-1, 354, 253, 492, 126, Title, #PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar )
   
    If gWinScan
       ProgressBarGadget(#PBar, 5, 85, 480, 35, 0, 100, #PB_ProgressBar_Smooth)
       TextGadget(#TDrive, 10, 10, 90, 30, "")
       TextGadget(#TFile, 10, 50, 475, 30, "")
       TextGadget(#TCount, 100, 10, 200,30,"")
    EndIf
    
    If dir <> ""
         
      
      gScanDone=0
      CreateThread(@AddToDB(),@scan)
 
      Repeat 
 
         evs=WindowEvent()
         Delay(0)
 
       Until gScanDone Or evs=#WM_CLOSE  
    Else 
      If IsWindow(gWinScan)
        CloseWindow(gWinScan)
      EndIf   
       gWinScan=0
    EndIf    
    If gScanDone
      If IsWindow(gWinScan)
        CloseWindow(gWinScan)
      EndIf   
      gWinScan=0
    EndIf
    
    EndIf 
    
 Else 
   scan\mode = 0
   scan\dir = ""
   
   AddToDB(@scan)

   
EndIf  
 
EndProcedure

Procedure UpdateList(*item)
  If *item  
     item.s = PeekS(*item)
     AddGadgetItem(#LV_APPS,-1,item) 
     SetGadgetState(#LV_APPS,0)  
   EndIf 
 EndProcedure   


mod.scaninf 
mod\dir = "\"
mod\mode = 0 
AddToDB(@mod)
;Open_ScanGui(1)
Global gpt
gmwind = OpenWindow(-1,300,300,300,300,"Runner", #PB_Window_SystemMenu)

StringGadget(#S_APP,5,5,290,20,"")
ListViewGadget(#LV_APPS,5,30,290,260)

If CreateMenu(0, WindowID(gmwind))  ; 
  MenuTitle("Apps")
  MenuItem(#M_ReScan, "Add Apps")
EndIf 

AddKeyboardShortcut(gmwind, #PB_Shortcut_Down,10)
AddKeyboardShortcut(gmwind, #PB_Shortcut_Up,11)
AddKeyboardShortcut(gmwind, #PB_Shortcut_Return,12)

SetActiveGadget(#S_APP)

 Repeat 
      
      EV = WaitWindowEvent()
      EVG = EventGadget()
      EVT = EventType()
      EVW=EventWindow()
       
      If ev  
      If EVW=gmwind
        If EV = #PB_Event_Menu
           mev = EventMenu()
           Select mev 
            Case #M_ReScan 
               Open_ScanGui(2)
             Case 10 
               If gpt < CountGadgetItems(#LV_APPS)
                  gpt+1 
                EndIf        
                SetGadgetState(#LV_APPS,gpt)
             Case 11 
               If gpt > 0 
                gpt-1
              EndIf 
              SetGadgetState(#LV_APPS,gpt)
             Case 12  
               pos = GetGadgetState(#LV_APPS)
                If pos >= 0 
                  tapp.s = GetGadgetItemText(#LV_APPS,pos)
                  res = mt\LookUp(tapp.s)
                  If res 
                    RunProgram(gapps(res))
                    SetActiveGadget(#S_APP)
                  EndIf
                EndIf 
          EndSelect 
        
        ElseIf EV = #PB_Event_Gadget 
          Select EVG 
              Case #LV_APPS 
                If evt = #PB_EventType_LeftDoubleClick 
                pos = GetGadgetState(#LV_APPS)
                tapp.s = GetGadgetItemText(#LV_APPS,pos)
                res = mt\LookUp(tapp.s)
                If res 
                  RunProgram(gapps(res))
                  SetActiveGadget(#S_APP)
                EndIf
                EndIf 
              Case #S_APP 
                tapp.s = GetGadgetText(#S_APP) 
                If Len(tapp) > 1 
                  ClearGadgetItems(#LV_APPS)
                  mt\Enum(tapp,@UpdateList())
                EndIf 
            EndSelect        
          EndIf
        EndIf
      EndIf 
            
Until EV = #WM_CLOSE