Page 1 of 1

record keystrokes and playback

Posted: Mon Jul 29, 2019 9:59 pm
by IdeasVacuum
My program uses an Editor Gadget for the User to prepare/modify text.

I would like to add a macro function where the User can record keystrokes and then play them back to 'auto edit' multiple lines. Has anyone already coded something like this?

Re: record keystrokes and playback

Posted: Tue Jul 30, 2019 9:08 am
by Joris
I've got this sample code (don't know the origin ... me, don't think so ???) :)
Might be a start.

Code: Select all

Structure L4B
  StructureUnion
    l.l
    b.b[4]
  EndStructureUnion
EndStructure
Global key$= Space(255) 
Global chk_ctrl.l,chk_shft.l,chk_alt.l
Procedure WindowCallback(hWnd, uMsg, wParam, lParam)   
  Select uMsg
    Case #WM_CHAR 
      k.L4B : k\l=lParam
      
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_CHAR")
      SetGadgetText(5,Str(wParam))
    Case #WM_KEYDOWN
      k.L4B : k\l=lParam
      
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_KEYDOWN")
      SetGadgetText(5,Str(wParam))
      
      Select wParam
        Case #VK_CONTROL : SetGadgetState(chk_ctrl, #PB_Checkbox_Checked)    
        Case #VK_SHIFT   : SetGadgetState(chk_shft, #PB_Checkbox_Checked)
      EndSelect
      
    Case #WM_KEYUP ;hier opslaan van de ingevoerde toetsen
      k.L4B : k\l=lParam
      
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_KEYUP")
      SetGadgetText(5,Str(wParam))
      
      locale = GetKeyboardLayout_(GetCurrentThreadId_())  
      ctrl$ = Space(100)  
      GetKeyNameText_(MapVirtualKeyEx_(k\l,1,locale), @ctrl$,  100)  
      SetWindowTitle(0,ctrl$)
      
      SetGadgetState(chk_ctrl, #PB_Checkbox_Unchecked)    
      SetGadgetState(chk_shft, #PB_Checkbox_Unchecked)
      SetGadgetState(chk_alt , #PB_Checkbox_Unchecked)
    Case  #WM_DEADCHAR
      k.L4B : k\l=lParam
      
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_DEADCHAR")
      SetGadgetText(5,Str(wParam))
    Case  #WM_SYSCHAR  ;hier opslaan van de ingevoerde toetsen
      k.L4B : k\l=lParam
      
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_SYSCHAR")
      SetGadgetText(5,Str(wParam))
      ;indien vooraf een WM_SYSKEYDOWN gebruikt werd (bvb. Alt)
      SetGadgetState(chk_ctrl, #PB_Checkbox_Unchecked)    
      SetGadgetState(chk_shft, #PB_Checkbox_Unchecked)
      SetGadgetState(chk_alt , #PB_Checkbox_Unchecked)
      
    Case  #WM_SYSKEYDOWN
      k.L4B : k\l=lParam
      
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_SYSKEYDOWN")
      SetGadgetText(5,Str(wParam))
      Select wParam
        Case #VK_CONTROL : SetGadgetState(chk_ctrl, #PB_Checkbox_Checked)    
        Case #VK_SHIFT   : SetGadgetState(chk_shft, #PB_Checkbox_Checked)
        Case #VK_MENU    : SetGadgetState(chk_alt,  #PB_Checkbox_Checked)
      EndSelect
      
  EndSelect 
  
  ProcedureReturn #PB_ProcessPureBasicEvents
  
EndProcedure


OpenWindow(0,0,0,320,240,"Hotkey Test",#PB_Window_SystemMenu | #PB_Window_ScreenCentered |#PB_Window_MinimizeGadget) 
chk_ctrl = CheckBoxGadget(#PB_Any,   5, 5, 40,  17,"Ctrl")
chk_shft = CheckBoxGadget(#PB_Any,  50, 5, 40,  17,"Shft")
chk_alt  = CheckBoxGadget(#PB_Any, 105, 5, 40,  17,"Alt")
TextGadget(1, 100,040,140,20, "") 
TextGadget(2, 100,060,140,20, "") 
TextGadget(3, 100,080,140,20,"") 
TextGadget(4, 100,100,140,20,"") 
TextGadget(5, 100,120,140,20,"") 
SetWindowCallback(@WindowCallback())

Repeat 
  
  Select WaitWindowEvent() 
    Case #PB_Event_CloseWindow 
      CloseWindow(0)
      End
  EndSelect 
  
ForEver

Re: record keystrokes and playback

Posted: Tue Jul 30, 2019 12:07 pm
by IdeasVacuum
Hi Joris

I was stuck in a traffic jam this morning thinking about SendKeys etc, but not sure of the best way to record keystrokes - your sample code is exactly what I need to get my brain functioning again :mrgreen:

Re: record keystrokes and playback

Posted: Tue Jul 30, 2019 12:40 pm
by BarryG
Note that it only works if your app has the focus - it's not global. And it doesn't detect Alt+<Whatever> for me?

Re: record keystrokes and playback

Posted: Thu Aug 01, 2019 1:26 pm
by IdeasVacuum
OK, it works perfectly for the App Window that has focus, that's good for me, but unfortunately it does not work with an Editor Gadget on that Window :(

So, back to square 1 !

Re: record keystrokes and playback

Posted: Thu Aug 01, 2019 1:48 pm
by Sirius-2337
Added code from this topic.

Code: Select all

Structure L4B
  StructureUnion
    l.l
    b.b[4]
  EndStructureUnion
EndStructure
Global key$= Space(255)
Global chk_ctrl.l,chk_shft.l,chk_alt.l
Procedure WindowCallback(hWnd, uMsg, wParam, lParam)   
  Select uMsg
    Case #WM_CHAR
      k.L4B : k\l=lParam
     
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_CHAR")
      SetGadgetText(5,Str(wParam))
    Case #WM_KEYDOWN
      k.L4B : k\l=lParam
     
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_KEYDOWN")
      SetGadgetText(5,Str(wParam))
     
      Select wParam
        Case #VK_CONTROL : SetGadgetState(chk_ctrl, #PB_Checkbox_Checked)   
        Case #VK_SHIFT   : SetGadgetState(chk_shft, #PB_Checkbox_Checked)
      EndSelect
     
    Case #WM_KEYUP ;hier opslaan van de ingevoerde toetsen
      k.L4B : k\l=lParam
     
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_KEYUP")
      SetGadgetText(5,Str(wParam))
     
      locale = GetKeyboardLayout_(GetCurrentThreadId_()) 
      ctrl$ = Space(100) 
      GetKeyNameText_(MapVirtualKeyEx_(k\l,1,locale), @ctrl$,  100) 
      SetWindowTitle(0,ctrl$)
     
      SetGadgetState(chk_ctrl, #PB_Checkbox_Unchecked)   
      SetGadgetState(chk_shft, #PB_Checkbox_Unchecked)
      SetGadgetState(chk_alt , #PB_Checkbox_Unchecked)
    Case  #WM_DEADCHAR
      k.L4B : k\l=lParam
     
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_DEADCHAR")
      SetGadgetText(5,Str(wParam))
    Case  #WM_SYSCHAR  ;hier opslaan van de ingevoerde toetsen
      k.L4B : k\l=lParam
     
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_SYSCHAR")
      SetGadgetText(5,Str(wParam))
      ;indien vooraf een WM_SYSKEYDOWN gebruikt werd (bvb. Alt)
      SetGadgetState(chk_ctrl, #PB_Checkbox_Unchecked)   
      SetGadgetState(chk_shft, #PB_Checkbox_Unchecked)
      SetGadgetState(chk_alt , #PB_Checkbox_Unchecked)
     
    Case  #WM_SYSKEYDOWN
      k.L4B : k\l=lParam
     
      SetGadgetText(1, Str(lParam))
      SetGadgetText(2, Str(k\b[0])+"   "+Str(k\b[1])+"   "+Str(k\b[2])+"   "+Str(k\b[3]))
      GetKeyNameText_(lParam, key$,255)
      SetGadgetText(3,key$)
      SetGadgetText(4,"WM_SYSKEYDOWN")
      SetGadgetText(5,Str(wParam))
      Select wParam
        Case #VK_CONTROL : SetGadgetState(chk_ctrl, #PB_Checkbox_Checked)   
        Case #VK_SHIFT   : SetGadgetState(chk_shft, #PB_Checkbox_Checked)
        Case #VK_MENU    : SetGadgetState(chk_alt,  #PB_Checkbox_Checked)
      EndSelect
     
  EndSelect
 
  ProcedureReturn #PB_ProcessPureBasicEvents
 
EndProcedure

Global Gadget
Procedure GadgetCallback(hWnd, uMsg, wParam, lParam)
  WindowCallback(hWnd, uMsg, wParam, lParam)
  ProcedureReturn CallWindowProc_(Gadget, hWnd, uMsg, wParam, lParam)
EndProcedure


OpenWindow(0,0,0,720,240,"Hotkey Test",#PB_Window_SystemMenu | #PB_Window_ScreenCentered |#PB_Window_MinimizeGadget)
chk_ctrl = CheckBoxGadget(#PB_Any,   5, 5, 40,  17,"Ctrl")
chk_shft = CheckBoxGadget(#PB_Any,  50, 5, 40,  17,"Shft")
chk_alt  = CheckBoxGadget(#PB_Any, 105, 5, 40,  17,"Alt")
TextGadget(1, 100,040,140,20, "")
TextGadget(2, 100,060,140,20, "")
TextGadget(3, 100,080,140,20,"")
TextGadget(4, 100,100,140,20,"")
TextGadget(5, 100,120,140,20,"")

EditorGadget(6, 400, 0, 400, 400)

Gadget = SetWindowLong_(GadgetID(6), #GWL_WNDPROC, @GadgetCallback())

; SetWindowCallback(@WindowCallback())

Repeat
 
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      CloseWindow(0)
      End
  EndSelect
 
ForEver

Re: record keystrokes and playback

Posted: Thu Aug 01, 2019 3:49 pm
by IdeasVacuum
Thanks Sirius-2337, I would never have worked that one out!

Re: record keystrokes and playback

Posted: Sat Aug 03, 2019 2:57 am
by Tenaja
I know I'm late to this party, but scintilla gadget has macro recording and playback built in...

Re: record keystrokes and playback

Posted: Sun Aug 04, 2019 4:25 pm
by IdeasVacuum
Hi Tenaga

Yeah, I think Scintilla would be good in that area, a number of text editors out in the wild are using it, but my Project is bespoke and has text manipulation that probably wouldn't be useful to many people outside of a tiny industry :) To change over to Scintilla would I think make some of the stuff difficult to achieve.

Re: record keystrokes and playback

Posted: Sun Aug 04, 2019 4:53 pm
by skywalk
Yes, I find I am migrating many of my editors that do not need embedded graphics to Scintilla.
Tired of patching the rich edit gadget...
Many useful features are built-in to Scintilla and it is cross platform.

Re: record keystrokes and playback

Posted: Sun Aug 04, 2019 5:59 pm
by Tenaja
The more capabilities a library has, the bigger the learning curve. Once you do a little work with scintilla, though, it becomes second nature. A few years ago I even embedded it into a vb app (work choice) because it only took a few minutes to prototype in PB.