Page 1 of 1

Strange behavior of launched programs

Posted: Sat Nov 10, 2007 3:17 pm
by Tipperton
I have a Microsoft natural keyboard 4000 that uses Microsoft's Intellitype Pro to allow assigning funcitons to the extra keys on the key board.

I decided that I wanted to be able to have up to two functions per key based on whether I pressed it with the shift key down or not. As an example pressing the Calculator key alone would run the Calculator but pressing the Calculator key while holding down a shift key would run Money.

So I wrote this little program:

Code: Select all

; Microsoft Keyboard Key Enhancer
; written by Tipperton in November 2007
;
; The idea behind this program is instead of assigning keys
; to specific programs or files, assign them to run this
; program renamed to reflect the key it is for.
; For example For the calculator key, rename the program to
; CalculatorKey.exe, then configure the Calculator key to run
; this program instead of the calculator.
;
; Now you can press the key alone to get one function or hold
; down the shift key to get a different function.
;
; You can also hold down the control key to bring up the
; configuration window to set up the normal and shifted
; functions for the key.

; Window Constants
Enumeration
  #wndConfig
EndEnumeration

; Gadget Constants
Enumeration
  #fraUnshifted
  #txtUnshiftedCommand
  #strUnshiftedCommand
  #btnUnshiftedBrowse
  #txtUnshiftedParameters
  #strUnshiftedParameters
  #fraShifted
  #txtShiftedCommand
  #strShiftedCommand
  #txtShiftedParameters
  #btnShiftedBrowse
  #strShiftedParameters
  #btnOK
  #btnCancel
EndEnumeration

