Hi, I've done some much needed improvements to my little DragonPad² project, and I think it works much better now. And for demonstration purposes, this instance of the script now sends its text to notepad, so it should be easier for anybody to try it quickly and easily.
...
The basic idea is this: You dictate to Dragon, and set the focus on DragonPad². It copies any text in its edit box to a variable, and then reads that variable, passing any text to (in this case) Notepad. In the event that variable contains any word that's been designated as a command, it executes that command instead of passing it through as text.
It performs this way either on a one-time basis that you can repeat as desired (which has a couple of uses outside of Dragon dictation) or on a regular timed basis, where it checks the edit field every 250ms, and if it finds it isn't empty, performs the function and then loops back again.
All text dictated to DragonPad² is both appended to a timestamped logfile, and to a variable. When finished dictating, you may view everything you have dictated by pressing f4, and after a brief pause, everything you've dictated or typed into DragonPad²'s edit field will display there, from the variable. To clear that variable, press f5.
You can assign any word whatsoever to an AHK command, by adding it to the command list, and creating a gosub for that command. See the example script. When Dragon types the command into DragonPad2, said command is executed.
Additional features include :
* all text from edit field being appended to a textfile, with timestamps.
* Numerical stamps or optionally timestamps appended to any command. See my examples.
* When you stop the timed cutnpaste, it now puts all the text you've sent to Dragonpad2 back in the edit field.
* Built in timer and word count display.
Usage:
Quick demo:
Start the script, go through the textfile creation dialog (in a hurry you can just keep pressing escape and it will do it all for you.) It will create a file called deleme.txt and open it in Notepad. If not, you need to do this yourself. Then press rctrl-numpad2 to activate DragonPad², and type or dictate some words and then @1 @2 @3 @4 @5 @6 into DragonPad² and then hit Ctrl-numpad0. Watch it work, and then press f4. Take a look at the results.
Or the long version:
Start the script. You should have no problem if you compile it, either. It will open a dialog to create a backup textfile. Eiher name the textfile or let it do that for you. The default is activedir/%A_MM%-%A_DD%-%A_Hour%-%A_Min%.txt
DragonPad² will also open an instance of notepad, and create a file named deleme.txt for it to dictate to by default. You can easily reconfigure it to send to any other word processor instead.
Activate DragonPad² by selecting it or by pressing Ctrl-1 or Ctrl-2. Ctrl-1 displays a messagebox reminding you to do whatever you need to before dictating, such as putting Dragon in "dictate" mode (highly recommended).
Start the timer by pressing the "start" button. When ready to dictate, press "timedcutnpaste" on the menu bar, or else press Ctrl-numpad0.
When DragonPad² has focus, you can dictate directly into it, and any command on the commandlist will be executed as a command instead of passed through as text. I have created 6 examples: @1,@2,@3,@4,@5,@6, and each one demonstrates a couple built-in features and limitations of this program.
When you want to pause DragonPad² you can either press "pause" or f4, or on the menubar, select actions>stoptimedcutnpaste. There will be a brief pause, and then everything you have dictated to it will display in the edit field. To re-send it, re-start timed cutnpaste again. To clear it, press f5, or reload the script.
Train Dragon for a few words. Replace the words in the commandlist, add the desired commands in the gosub section, and test them. Standard AHK syntax rules here.
Problems/bugs:
* The word count includes spaces right now. I aim to fix this soon. Does not affect basic functioning in any way.
* Basically, DragonPad² was designed for being dictated to with Dragon, and so if you manually enter text, you may see some spurious results. Dragon sends words as whole words, so when dictating the timed cutnpaste will not send incomplete words -- not so for typing and timed cutnpaste. A simple solution if you are typing into it for some reason, like testing, is to use the cutnpaste that is not timed, when you are done typing. And several things you would normally type need to be sent in the form of commands instead.
* DragonPad2 will not pass through the symbols {,},^,+,#,!, and probably one or two others I've forgotten, as they are AHK code symbols and AHK reads them as such. The workaround for this was more extensive than I wanted to undertake so far. A number of simple workarounds are available but I didn't want to clutter up the demo version any worse than it is already.
* At present, DragonPad² is not good at reading and sending carriage returns to the target program, and if you have a carriage return before a command, the command may get passed as text instead or may not get executed. I don't anticipate dictating carriage returns, and so I didn't design it for that. The solution is to create a carriage return command for DragonPad² to execute a carriage return
in the word processor that you are sending to, rather than in DragonPad² itself. That is to say, do not dictate "New Line" to DragonPad² but rather dictate some made-up word like "dookie" and create an entry in the commandlist, and create a command that looks like:
Code:
dookie:
Controlsend,Edit1,`n *Now we are on a new line*,deleme.txt - Notepad
Return
* Due to the current typing rate of my keyboard, I have been forced to use a setkeydelay setting of 1,1 which is pretty slow. At the default setting, there are errors and bad capitalizations. In all likelihood this will never be an issue when dictating, even at the setting of 1,1, because it's pretty rare that you will dictate that fast for any duration. And DragonPad² does keep it all in a buffer, so any lag in transmission between DragonPad² and your target word processor is not lost, even if you don't see it right away.
;-----------------------------------------------------
The overall purpose of this program is to extend the potential of Dragon Naturally Speaking, to dictate with DNS at a higher speed. and to provide an alternative way of sending commands, including "text commands" without the 1/2-second pause you always get with Dragon while it executes a command. (Or at least you do with the Preferred version. I can't speak to the "Pro" version.) And of course, like Dragon's own DragonPad, another important use of this program is to allow one to dictate freely to programs that are not "select and say compliant," which is pretty much anything but Windows native applications and WordPerfect, and Mozilla. Using this program, for instance, I can now dictate to my favorite text editor, Textpad. I could not before.
Todo: Fix the word count
Enable an accurate wpm counter
Rewrite the cutnpaste and timedcutnpaste so they do not cut text from the edit field, but rather read the last words entered. This is important.
Code:
#Persistent
settimer, update_clock, 50
;return
; Grier = 1
Commandlist = @0,@1,@2,@3,@4,@5,@6
Wordcount = 0
; DragonPad2 -- FREEWARE by ribbet.1 and many others
; who have taught me or provided code I've lifted from,
; most especially Chris and SKAN!
; You are free to distribute this script, modify or compile it, and MAY NOT CHARGE MONEY FOR IT!
; A minor note of apology for my use of religious terminology for my variables. I am very much in love with the dieties of the Hindu pantheon, and that is why I used them. There is no offense intended.
; To add a new command you must type one in here.
; Some characters are illegal and must be escaped or left unused, such as comma, pipe, or colon.
; This program is initially based on the 'simple text editor with menu bar,' provided at the ahk website, nothing more.
; Create the sub-menus for the menu bar:
DateTimeStamp=20061103000000
Menu, FileMenu, Add, &New, FileNew
Menu, FileMenu, Add, &Open, FileOpen
Menu, FileMenu, Add, &Save, FileSave
Menu, FileMenu, Add, Save &As, FileSaveAs
Menu, FileMenu, Add ; Separator line.
Menu, FileMenu, Add, E&xit, FileExit
Menu, HelpMenu, Add, &About, HelpAbout
Menu, HelpMenu, Add, &Woids, Helpwords
Menu, ActionsMenu, Add, &TimedCutNpaste, TimedCutNpaste
Menu, ActionsMenu, Add, &STOPTimedCutNpaste -- F4, STOPTimedCutNpaste
Menu, ActionsMenu, Add, &SingleCutNpaste -- Ctrl-Shift-Win-v, SingleCutNpaste
;Menu, StopwatchMenu, Add, &StartStop, StartStop
;Menu, StopwatchMenu, Add, &PauseResume, PauseResume
Menu, MyMenuBar, Add, &File, :FileMenu
Menu, MyMenuBar, Add, &Help, :HelpMenu
Menu, MyMenuBar, Add, &Actions, :ActionsMenu
Menu, MyMenuBar, Add, &TimedCutNpaste, TimedCutNpaste
;Menu, MyMenuBar, Add, &Actions, :Actions
;Menu, StopwatchMenu, Add, &Stopwatch, StartStopwatch
;Menu, MyMenuBar, Add, &Stopwatch, StartStopwatcher
;Menu, StopwatchMenu, Add, &Reset, Reset
; Attach the menu bar to the window:
Gui, Menu, MyMenuBar
; Create the main Edit control and display the window:
Gui, +Resize -MaximizeBox ; Make the window resizable.
;Gui, Add, Tab2,w600 h80,Main||Non-Main
Gui, Add,Edit,vMainEdit WantTab x10 y28 w600 h80
Gui, Add, Button, x326 y4 w50 h20 vStartStop gStartStop, Start
Gui, Add, Button, x376 y4 w50 h20 vPauseResume gPauseResume, Pause
Gui, Add, Button, x426 y4 w50 h20 vReset gReset, Reset
Gui, Add, Text, x508 y8 w50 h20 +Center, 00:00:00
Gui, Add, Text, x556 y8 w50 h20 +Center, 00:00:00
Gui, Add, Text, x256 y8 w90 h20, 0 Words
Gui, Font, S12 CDefault, Verdana
CurrentFiln = ; Indicate that there is no current file.
Gui,Tab,2
;Gui, Add,Edit,vMainEdit2 WantTab x10 y28 w600 h80
Gui, Show,, DragonPad²
;return
;-----------------------------------------------------
; This simply creates a text editor to for DragonPad² to send text to. You will probably want to replace it with your favorite text editor, such as Word, WP, Textpad, whatever floats your boat.
Fileappend, Created %A_MM%-%A_DD%-%A_Hour%-%A_Min%,deleme.txt
Sleep,500
Run, Notepad.exe deleme.txt
FileSelectFile,CurrentFiln
;-----------------------------------------------------
; This creates a textfile that all strings are sent to, as sort of a backup. In the event DragonPad² has a problem, you can still have this, and in fact you can paste it into DragonPad² and send it to your text editor again.
If CurrentFiln =
{
CurrentFiln = %A_MM%-%A_DD%-%A_Hour%-%A_Min%.txt
Fileappend, Created %A_MM%-%A_DD%-%A_Hour%-%A_Min%`n,%CurrentFiln%
MsgBox,The literal textstrings are being saved to `n%A_Workingdir%\%CurrentFiln%`n
FullCurFiln = %A_Workingdir%\%CurrentFiln%
MsgBox,%FullCurFiln%
WinActivate,DragonPad²
Return
}
Else
MsgBox,%CurrentFiln%
WinActivate,DragonPad²
Return
;-----------------------------------------------------
FileNew:
GuiControl,, MainEdit ; Clear the Edit control.
return
;-----------------------------------------------------
FileOpen:
Gui +OwnDialogs ; Force the user to dismiss the FileSelectFile dialog before returning to the main window.
FileSelectFile, SelectedFileName, 3,, Open File, Text Documents (*.txt)
if SelectedFileName = ; No file selected.
return
Gosub FileRead
return
;-----------------------------------------------------
FileRead: ; Caller has set the variable SelectedFileName for us.
FileRead, MainEdit, %SelectedFileName% ; Read the file's contents into the variable.
if ErrorLevel
{
MsgBox Could not open "%SelectedFileName%".
return
}
GuiControl,, MainEdit, %MainEdit% ; Put the text into the control.
FullCurFiln = %SelectedFileName%
Gui, Show,, DragonPad² ; Show file name in title bar.
MsgBox,%FullCurFiln%
return
FileSave:
if FullCurFiln = ; No filename selected yet, so do Save-As instead.
Goto FileSaveAs
Gosub SaveCurrentFile
return
;-----------------------------------------------------
FileSaveAs:
Gui +OwnDialogs ; Force the user to dismiss the FileSelectFile dialog before returning to the main window.
FileSelectFile, SelectedFileName, S16,, Save File, Text Documents (*.txt)
if SelectedFileName = ; No file selected.
return
FullCurFiln = %SelectedFileName%
Gosub SaveCurrentFile
return
;-----------------------------------------------------
SaveCurrentFile: ; Caller has ensured that CurrentFiln is not blank.
IfExist %FullCurFiln%
{
FileDelete %FullCurFiln%
if ErrorLevel
{
MsgBox The attempt to overwrite "%FullCurFiln%" failed.
return
}
}
GuiControlGet, MainEdit ; Retrieve the contents of the Edit control.
FileAppend, %MainEdit%, %FullCurFiln% ; Save the contents to the file.
Gui, Show,, DragonPad²
MsgBox,%FullCurFiln%
return
;-----------------------------------------------------
HelpAbout:
Gui, 2:+owner1 ; Make the main window (Gui #1) the owner of the "about box" (Gui #2).
Gui +Disabled ; Disable main window.
Gui, 2:Add, Text,, Text for about box.
Gui, 2:Add, Button, Default, OK
Gui, 2:Show
return
;-----------------------------------------------------
Helpwords: ;This is a simple textbox I manually add my words from my commandlist into for fast reference.
^#!f1::
Msgbox,Commandlist = @1,@2,@3,@4,@5,@6,
Return
;-----------------------------------------------------
2ButtonOK: ; This section is used by the "about box" above.
2GuiClose:
2GuiEscape:
Gui, 1:-Disabled ; Re-enable the main window (must be done prior to the next step).
Gui Destroy ; Destroy the about box.
return
;-----------------------------------------------------
GuiDropFiles: ; Support drag & drop.
Loop, parse, A_GuiEvent, `n
{
SelectedFileName = %A_LoopField% ; Get the first file only (in case there's more than one).
break
}
Gosub FileRead
return
;-----------------------------------------------------
GuiSize:
if ErrorLevel = 1 ; The window has been minimized. No action needed.
return
; Otherwise, the window has been resized or maximized. Resize the Edit control to match.
NewWidth := A_GuiWidth - 20
NewHeight := A_GuiHeight - 34
Button1posw := A_GuiWidth - 295
Button2posw := A_GuiWidth - 245
Button3posw := A_GuiWidth - 195
Static1posw := A_GuiWidth - 133
Static2posw := A_GuiWidth - 85
Static3posw := A_GuiWidth - 385
GuiControl, Move, MainEdit, W%NewWidth% H%NewHeight%
GuiControl, Move, MainEdit2, W%NewWidth% H%NewHeight%
GuiControl, Move, SysTabControl321, W%NewWidth% H%NewHeight%
;GuiControl, Move, Tab 2, W%NewWidth% H%NewHeight%
GuiControl, Move, Button1, x%Button1posw% y4
GuiControl, Move, Button2, x%Button2posw% y4
GuiControl, Move, Button3, x%Button3posw% y4
GuiControl, Move, Static1, x%Static1posw% y8
GuiControl, Move, Static2, x%Static2posw% y8
GuiControl, Move, Static3, x%Static3posw% y8
return
;-----------------------------------------------------
FileExit: ; User chose "Exit" from the File menu.
GuiClose: ; User closed the window.
ExitApp
;-----------------------------------------------------
^+#d:: ;;Activate DragonPad²
WinActivate,DragonPad²
Return
;-----------------------------------------------------
pause::pause
;-----------------------------------------------------
STOPTimedCutNpaste:
If stop = 1
stop = 0
Else
stop = 1
ControlSetText,Edit1,%Vishnu%,DragonPad²
return
;-----------------------------------------------------
SingleCutNpaste:
^!#v:: ;;Single instance CutNPaste -- not timed that is :)
Gosub,CutNPaste
Return
;-----------------------------------------------------
^+#Backspace:: ;;Exit
ExitApp
Return
;-----------------------------------------------------
^+#5::
Winactivate,WordPerfect
Winactivate,DragonPad²
Return
;-----------------------------------------------------
CutNPaste:
^#!b:: ;;CutnPaste Single Instance
ControlSend,Edit1,^{end},deleme.txt - Notepad
SetKeyDelay, 1, 0
Clipboard =
Winactivate,DragonPad²
ControlSend,Edit1,^a,DragonPad²
ControlSend,Edit1,^x,DragonPad²
;MsgBox,Clipboard = %Clipboard%
FileAppend `n*%timez%*%ntime%* -- %A_Space%%Clipboard%,Testy.txt
StringReplace,Clipboard,Clipboard,`n`n,`n,all
StringReplace,Clipboard,Clipboard,%A_Space%%A_Space%,%A_Space%,all
Loop,Parse,Clipboard,%A_Space%
{
Kali = %A_Loopfield%
;MsgBox,Kali = %Kali%
If Kali in %Commandlist%
{
;MsgBox, %Kali%, is in Commandlist
Grier++
FileAppend, `n|%Grier%|%timez%%ntime% -- %A_Space%%Kali%,%FullCurFiln%
SetKeyDelay,1,1
Gosub, %Kali%
}
Else
ControlSend,Edit1,%Kali%%A_Space%,deleme.txt - Notepad
;This is the word processor you intend to send text to. In this case it's WordPerfect.
Durga = %A_Index%
}
Wordcount+=%Durga%
GuiControlGet, Static3
If ( Static3 <> Wordcount ) ; Update the control only when needed
GuiControl,, Static3, %Wordcount% words ; this avoids flicker
;SetKeyDelay -1,-1
Return
;-----------------------------------------------------
;-----------------------------------------------------
; This is where the commands go. There have to be entries in the commandlist for these to work.
@1:
;MsgBox, Command = @1
ControlSend,Edit1,^{end} `n{Tab}|%Grier%| {Tab} This is some example text. Please note that the number between the pipes will match the corresponding entry in the backup textfile. That number is associated with the variable grier and is incremented with every successful cutnpaste. This can be very useful. To see what it does try doing all of these demo commands and then opening up the backup textfile which would be %FullCurFiln%.deleme.txt.,deleme.txt - Notepad
Return
@2:
;MsgBox, Command = @2
ControlSend,Edit1,^{end} `n{Tab}|%Grier%| {Tab} *%nTime%*%timez%* {Tab} This is a time-stamped example text. If you didn't start the timer`, you will only see a single time and if you start the timer you will see two. HINT -- You start the timer by pressing the Start button. :){Space}{Space},deleme.txt - Notepad
Return
@3:
;MsgBox, Command = @3
SetKeyDelay, -1, -1
ControlSend,Edit1,^{end} `n{Tab}|%Grier%|{Tab}{f5} -- This is example text being sent to Notepad using the setkeydelay command to speed up input. In my experience so far this can result in errors such as the wrong letters being capitalized etc. If you see no errors in this text`, you may be want to experiment with using the -1`,-1 setting. Otherwise you may have to keep it as I set it`, at 1`,1., deleme.txt - Notepad
SetKeyDelay, 1,1
Return
@4:
;MsgBox, Command = @4
WinActivate, deleme.txt - Notepad
SendInput,^{end} `n{Tab}|%Grier%|{Tab}And this method sends text much faster but it also does not send it in the background.
WinActivate,DragonPad²
Return
@5:
;MsgBox, Command = @5
Blockinput, On
WinActivate, deleme.txt - Notepad
SendInput,^{end} `n{Tab}|%Grier%|{tab}And this is the same method protecting the function with Blockinput. I have not experimented with using Dragon at the same time as this. You cannot use the mouse/keyboard while blockinput is on`, and I doubt you can use Dragon either`, but as I said I have not tried yet.
BlockInput, Off
WinActivate,DragonPad²
Return
@6:
;MsgBox, Command = @6
ControlSend,Edit1,^{end} `n{Tab}|%Grier%|{tab}*%nTime%*%timez%* And this should open up your backup textfile. You will see that it resembles a logfile`, and logs commands sent as their command names rather than the resulting text., deleme.txt - Notepad
Run, Notepad.exe %FullCurFiln%
Return
;=== The killswitch shortcut (Ctrl-Alt-Backspace)
^!Backspace::Reload
;---------------------------------------------------
StartStop:
GuiControlGet, StartStop
If ( StartStop = "Start" )
{
GuiControl,, StartStop, Stop
SetTimer, Count,990
}
Else
{
GuiControl,, StartStop, Start
SetTimer, Count, Off
GuiControl,, PauseResume, Pause
DateTimeStamp = 20061103000000
}
Return
PauseResume:
GuiControlGet, StartStop
If ( StartStop = "Start" )
Return
GuiControlGet, PauseResume
If ( PauseResume = "Pause" )
{
GuiControl,, PauseResume, Resume
SetTimer, Count, OFF
}
Else
{
GuiControl,, PauseResume, Pause
SetTimer, Count, 990
}
Return
Reset:
GuiControl,, Static1, 00:00:00
DateTimeStamp = 20061103000000
Return
Count:
DateTimeStamp += 1, Seconds
FormatTime, nTime, %DateTimeStamp%, HH:mm:ss
GuiControlGet, Static1
If ( Static1 <> nTime ) ; Update the control only when needed
GuiControl,, Static1, %nTime% ; this avoids flicker
Return
update_clock:
FormatTime, timez,, HH:mm:ss
ControlSetText, Static2,%timez%,DragonPad²
Return
; The updateclock function is courtesy of SKAN -- ONCE AGAIN!
;-----------------------------------------------------
rctrl & numpad1::
MsgBox,Make Sure Dragon is in Dictation Mode.`nTurn on the recording.`nStart the timer.
Send, ^{f12}
WinActivate, deleme.txt - Notepad
WinActivate, DragonPad²
Return
rctrl & numpad2::
WinActivate, deleme.txt - Notepad
WinActivate, DragonPad²
Return
;-----------------------------------------------------
; OK, this new version of timed cutnpaste is working. Gotta test it further with Dragon.
TIMEDCUTNPASTE:
rctrl & numpad0:: ;;Init timed CutNPaste
ControlSend,Edit1,^{end},deleme.txt - Notepad
stop = 0
WinActivate, deleme.txt - Notepad
Winactivate, DragonPad²
SetKeyDelay, 1, 1
Loop
{ ;111
Winactivate,DragonPad²
if stop = 1
break
else
Lakshmi =
Loop
{ ;222
if stop = 1
break
else
ControlGetText,Lakshmi,Edit1,DragonPad²
If Lakshmi =
Sleep, 250
else
break
} ;222
ControlSetText,Edit1,,DragonPad²
Krsna := jaganath . " " . Lakshmi
Vishnu := Krsna
;MsgBox,Lakshmi = %Lakshmi%
FileAppend `n|%grier%| {tab} *%timez%*%ntime%* -- %A_Space%%Lakshmi%,%FullCurFiln%
StringReplace,Lakshmi,Lakshmi,`n`n,`n,all
StringReplace,Lakshmi,Lakshmi,%A_Space%%A_Space%,%A_Space%,all
Loop,Parse,Lakshmi,%A_Space%,%A_Space%
{ ;333
Kali = %A_Loopfield%
;MsgBox,Kali = %Kali%
If Kali in %Commandlist%
{ ;444
Grier++
FileAppend, `n|%Grier%|*%timez%*%ntime%* -- %A_Space%%Kali%,%FullCurFiln%
Sleep,50
Gosub, %Kali%
} ;444
Else
ControlSend,Edit1,%Kali%%A_Space%,deleme.txt - Notepad
;This is the word processor you intend to send text to. In this case it's Notepad.
Durga = %A_Index%
} ;333
Wordcount+=%Durga%
GuiControlGet, Static3
If ( Static3 <> Wordcount ) ; Update the control only when needed
GuiControl,, Static3, %Wordcount% words ; this avoids flicker
Sleep, 2000
jaganath := Krsna
If stop = 1
Break
} ;111
ControlSetText,Edit1,%Vishnu%,DragonPad²
ControlSend,Edit1,^{end},DragonPad²
Return
F4::
stop = 1
F5::
ControlSetText,Edit1,,DragonPad²
Vishnu =
Enderz:
;ControlSetText,Edit1,%Vishnu%,DragonPad²
ControlSend,Edit1,^{end},DragonPad²
return