WinBatch Dialogs, keyboard events and focus ...

Started by mhall, August 29, 2014, 02:10:06 AM

Previous topic - Next topic

mhall

Hi,

I working on a dynamic dialog at the moment that listens for keyboard presses inside of the timer event of the dialog callback. Works just fine ... but I have noticed that the dialog is very selfish when it comes to keyboard events. For instance, one of the keypresses I listen for is {ENTER} .. while typing this message I pressed enter and, even though the browser has focus, the dialog captured that keypress, acted on it and stole focus. The same thing happens with other keypresses I am using.

Anything I should be looking at on this? I'm running Windows7 and using WinBatch 2014B.

My basic setup looks like this (obviously not a working sample, just the code taken from my timer handler):


          case MSG_TIMER

keyCodeList       = '{F5} {F7} {ENTER}'
keyPressed        = strLower( waitForKeyEx( keyCodeList, .01 ) )
keyPressedValue   = itemExtract( keyPressed, keyCodeList, @TAB )

select @True

case keyPressedValue == '{F5}'

;// REFRESH THE VIEW
getControlValues()
updateOrderList()

break

case keyPressedValue == '{F7}'

getControlValues()

;// OUTPUT SELECTED PRODUCTS
if output_PSD || output_Print && strLower( input_selected ) == 'database'
message( 'Oopsies ...', 'We need an input path for the high resolution files. Those are not stored in the database.' )
return(RET_DO_NOT_EXIT)
endif

outputProducts( filter_array, rowContent_Selected )

break


case keyPressedValue == '{ENTER}'

if rCount == 0 then return ( RET_DO_DEFAULT )

getControlValues()
openInPhotoShop( rowContent_Selected, filter_array )

break


endSelect

return( RET_DO_DEFAULT )




Thanks!
~Micheal

td

You need to use DialogProcOption 1000 to disable the dialog during the timer event.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

mhall


mhall

Hmmm ... as soon as I do that, my dialog flickers like mad. I have the timer interval set at 50 as that gives me decent response to keyboard events, otherwise I find myself having to hold keys for longer periods or potentially missing the event.

Not only does it flicker crazily, but not it completely steals focus as it gets focus back each time the dialog is re-enabled.

Perhaps I did it wrong? I placed the dialogProcOptions call for disable at the beginning of the timer event and the call for enable at the end.

Or am I wrong in how I am going about listening for keyboard events?


case MSG_TIMER

dialogProcOptions( outputCollage_Handle, DPO_DISABLESTATE, 1 )

keyCodeList       = '{F5} {F7} {ENTER}'
keyPressed        = strLower( waitForKeyEx( keyCodeList, .01 ) )


keyPressedValue   = itemExtract( keyPressed, keyCodeList, @TAB )

select @True

case keyPressedValue == '{F5}'

;// REFRESH THE VIEW
getControlValues()
updateOrderList()

break

case keyPressedValue == '{F7}'

getControlValues()

;// OUTPUT SELECTED PRODUCTS
if output_PSD || output_Print && strLower( input_selected ) == 'database'
message( 'Oopsies ...', 'We need an input path for the high resolution files. Those are not stored in the database.' )
return(RET_DO_NOT_EXIT)
endif

outputProducts( filter_array, rowContent_Selected )

break


case keyPressedValue == '{ENTER}'

getControlValues()
if rCount == 0 then return ( RET_DO_DEFAULT )

openInPhotoShop( rowContent_Selected, filter_array )

break


endSelect


;// TRIGGER A LIST REFRESH AND OUTPUT SELECTED PRODUCTS
;// BASED ON A TIMER
if auto_refresh

timer_tick = timer_tick + 2

dialogControlSet( outputCollage_Handle, 'VaryText_NextCheck', DC_TITLE, ( ( update_ticks_to_wait - timer_tick ) + 0.0 ) / tick_factor )

if timer_tick >= update_ticks_to_wait

;// UPDATE LIST OF ORDERS AND GET GRID CONTENTS AFTER FILTERING
if use_imported_list
buildArray( order_id_list )
else
updateOrderList()
endif

getControlValues()

;// IF THE GRID CONTAINS ORDERS, THEN OUTPUT SELECTED PRODUCTS
if arrInfo( rowContents, -1 ) && ok_to_process then outputProducts( filter_array, rowContents  )