Procedure Open_wndConfig(KeyName.s)
  If OpenWindow(#wndConfig, #PB_Ignore, #PB_Ignore, 400, 200, "Configure "+KeyName+" key", #PB_Window_TitleBar | #PB_Window_ScreenCentered)
    If CreateGadgetList(WindowID(#wndConfig))
      Frame3DGadget(#fraUnshifted, 10, 10, 380, 70, "Unshifted")
      TextGadget(#txtUnshiftedCommand, 20, 30, 60, 20, "Command:", #PB_Text_Right)
      StringGadget(#strUnshiftedCommand, 90, 30, 230, 20, "")
      ButtonGadget(#btnUnshiftedBrowse, 320, 30, 60, 20, "Browse")
      TextGadget(#txtUnshiftedParameters, 20, 50, 60, 20, "Parameters:", #PB_Text_Right)
      StringGadget(#strUnshiftedParameters, 90, 50, 290, 20, "")
      Frame3DGadget(#fraShifted, 10, 90, 380, 70, "Shifted")
      TextGadget(#txtShiftedCommand, 20, 110, 60, 20, "Command:", #PB_Text_Right)
      StringGadget(#strShiftedCommand, 90, 110, 230, 20, "")
      ButtonGadget(#btnShiftedBrowse, 320, 110, 60, 20, "Browse")
      TextGadget(#txtShiftedParameters, 20, 130, 60, 20, "Parameters:", #PB_Text_Right)
      StringGadget(#strShiftedParameters, 90, 130, 290, 20, "")
      ButtonGadget(#btnOK, 260, 170, 60, 20, "OK", #PB_Button_Default)
      ButtonGadget(#btnCancel, 330, 170, 60, 20, "Cancel")
    EndIf
    SetActiveWindow_(WindowID(#wndConfig))
  EndIf
EndProcedure

; Get status of Shift and Control keys
KeyState.b=0
If GetAsyncKeyState_(#VK_CONTROL)&$8000
  KeyState+2
EndIf
If GetAsyncKeyState_(#VK_SHIFT)&$8000
  KeyState+1
EndIf

; Get information about program for accessing prefs file
FileSpec.s=ProgramFilename()
PathPart.s=GetPathPart(FileSpec)
FilePart.s=GetFilePart(FileSpec)
ExtPart.s=GetExtensionPart(FileSpec)
FilePart=Left(FilePart, Len(FilePart)-(Len(ExtPart)+1))
KeyName.s=ReplaceString(FilePart, "Key", "")
PrefsFile.s=PathPart+FilePart+".prefs"

; Load preferences if available
If OpenPreferences(PrefsFile)
  PreferenceGroup("Unshifted")
  UnshiftedCommand.s=Trim(ReadPreferenceString("Command", ""))
  If Len(UnshiftedCommand)
    If FindString(UCase(UnshiftedCommand), ".EXE", 1)
      UnshiftedWindowMode.l=#SW_SHOW
    Else
      UnshiftedWindowMode=0
    EndIf
    UnshiftedPath.s=GetPathPart(UnshiftedCommand)
  Else
    UnshiftedPath=""
  EndIf
  UnshiftedParameters.s=Trim(ReadPreferenceString("Parameters", ""))
  PreferenceGroup("Shifted")
  ShiftedCommand.s=Trim(ReadPreferenceString("Command", ""))
  If Len(ShiftedCommand)
    If FindString(UCase(ShiftedCommand), ".EXE", 1)
      ShiftedWindowMode.l=#SW_SHOW
    Else
      ShiftedWindowMode=0
    EndIf
    ShiftedPath.s=GetPathPart(ShiftedCommand)
  Else
    ShiftedPath=""
  EndIf
  ShiftedParameters.s=Trim(ReadPreferenceString("Parameters", ""))
  ClosePreferences()
Else
  UnshiftedCommand=""
  UnshiftedParameters=""
  ShiftedCommand=""
  ShiftedParameters=""
  KeyState=2
EndIf

; Choose action based on shift and control key state or if there is no prefs file
Select KeyState

  ; Prefs exist and no shift or control key pressed
  Case 0
    If Len(UnshiftedCommand)
      hInstance.l=ShellExecute_(0, 0, UnshiftedCommand, UnshiftedParameters, UnshiftedPath, UnshiftedWindowMode)
      If hInstance>32 Or hInstance<0
        SetActiveWindow_(hInstance)
      EndIf
    Else
      PlaySound_("Default", 0, #SND_ALIAS)
    EndIf

  ; Prefs exist and shift key pressed
  Case 1
    If Len(ShiftedCommand)
      hInstance=ShellExecute_(0, 0, ShiftedCommand, ShiftedParameters, ShiftedPath, ShiftedWindowMode)
      If hInstance>32 Or hInstance<0
        SetActiveWindow_(hInstance)
      EndIf
    Else
      PlaySound_("Default", 0, #SND_ALIAS)
    EndIf

  ; Prefs don't exist or control key pressed
  Case 2
    Open_wndConfig(KeyName)
    SetGadgetText(#strUnshiftedCommand, Trim(UnshiftedCommand))
    SetGadgetText(#strUnshiftedParameters, Trim(UnshiftedParameters))
    SetGadgetText(#strShiftedCommand, Trim(ShiftedCommand))
    SetGadgetText(#strShiftedParameters, Trim(ShiftedParameters))
    Repeat ; Start of the event loop
      Event=WaitWindowEvent() ; This line waits until an event is received from Windows
      WindowID=EventWindow() ; The Window where the event is generated, can be used in the gadget procedures
      GadgetID=EventGadget() ; Is it a gadget event?
      EventType=EventType() ; The event type
      If Event=#PB_Event_Gadget
        If GadgetID=#btnUnshiftedBrowse
          NewUnshiftedCommand.s=Trim(OpenFileRequester("Select file to open or run", GetGadgetText(#strUnshiftedCommand), "All files (*.*)|*.*", 1))
          If Len(NewUnshiftedCommand)
            SetGadgetText(#strUnshiftedCommand, NewUnshiftedCommand)
          EndIf
        ElseIf GadgetID=#btnShiftedBrowse
          NewShiftedCommand.s=Trim(OpenFileRequester("Select file to open or run", GetGadgetText(#strShiftedCommand), "All files (*.*)|*.*", 1))
          If Len(NewShiftedCommand)
            SetGadgetText(#strShiftedCommand, NewShiftedCommand)
          EndIf
        ElseIf GadgetID=#btnOK
          CreatePreferences(PrefsFile)
          PreferenceGroup("Unshifted")
          WritePreferenceString("Command", Trim(GetGadgetText(#strUnshiftedCommand)))
          WritePreferenceString("Parameters", Trim(GetGadgetText(#strUnshiftedParameters)))
          PreferenceGroup("Shifted")
          WritePreferenceString("Command", Trim(GetGadgetText(#strShiftedCommand)))
          WritePreferenceString("Parameters", Trim(GetGadgetText(#strShiftedParameters)))
          ClosePreferences()
          Event=#PB_Event_CloseWindow
        ElseIf GadgetID=#btnCancel
          Event=#PB_Event_CloseWindow
        EndIf
      EndIf
    Until Event=#PB_Event_CloseWindow ; End of the event loop

  ; Prefs exist and both shift and control key pressed
  Default
    PlaySound_("Default", 0, #SND_ALIAS)
EndSelect
End
It works but has a minor problem, programs run from the shifted function don't become the active window, nor does the configuration window when your press the key with control held down.

On further testing it appears that the shifted behavior is from IntelliType Pro itself. :(

Any ideas how I can solve both problems?

Thanks!

Update

Posted: Sun Nov 11, 2007 3:39 pm
by Tipperton
Well, I solved two of the problems by replacing the two lines that read:

Code: Select all

SetActiveWindow_(hInstance)
with:

Code: Select all

BringWindowToTop_(hInstance)
So that just leaves fixing the configuration window, I tried the BringWindowToTop function on it too but it didn't work. I have also tried PB's built-in ActivateWindow function, still didn't work.[/quote]

Re: Update

Posted: Sun Nov 11, 2007 9:09 pm
by PB

Re: Update

Posted: Sun Nov 11, 2007 11:18 pm
by Tipperton
PB wrote:Try my "ForceFore" procedure
Thanks, I'll save that for when I need it.

However as I read the thread, I realized that since the window I was having a problem with was one that was launched by my program I could use the SetForegroundWindow_() function to bring it to the top and it works.

So the final working program is:

Code: Select all

; Microsoft Keyboard Key Enhancer
; written by Tipperton in November 2007
;
; The idea behind this program is instead of assigning keys
; to specific programs or files, assign them to run this
; program renamed to reflect the key it is for.
; For example For the calculator key, rename the program to
; CalculatorKey.exe, then configure the Calculator key to run
; this program instead of the calculator.
;
; Now you can press the key alone to get one function or hold
; down the shift key to get a different function.
;
; You can also hold down the control key to bring up the
; configuration window to set up the normal and shifted
; functions for the key.

; Window Constants
Enumeration
  #wndConfig
EndEnumeration

; Gadget Constants
Enumeration
  #fraUnshifted
  #txtUnshiftedCommand
  #strUnshiftedCommand
  #btnUnshiftedBrowse
  #txtUnshiftedParameters
  #strUnshiftedParameters
  #fraShifted
  #txtShiftedCommand
  #strShiftedCommand
  #txtShiftedParameters
  #btnShiftedBrowse
  #strShiftedParameters
  #btnOK
  #btnCancel
EndEnumeration

; Define and create configuration window
Procedure Open_wndConfig(KeyName.s)
  If OpenWindow(#wndConfig, #PB_Ignore, #PB_Ignore, 400, 200, "Configure "+KeyName+" key", #PB_Window_TitleBar | #PB_Window_ScreenCentered)
    If CreateGadgetList(WindowID(#wndConfig))
      Frame3DGadget(#fraUnshifted, 10, 10, 380, 70, "Unshifted")
      TextGadget(#txtUnshiftedCommand, 20, 30, 60, 20, "Command:", #PB_Text_Right)
      StringGadget(#strUnshiftedCommand, 90, 30, 230, 20, "")
      ButtonGadget(#btnUnshiftedBrowse, 320, 30, 60, 20, "Browse")
      TextGadget(#txtUnshiftedParameters, 20, 50, 60, 20, "Parameters:", #PB_Text_Right)
      StringGadget(#strUnshiftedParameters, 90, 50, 290, 20, "")
      Frame3DGadget(#fraShifted, 10, 90, 380, 70, "Shifted")
      TextGadget(#txtShiftedCommand, 20, 110, 60, 20, "Command:", #PB_Text_Right)
      StringGadget(#strShiftedCommand, 90, 110, 230, 20, "")
      ButtonGadget(#btnShiftedBrowse, 320, 110, 60, 20, "Browse")
      TextGadget(#txtShiftedParameters, 20, 130, 60, 20, "Parameters:", #PB_Text_Right)
      StringGadget(#strShiftedParameters, 90, 130, 290, 20, "")
      ButtonGadget(#btnOK, 260, 170, 60, 20, "OK", #PB_Button_Default)
      ButtonGadget(#btnCancel, 330, 170, 60, 20, "Cancel")
    EndIf
    SetForegroundWindow_(WindowID(#wndConfig))
  EndIf
EndProcedure

; Get status of Shift and Control keys
KeyState.b=0
If GetAsyncKeyState_(#VK_CONTROL)&$8000
  KeyState+2
EndIf
If GetAsyncKeyState_(#VK_SHIFT)&$8000
  KeyState+1
EndIf

; Wait until both the Shift and Control keys have been released
; to make sure that either of them being held down has no affect
; the program that gets launched
While GetAsyncKeyState_(#VK_CONTROL)&$8000 Or GetAsyncKeyState_(#VK_SHIFT)&$8000
  Delay(1)
Wend

; Get information about program for accessing prefs file
FileSpec.s=ProgramFilename()
PathPart.s=GetPathPart(FileSpec)
FilePart.s=GetFilePart(FileSpec)
ExtPart.s=GetExtensionPart(FileSpec)
FilePart=Left(FilePart, Len(FilePart)-(Len(ExtPart)+1))
KeyName.s=ReplaceString(FilePart, "Key", "")
PrefsFile.s=PathPart+FilePart+".prefs"

; Load preferences if available
If OpenPreferences(PrefsFile)
  PreferenceGroup("Unshifted")
  UnshiftedCommand.s=Trim(ReadPreferenceString("Command", ""))
  If Len(UnshiftedCommand)
    If FindString(UCase(UnshiftedCommand), ".EXE", 1)
      UnshiftedWindowMode.l=#SW_SHOW
    Else
      UnshiftedWindowMode=0
    EndIf
    UnshiftedPath.s=GetPathPart(UnshiftedCommand)
  Else
    UnshiftedPath=""
  EndIf
  UnshiftedParameters.s=Trim(ReadPreferenceString("Parameters", ""))
  PreferenceGroup("Shifted")
  ShiftedCommand.s=Trim(ReadPreferenceString("Command", ""))
  If Len(ShiftedCommand)
    If FindString(UCase(ShiftedCommand), ".EXE", 1)
      ShiftedWindowMode.l=#SW_SHOW
    Else
      ShiftedWindowMode=0
    EndIf
    ShiftedPath.s=GetPathPart(ShiftedCommand)
  Else
    ShiftedPath=""
  EndIf
  ShiftedParameters.s=Trim(ReadPreferenceString("Parameters", ""))
  ClosePreferences()
Else
  UnshiftedCommand=""
  UnshiftedParameters=""
  ShiftedCommand=""
  ShiftedParameters=""
  KeyState=2
EndIf

; Choose action based on shift and control key state
; or if there is no prefs file
Select KeyState

  ; Prefs exist and no shift or control key pressed
  Case 0
    If Len(UnshiftedCommand)
      hInstance.l=ShellExecute_(0, 0, UnshiftedCommand, UnshiftedParameters, UnshiftedPath, UnshiftedWindowMode)
      If hInstance>32 Or hInstance<0
        BringWindowToTop_(hInstance)
      EndIf
    Else
      PlaySound_("Default", 0, #SND_ALIAS)
    EndIf

  ; Prefs exist and shift key pressed
  Case 1
    If Len(ShiftedCommand)
      hInstance=ShellExecute_(0, 0, ShiftedCommand, ShiftedParameters, ShiftedPath, ShiftedWindowMode)
      If hInstance>32 Or hInstance<0
        BringWindowToTop_(hInstance)
      EndIf
    Else
      PlaySound_("Default", 0, #SND_ALIAS)
    EndIf

  ; Prefs don't exist or control key pressed
  Case 2
    Open_wndConfig(KeyName)
    SetGadgetText(#strUnshiftedCommand, Trim(UnshiftedCommand))
    SetGadgetText(#strUnshiftedParameters, Trim(UnshiftedParameters))
    SetGadgetText(#strShiftedCommand, Trim(ShiftedCommand))
    SetGadgetText(#strShiftedParameters, Trim(ShiftedParameters))
    Repeat ; Start of the event loop
      Event=WaitWindowEvent() ; This line waits until an event is received from Windows
      WindowID=EventWindow() ; The Window where the event is generated, can be used in the gadget procedures
      GadgetID=EventGadget() ; Is it a gadget event?
      EventType=EventType() ; The event type
      If Event=#PB_Event_Gadget
        If GadgetID=#btnUnshiftedBrowse
          NewUnshiftedCommand.s=Trim(OpenFileRequester("Select file to open or run", GetGadgetText(#strUnshiftedCommand), "All files (*.*)|*.*", 1))
          If Len(NewUnshiftedCommand)
            SetGadgetText(#strUnshiftedCommand, NewUnshiftedCommand)
          EndIf
        ElseIf GadgetID=#btnShiftedBrowse
          NewShiftedCommand.s=Trim(OpenFileRequester("Select file to open or run", GetGadgetText(#strShiftedCommand), "All files (*.*)|*.*", 1))
          If Len(NewShiftedCommand)
            SetGadgetText(#strShiftedCommand, NewShiftedCommand)
          EndIf
        ElseIf GadgetID=#btnOK
          CreatePreferences(PrefsFile)
          PreferenceGroup("Unshifted")
          WritePreferenceString("Command", Trim(GetGadgetText(#strUnshiftedCommand)))
          WritePreferenceString("Parameters", Trim(GetGadgetText(#strUnshiftedParameters)))
          PreferenceGroup("Shifted")
          WritePreferenceString("Command", Trim(GetGadgetText(#strShiftedCommand)))
          WritePreferenceString("Parameters", Trim(GetGadgetText(#strShiftedParameters)))
          ClosePreferences()
          Event=#PB_Event_CloseWindow
        ElseIf GadgetID=#btnCancel
          Event=#PB_Event_CloseWindow
        EndIf
      EndIf
    Until Event=#PB_Event_CloseWindow ; End of the event loop

  ; Prefs exist and both shift and control key pressed
  Default
    PlaySound_("Default", 0, #SND_ALIAS)
EndSelect
End
Just in case somebody else thinks this might be useful to them.

Just in case holding down the shift or control key while some program starts (should really only need to watch the shift key since the control key just starts this program configuration routine) I decided to add a while loop that won't exit until both the shift and control keys are not being pressed.