timer_tick = 0

endif

endif


;// REFRESH THE CONTENTS OF THE GRID AFTER TIMER DELAY
;// BASED ON CONTROL INTERACTIONS ( CHECKBOXES FOR COLLAGES, SINGLEPRINTS AND IMAGEPACKAGES )
if reload_timer

reload_tick = reload_tick + 1
if reload_tick > reload_ticks_to_wait

;// UPDATE LIST OF ORDERS AND GET GRID CONTENTS AFTER FILTERING
reload_timer = @FALSE
reload_tick = 0

if use_imported_list
buildArray( order_id_list )
else
updateOrderList()
endif

getControlValues()

endif

endif


dialogProcOptions( outputCollage_Handle, DPO_DISABLESTATE, 0 )

return( RET_DO_DEFAULT )


JTaylor

You need to do something like:

        If WinGetActive() != "YOUR WINDOW NAME" Then Return -1   ;Checks to make sure your script is active


Jim

td

Quote from: mhall on August 29, 2014, 07:01:41 PM
Hmmm ... as soon as I do that, my dialog flickers like mad. I have the timer interval set at 50 as that gives me decent response to keyboard events, otherwise I find myself having to hold keys for longer periods or potentially missing the event.

Not only does it flicker crazily, but not it completely steals focus as it gets focus back each time the dialog is re-enabled.

Perhaps I did it wrong? I placed the dialogProcOptions call for disable at the beginning of the timer event and the call for enable at the end.

Or am I wrong in how I am going about listening for keyboard events?
...

That was a bad suggestion on my part.  Friday was a very hectic day and I answered too hastily. A timer set to 50 ms is going to cause the dialog's title bar to dim and brighten at a very high rate.   

The WaitForKeyEx function checks the system keyboard buffer for key presses and not the dialog's message queue for key strokes so every key press will be detected and not just those directed at the dialog. As already suggested one way around this is to check whether or not the dialog is the active process before processing key strokes.

Another possible solution is to use dialog global context menu shortcut keys. These have the advantages of only being active when the dialog is the active Window and not requiring a timer event.  You do have to be careful about certain keys because the dialog uses some key combinations for dialog navigation.  Outside of that, the technique works well.

The help file doesn't do good job explaining how to use dialog shortcut keys so don't be afraid to ask, if you are interested in perusing this approach.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

td

Here's a very crude example of handling key strokes using WIL Dialog's context menu functionality.

Code (winbatch) Select

InitDialogConstants()                                       ; Initialize Dialog Constants (need only be done once usually)

#DefineSubroutine MyDialogCallbackProc(MyDialog_Handle,MyDialog_Message,MyDialog_Name,MyDialog_EventInfo,MyDialog_ChangeInfo)
   ON_EQUAL = @TRUE                                         ; Initialize variable ON_EQUAL
   switch MyDialog_Message                                  ; Switch based on Dialog Message type
      case MSG_INIT                                         ; Standard Initialization message
         DialogProcOptions(MyDialog_Handle,MSG_BUTTONPUSHED,@TRUE)
         DialogProcOptions(MyDialog_Handle,MSG_MENUITEM,@TRUE)
;         DialogProcOptions(MyDialog_Handle,MSG_MENUITEMINIT,@TRUE)
         return(RET_DO_DEFAULT)

     case MSG_BUTTONPUSHED
        if MyDialog_Name == "PushButton_OK"                ; OK
              return(RET_DO_DEFAULT)

        elseif MyDialog_Name == "PushButton_Cancel"        ; Cancel
              return(RET_DO_DEFAULT)

        endif                                              ; MyDialog_Name
        return(RET_DO_DEFAULT)

     case MSG_MENUITEM
        if MyDialog_Name == "cmi1_Enter"                   ; \{Enter]
           strText=DialogControlGet(MyDialog_Handle,"MultiLineBox_1",DC_EDITBOX,0)
           DialogControlset(MyDialog_Handle,"MultiLineBox_1",DC_EDITBOX,strText:@CRLF:"Enter Key Pressed")
             return(RET_DO_DEFAULT)

        elseif MyDialog_Name == "cmi2_F5"                  ; \{5}
           strText=DialogControlGet(MyDialog_Handle,"MultiLineBox_1",DC_EDITBOX,0)
           DialogControlset(MyDialog_Handle,"MultiLineBox_1",DC_EDITBOX,strText:@CRLF:"F5 Key Pressed")
          return(RET_DO_DEFAULT)

        elseif MyDialog_Name == "cmi3_F7"                  ; \{F7}
           strText=DialogControlGet(MyDialog_Handle,"MultiLineBox_1",DC_EDITBOX,0)
           DialogControlset(MyDialog_Handle,"MultiLineBox_1",DC_EDITBOX,strText:@CRLF:"F7 Key Pressed")
          return(RET_DO_DEFAULT)

        endif                                              ; MyDialog_Name
        return(RET_DO_DEFAULT)

   endswitch                                                ; MyDialog_Message
   return(RET_DO_DEFAULT)
#EndSubroutine                                              ; End of Dialog Callback MyDialogCallbackProc

MyDialogFormat=`WWWDLGED,6.2`

MyDialogCaption=`WIL Dialog 1`
MyDialogX=882
MyDialogY=085
MyDialogWidth=425
MyDialogHeight=242
MyDialogNumControls=006
MyDialogProcedure=`MyDialogCallbackProc`
MyDialogFont=`DEFAULT`
MyDialogTextColor=`DEFAULT`
MyDialogBackground=`DEFAULT,DEFAULT`
MyDialogConfig=0

MyDialog001=`119,225,033,011,PUSHBUTTON,"PushButton_OK",DEFAULT,"OK",1,10,32,DEFAULT,DEFAULT,DEFAULT`
MyDialog002=`273,225,033,011,PUSHBUTTON,"PushButton_Cancel",DEFAULT,"Cancel",0,20,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MyDialog003=`068,039,257,141,MULTILINEBOX,"MultiLineBox_1",mlVariable1,"Multiline edit 1",DEFAULT,60,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MyDialog004=`000,000,000,000,MENUITEM,"cmi1_Enter",DEFAULT,"\{Enter}",DEFAULT,10,1`
MyDialog005=`000,000,000,000,MENUITEM,"cmi2_F5",DEFAULT,"\{F5}",DEFAULT,20,1`
MyDialog006=`000,000,000,000,MENUITEM,"cmi3_F7",DEFAULT,"\{F7}",DEFAULT,30,1`

ButtonPushed=Dialog("MyDialog")
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

COOL!!!   Don't ever recall this being mentioned as a possibility.    I definitely have some immediate uses.   Thanks.

Jim

JTaylor

Any way to modify these type menus in the Menu Editor?   Not finding them.

You mention the Help file doesn't explain it very well...where is it mentioned in the Help file?

Jim

mhall

Thanks again Tony!

Strangely, I could not adapt your code to work with my dialog. Your dialog works just fine ... but adding menu items to my dialog according to what you posted didn't work. I didn't get any errors, it just wouldn't do anything. Obviously I was doing something wrong. (I'll play with it more on a smaller example to see if I can find out what I was doing incorrectly).

However, in trying to find out why it wasn't working, I realized that your method was essentially providing keyboard shortcuts for text-less menu items. I hadn't seen in the past how to assign keyboard shortcuts and, as I already had a context menu that contained those items, I simply added keyboard shortcuts their menu items and that is working.

Regards,
Micheal

td

It is very simple to add global hot keys to a dialog.  Just fire up the Dialog Editor's Menu Editor by right clicking in your dialog's client area outside of any controls and selecting the Menu Editor menu item. Once in the Menu Editor select the 'Context' radio button and the invisible style.  Simply create new menu  items with a blackslash followed by a key combination for each menu item's only text and then save the edits. 

The example I posted was created with Dialog Editor and WinBatch Studio's user defined callback creation functionality.  Typed in 2 lines of code into the Studio created callback then did a couple of copy and paste operations changing string text as needed.  Removed a few comment characters and was done. Took about 5 min.

Since I don't know what you tried or what other menus you have in your dialog, it is hard to say why it didn't work for you.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

JTaylor

Never noticed the "Context" option at the top before.   That is why I couldn't see the items in the Editor.   Thanks.

Jim

mhall

Thanks Tony - I never saw that.

Makes it dead simple.

~m