Difference between revisions of "API"
Line 80: | Line 80: | ||
| '''<tt>wtKeyer:GetCwSpeed()</tt>''' | | '''<tt>wtKeyer:GetCwSpeed()</tt>''' | ||
| Return the CW speed in wpm (return 0 in case of error). | | Return the CW speed in wpm (return 0 in case of error). | ||
+ | |- | ||
+ | | '''<tt>wtKeyer:GrabHighlightedCallsign()</tt>''' | ||
+ | | Works only in RTTY mode and grabs the currently highlighted callsign from the RX window. | ||
|- | |- | ||
| '''<tt>wtKeyer:Play(Message)</tt>''' | | '''<tt>wtKeyer:Play(Message)</tt>''' |
Revision as of 17:35, 1 November 2009
List of Win-Test API Functions
Compiled from information found on the WT reflector on October 7, 2009 ([1], [2])
Class wtApp
wtApp:AlertBox(Text) | Opens a standard Windows alert box with text. |
wtApp:CallScript(strScript) | Call a wts script (no extension required in strScript). Can return a number only (or nothing) |
wtApp:GetKeyState | Returns the modifers keys status when the function is called. |
wtApp:InputInteger(Prompt, Title, Default) | If Title or Prompt is empty, a default text is used |
wtApp:InputNumber(Prompt, Title, Default) | If Title or Prompt is empty, a default text is used |
wtApp:InputText(Prompt, Title, Default) | If Title or Prompt is empty, a default text is used |
wtApp:IsPostKeyProcess() | Return true if the current script is executed after the assigned key has been processed by WT, and false otherwise |
wtApp:MessageBox(Text, Type, Title) | Create a Message box. Return the button pressed to exit the message (can be ignored). |
wtApp:SendAltKey(Key) | Key is a letter, a number, or a function key ("F1".."F12" + "Insert" + "Plus" + "Esc") |
wtApp:SendCtrlKey(Key) | Key is a letter, a number, or a function key ("F1".."F12" + "Insert" + "Plus" + "Esc") |
wtApp:SendFKey(Key) | Send Functions keys (and Insert and Plus). Key is one of "F1".."F12" + "Insert" + "Plus" + "Esc". Modifier Keys (optional) indicates the modifier keys (Ctrl = 4, Alt = 2, Shift = 1, None = 0 - Can be combined). If this argument is missing or -1, the current modifiers keys are used. |
wtApp:SendKeyCode(Code [, Modifier Keys]) | Send a key by its ASCII code. Keycode is an ASCII code. Modifier Keys (optional) indicates the modifier keys (Ctrl = 4, Alt = 2, Shift = 1, None = 0 - Can be combined). If this argument is missing or -1, the current modifiers keys are used |
wtApp:SetWindowColor(ChildWndId, nRed, nGreen, nBlue, nColorIndex) | Set the nColorIndex color of the child window designated by its windowID (see the wtConstants list). If ChildWndId is < 0, it applies to the main window. If nColorIndex is omitted (or set to 0), it applies to the background color All colors must be <= 255. |
wtApp:ShowWindow(ChildWndId) | Show the child window designated by its windowID (see the wtConstants list) |
wtApp:Sleep(Time) | Time expressed in milliseconds. |
wtApp:TextCommand(Text) | Send WT text command to application |
wtApp:ToggleWindow(ChildWndId) | Toggle the child window designated by its windowID (see the wtConstants list) |
wtApp:WizzWindow(ChildWndId) | Wizz the child window designated by its windowID (see the wtConstants list) |
Class wtContest
wtContest:IsExchangeRequired() | Return a boolean. True if the current contest requires an exchange (associated with RST) |
wtContest:GetContestId() | Return the current contestID |
Class wtKeyer
wtKeyer:GetCwSpeed() | Return the CW speed in wpm (return 0 in case of error). |
wtKeyer:GrabHighlightedCallsign() | Works only in RTTY mode and grabs the currently highlighted callsign from the RX window. |
wtKeyer:Play(Message) | Message is a plain string to be played, a saved message ($F1 etc.) or a variable ($xxx) |
wtKeyer:SetCwSpeed(Speed) | Set CW speed in wpm. |
wtKeyer:Stop() | Stop the current message |
Class wtOp
wtOp:GetCallsign() | Return the current op callsign |
wtOp:GetNick() | Return the current op nick |
Class wtQso
wtQso:IsCallsignEmpty() | Return a boolean : True if the callsign field of the active QSO is empty |
wtQso:IsCallsignIncomplete() | Return a boolean : True if the callsign field of the active QSO contains a "?" |
wtQso:IsExchangeEmpty() | Return a boolean : True if the exchange field of the active QSO is empty |
wtQso:IsExchangeSent() | Return a boolean : True if the exchangeSent flag of the active QSO is set |
wtQso:SetExchangeSent() | Set the exchangeSent flag of the active QSO (see wtQso::IsExchangeSent()) - Similar to the use of $SETEXCHSENT |
wtQso:ResetExchangeSent() | Reset the exchangeSent flag of the active QSO (see wtQso::IsExchangeSent()) - Similar to the use of $RSTEXCHSENT |
wtQso:ClearStatus() | Clear the status flags of the active QSO |
wtQso:GetModeId() | Return the mode ID of the active Qso |
wtQso:IsCallsignRepeated() | Return a boolean. True if the callsign hasn't changed since the last Enter |
wtQso:IsOperatingModeRun() | Return a boolean. True if the operating mode of the active QSO is RUN (and False if S&P) |
wtQso:IsModePhone() | Return a boolean. True if the mode of the active QSO is Phone (SSB and FM), and False otherwise |
wtQso:IsQsoApproved() | Return a boolean. True if all requested fields of the active QSO are filled (contest dependent) |
wtQso:IsDupe() | Return a boolean. True if the current callsign is a dupe |
wtQso:IsCurrentFieldCallsign() | Return a boolean : True if the current field is the callsign field |
wtQso:IsCurrentFieldExchange() | Return a boolean : True if the current field is an exchange field |
wtQso:IsCurrentFieldOther() | Return a boolean : True if the current field is not the callsign field or an exchange field |
wtQso:IsCurrentFieldEmpty() | Return a boolean : True if the current field is empty (except RST for the exchange field) |
wtQso:IsCurrentFieldPrimaryRadio() | Return a boolean : True if the current field is in the primary radio (main log) |
wtQso:IsCurrentFieldSecondryRadio() | Return a boolean : True if the current field is in the secondary radio |
Class wtRadio*
The following generic functions can by applied to: wtRadio (the active one), wtRadioInactive (the non-active one), wtRadioPrimary (the one that is in the main log wnd) wtRadioSecondary (the one that is in the secondary log wnd) wtRadio1 and wtRadio2.
WARNING: Some functions may not work because of the CAT protocol or radio hardware limitations.
wtRadio*GetFreq() | Return freq of the active VFO of the designated radio freq is expressed in kHz |
wtRadio*GetFreq(NVfo) | Return freq of the designated VFO (0 => VFO A, 1 => VFO B) of the designated radio freq is expressed in kHz |
wtRadio*GetFreqInactiveVfo() | Return freq of the inactive VFO of the designated radio freq is expressed in kHz |
wtRadio*SetFreq(freq) | Set freq of the active VFO of the designated radio freq is expressed in kHz |
wtRadio*SetFreq(freq, nVfo) | Set freq of the designated VFO (0 => VFO A, 1 => VFO B) of the designated radio freq is expressed in kHz |
wtRadio*SetFreqInactiveVfo(freq) | Set freq of the inactive VFO of the designated radio freq is expressed in kHz |
wtRadio*SetFreqSubVfo(freq) | Set freq of the sub VFO of the designated radio freq is expressed in kHz |
wtRadio*SetSplit(freq) | Set split ON and the split frequency on the designated radio freq is expressed in kHz |
wtRadio*ResetSplit() | Reset split on the designated radio |
wtRadio*IsSplit() | Return false or true whether the split is set or not on the designated radio |
wtRadio*GetRadioId() | Return the radioID (0 => RADIO_1, 1 => RADIO_2) of the designated radio |
wtRadio*Send(catString) | Send the ASCII catString to the designated radio |
wtRadio*SendHex(hexString) | Send the hexString to the designated radio. The hexString must contain only 0-9 and A-F characters and must have an even length. Ex "02DFA8" etc. |
Win-Test API Constants
Constants are not guaranteed to remain constant in Lua. The name of the constant could be accidentally reassigned to refer to some other object or value. Unfortunately, there is no easy way to generate code that prevents this. You will just have to be careful.
Child windows IDs
WT_WND_SUMMARY = 0; WT_WND_GRIDSQUAREMAP = 1; WT_WND_CHECKPARTIAL = 2; WT_WND_RATESHEET = 3; WT_WND_CLOCK = 4; WT_WND_VUMETER = 5; WT_WND_RATE = 6; WT_WND_GAB = 7; WT_WND_MAP = 8; WT_WND_CHECKCOUNTRY = 9; WT_WND_ZONE = 10; WT_WND_MULT = 11; WT_WND_NP1 = 12; WT_WND_RADIO1 = 13; WT_WND_RADIO2 = 14; WT_WND_PACKETCLUSTER = 15; WT_WND_DXCLUSTERANN = 16; WT_WND_SOLAR = 17; WT_WND_PILEUP = 18; WT_WND_STATUS = 19; WT_WND_SKED = 20; WT_WND_CHECKCALL = 21; WT_WND_SECONDARYRADIO = 22; WT_WND_RTTY1 = 23; WT_WND_RTTY2 = 24; WT_WND_QSYWIZARD = 25; WT_WND_EXTRAINFO = 26; WT_WND_ZONE2 = 27; WT_WND_ROTATORS = 28; WT_WND_CONTESTRECORDER = 29;
Supported contests IDs
WT_CONTEST_IARU_VHF = 1; WT_CONTEST_IARU_UHF = 2; WT_CONTEST_IARU_CW = 3; WT_CONTEST_IARU_HF = 4; WT_CONTEST_IARU_R1_50MHZ = 5; WT_CONTEST_REF_THF = 10; WT_CONTEST_REF_DDFM_50MHZ = 11; WT_CONTEST_THF_EU = 20; WT_CONTEST_THF_EU_50_70 = 21; WT_CONTEST_THF_EU_GRIDSQUARE = 30; WT_CONTEST_THF_EU_GRIDSQUARE_50_70 = 31; WT_CONTEST_THF_EU_GRIDSQUARE_NO_DIST = 32; WT_CONTEST_THF_EU_GRIDSQUARE_NO_DIST_50_70 = 33; WT_CONTEST_REF_HF = 100; WT_CONTEST_ARRL_DX = 101; WT_CONTEST_ARRL_10 = 102; WT_CONTEST_ARRL_160 = 103; WT_CONTEST_ARRL_SWEEPSTAKES = 104; WT_CONTEST_ARRL_FD = 105; WT_CONTEST_ARRL_RU = 106; WT_CONTEST_ARRL_UHF_AUG = 130; WT_CONTEST_ARRL_VHF_JAN = 131; WT_CONTEST_ARRL_VHF_JUN = 132; WT_CONTEST_ARRL_VHF_SEP = 133; WT_CONTEST_REF_160 = 150; WT_CONTEST_CQWW_DX = 200; WT_CONTEST_CQWW_WPX = 201; WT_CONTEST_CQWW_160 = 202; WT_CONTEST_CQWW_VHF = 250; WT_CONTEST_RDXC = 300; WT_CONTEST_RDAC = 301; WT_CONTEST_CIS = 302; WT_CONTEST_R_160 = 303; WT_CONTEST_RRTC = 304; WT_CONTEST_RAEM = 305; WT_CONTEST_DXPEDITION_HF = 400; WT_CONTEST_DXPEDITION_VHF = 410; WT_CONTEST_ALL_ASIAN = 500; WT_CONTEST_SPDXC = 600; WT_CONTEST_JIDX = 700; WT_CONTEST_KCJ = 701; WT_CONTEST_KCJ_TOPBAND = 702; WT_CONTEST_YUDXC = 800; WT_CONTEST_CQM = 900; WT_CONTEST_ARI = 1000; WT_CONTEST_ARI_SEZIONI = 1001; WT_CONTEST_ARI_40_80 = 1002; WT_CONTEST_BALTIC = 1100; WT_CONTEST_KING_OF_SPAIN = 1200; WT_CONTEST_IOTA = 1300; WT_CONTEST_RSGB_160 = 1301; WT_CONTEST_RSGB_80_CC = 1302; WT_CONTEST_RSGB_CMW = 1303; WT_CONTEST_RSGB_15_10 = 1304; WT_CONTEST_RSGB_AFS = 1305; WT_CONTEST_WAEDC = 1400; WT_CONTEST_WAG = 1401; WT_CONTEST_DARC_XMAS = 1402; WT_CONTEST_DARC_10 = 1403; WT_CONTEST_YODXC = 1500; WT_CONTEST_EU_HF = 1600; WT_CONTEST_SCC = 1601; WT_CONTEST_OCDXC = 1700; WT_CONTEST_TOECC = 1800; WT_CONTEST_SAC = 1900; WT_CONTEST_NRAU_BALTIC = 1901; WT_CONTEST_NAC = 1902; WT_CONTEST_SARTG = 1903; WT_CONTEST_QP_TX = 2000; WT_CONTEST_EU_SPRINT = 2100; WT_CONTEST_UKDXC = 2200; WT_CONTEST_OKOMDXC = 2300; WT_CONTEST_STEW_PERRY = 2400; WT_CONTEST_GACW_DX = 2401; WT_CONTEST_NINE_KCC_15 = 2402; WT_CONTEST_FOC_MARATHON = 2403; WT_CONTEST_LOTW = 2404; WT_CONTEST_AP_SPRINT = 2405; WT_CONTEST_JARTS = 2406; WT_CONTEST_MARCONI_HF = 2407; WT_CONTEST_LZDX = 2500; WT_CONTEST_CROATIAN_CW = 2600; WT_CONTEST_UBADX = 2700; WT_CONTEST_UBA_SPRING_80M = 2701; WT_CONTEST_UBA_SPRING_6M = 2702; WT_CONTEST_UBA_SPRING_2M = 2703; WT_CONTEST_ON_80M = 2704; WT_CONTEST_ON_6M = 2705; WT_CONTEST_ON_2M = 2706; WT_CONTEST_RAC_DAY = 2800; WT_CONTEST_RAC_WINTER = 2801; WT_CONTEST_PACC = 2900; WT_CONTEST_HELVETIA = 3000; WT_CONTEST_HELVETIA_VHF = 3001; WT_CONTEST_IARU_FD_R1_GENERIC = 3100; WT_CONTEST_IARU_FD_R1_DARC = 3101; WT_CONTEST_IARU_FD_R1_RSGB = 3102; WT_CONTEST_UFT_HF = 3200; WT_CONTEST_AGCW_HNY = 3300; WT_CONTEST_HA_DX = 3400; WT_CONTEST_NAQP = 3500; WT_CONTEST_NA_SPRINT = 3501; WT_CONTEST_NCCC_SPRINT = 3600; WT_CONTEST_CQIR = 3700;
Supported modes IDs
WT_MODE_CW = 0; WT_MODE_SSB = 1; WT_MODE_RTTY = 2; WT_MODE_FM = 3; WT_MODE_PSK = 4; WT_MODE_PKT = 5; WT_MODE_HELL = 6; WT_MODE_SAT = 7;
Supported status keys IDs
WT_KEY_SHIFT = 1; WT_KEY_ALT = 2; WT_KEY_CTRL = 4;
Radio Constants
WT_RADIO_MAX = 2; WT_RADIO_VFOA = 0; WT_RADIO_VFOB = 1; WT_RADIO_1 = 0; WT_RADIO_2 = 1;
Advanced Programming Examples
ESM Script (embedded into Win-Test)
For convenience, you can find below the current ESM embedded script. Note that the real returned values are somewhat different from the ones described above, because of the nature of this script (embedded), but it is a good source of inspiration for your own masterpiece. As Lua is an interpreted language, the good news is that you can edit your script while WT is running. No need to exit WT, enter modifications, and start WT again. Just edit esm.wts while WT is running, save it, and try it immediately!
-- v1.1 Dupes taken into account in the S&P mode -- v1.0 Initial version -- Send functions function sendCq() wtQso:ResetExchangeSent(); wtApp:SendFKey("F1"); -- Always use the function key end; function sendExchangeRun() if (wtQso:IsModePhone()) then wtApp:SendFKey("F2"); else wtKeyer:Play("$INSERT"); end; wtQso:SetExchangeSent(); end; function sendExchangeAgain() if (wtQso:IsModePhone()) then wtApp:SendFKey("F2"); else wtKeyer:Play("$F5 $F7"); -- $LOGGED ? end; end; function sendTu() if (wtQso:IsModePhone()) then wtApp:SendFKey("PLUS"); else wtKeyer:Play("$PLUS"); end; wtQso:ClearStatus(); end; function sendQuestionMark() wtQso:ResetExchangeSent(); if (wtQso:IsModePhone()) then wtApp:SendFKey("F7"); -- Again ? else wtKeyer:Play("$F7"); end; end; function sendMyCall() if (wtQso:IsModePhone()) then wtApp:SendFKey("F4"); -- My call else wtKeyer:Play("$F4"); end; end; function sendExchangeSAndP() if (wtQso:IsModePhone()) then wtApp:SendFKey("F2"); else wtKeyer:Play("$F2"); end; wtQso:SetExchangeSent(); end; -- ESM core code -- Return 0 (or return nothing) if we want the CR -- to be processed also by WT (ie log QSO) and -1 if not. if (wtQso:IsOperatingModeRun()) then -- Run if (wtContest:IsExchangeRequired()) then -- Usual contests if (wtQso:IsExchangeEmpty() or not wtQso:IsQsoApproved()) then if (wtQso:IsCallsignEmpty()) then sendCq(); else if (wtQso:IsCallsignRepeated()) then sendExchangeAgain(); else sendExchangeRun(); end; end; else if (wtQso:IsExchangeSent()) then sendTu() else sendExchangeRun(); end; end; else -- DXPed etc. if (not wtQso:IsQsoApproved()) then if (wtQso:IsCallsignEmpty()) then sendCq(); else if (wtQso:IsCallsignRepeated()) then sendExchangeAgain(); else sendExchangeRun(); end; end; else if (wtQso:IsExchangeSent()) then sendTu(); else sendExchangeRun(); end; end; end; else -- S&P : The automatic exchange fill (if enabled) is disabled by WT if ( (wtQso:IsExchangeEmpty() and wtContest:IsExchangeRequired()) or not wtQso:IsQsoApproved() ) then if (wtQso:IsCallsignEmpty()) then sendQuestionMark(); else if (not wtQso:IsDupe()) then -- Call only if not dupe sendMyCall(); end; end; else if (wtQso:IsExchangeSent()) then wtQso:ClearStatus(); return 1 -- Log it silently _Caution_ : embedded script returns 0 else if (not wtQso:IsDupe()) then -- Sent exchange only if not dupe sendExchangeSAndP(); end; end; end; end; return -1; -- This script overrides the Win-Test CR process
Alternative ESM Script (provided by F5VIH/SV3SJ)
At the top of the script you will find a variable setting:
shortcq = false;
Setting it to true, it will convert the CQ calling and the TU part of the QSO in short forms (a la 5b4agn) and the exact contents of the messages are defined in the two lines that follow the shortcq setting. I have also added the possibility to have an exchange filled in and no call (in that case the script sends CL?)
I must say I am very impressed by the functionality that WT opens to the users with lua scripts. I would really like to see more API calls made available and WT functions using scripts (programmable keys, even SO2R, etc).
In the mean time if you have suggestions to improve the script let me know. I can easily inlcude them.
----------------------------------- -- Wintest ESM - Nick, F5VIH/SV3SJ -- Set "shortCQ to true or false ----------------------------------- shortcq = false; shortCQ = "$MYCALL"; shortTU = "$CORRECT ++TU-- $CR"; -- Send functions function sendCq() wtQso:ResetExchangeSent(); if (wtQso:IsModePhone()) then wtApp:SendFKey("F1"); else if (shortcq) then wtKeyer:Play(shortCQ); else wtApp:SendFKey("F1"); -- Always use the function key end; end; end; function sendExchangeRun() if (wtQso:IsModePhone()) then wtApp:SendFKey("F2"); wtKeyer:Play("$CR"); else wtKeyer:Play("$INSERT"); end; wtQso:SetExchangeSent(); end; function sendExchangeAgain() if (wtQso:IsModePhone()) then wtApp:SendFKey("F2"); else wtKeyer:Play("$F5 $F7"); -- $LOGGED ? end; end; function sendTu() if (wtQso:IsModePhone()) then if (shortcq) then wtKeyer:Play("$CR"); wtApp:SendFKey("F5"); else wtApp:SendFKey("PLUS"); end; else if (shortcq) then wtKeyer:Play(shortTU); else wtKeyer:Play("$PLUS"); end; end; wtQso:ClearStatus(); end; function sendQuestionMark() wtQso:ResetExchangeSent(); if (wtQso:IsModePhone()) then wtApp:SendFKey("F7"); -- Again ? else wtKeyer:Play("$F7"); end; end; function sendMyCall() if (wtQso:IsModePhone()) then wtApp:SendFKey("F4"); -- My call else wtKeyer:Play("$F4"); end; end; function sendExchangeSAndP() -- Sends appropriate exchange when in S&P mode if (wtQso:IsModePhone()) then wtApp:SendFKey("F2"); -- 5NN EXCHANGE else wtKeyer:Play("$F2"); end; wtQso:SetExchangeSent(); end; function sendAskForCall() if (wtQso:IsModePhone()) then wtApp:SendFKey("F7"); -- AGN else wtKeyer:Play("CL?"); end; end; function askForNumber() if (wtQso:IsModePhone()) then wtApp:SendFKey("F6"); -- NR AGN else wtKeyer:Play("$F6"); end; end; function askWithPartialCall() if (wtQso:IsModePhone()) then wtApp:SendFKey("F7"); -- AGN else wtKeyer:Play("$F5 ?"); end; end; -- ESM core code -- Return 0 (or return nothing) if we want the CR -- to be processed also by WT (ie log QSO) and -1 if not. if (wtQso:IsOperatingModeRun()) then -- Run Mode if (wtContest:IsExchangeRequired()) then -- Usual contests requiring an exchange if (wtQso:IsCallsignEmpty()) then if (wtQso:IsExchangeEmpty()) then sendCq(); else -- we ve got an exchange but not a call, ask for the call sendAskForCall(); end; else -- call is not empty if (wtQso:IsExchangeSent()) then -- we have sent the exchage if (not wtQso:IsQsoApproved()) then if (wtQso:IsCurrentFieldCallsign() and not wtQso:IsExchangeEmpty()) then askWithPartialCall(); end; if (wtQso:IsCurrentFieldCallsign() and wtQso:IsExchangeEmpty()) then wtQso:ResetExchangeSent(); sendExchangeRun(); if (wtQso:IsCurrentFieldCallsign()) then wtKeyer:Play("$SPACEBAR") end; end; if (wtQso:IsCurrentFieldExchange() and wtQso:IsExchangeEmpty()) then askForNumber(); end; else -- qso has valid call and exchange if (wtQso:IsCurrentFieldExchange()) then sendTu(); else -- current field is not exchange (should be callsign) if (wtQso:IsCurrentFieldCallsign()) then wtQso:ResetExchangeSent(); sendExchangeRun(); if (wtQso:IsCurrentFieldCallsign()) then wtKeyer:Play("$SPACEBAR") end; end; end; end; else -- have not sent exchange and we are in the call field sendExchangeRun(); if (wtQso:IsCurrentFieldCallsign()) then wtKeyer:Play("$SPACEBAR") end; end; end; else -- The contest doesnt require an exchange to be received e.g. DXPed etc. if (not wtQso:IsQsoApproved()) then if (wtQso:IsCallsignEmpty()) then sendCq(); else if (wtQso:IsCallsignRepeated()) then sendExchangeAgain(); else sendExchangeRun(); end; end; else if (wtQso:IsExchangeSent()) then sendTu(); else sendExchangeRun(); end; end; end; else -- S&P : The automatic exchange fill (if enabled) is disabled by WT if ( (wtQso:IsExchangeEmpty() and wtContest:IsExchangeRequired()) or not wtQso:IsQsoApproved() ) then if (wtQso:IsCallsignEmpty()) then sendQuestionMark(); else if (not wtQso:IsDupe()) then -- Call only if not dupe sendMyCall(); end; end; else if (wtQso:IsExchangeSent()) then wtQso:ClearStatus(); wtKeyer:Play("$CR"); return -1; -- Log it silently else if (not wtQso:IsDupe()) then -- Sent exchange only if not dupe sendExchangeSAndP(); end; end; end; end; return -1; -- This script overrides the Win-Test CR process
Grab next call from partner window
The following script was kindly provided by Hank Lonberg, KR7X. It remaps the [~] key to grab the next callsign from the partner window and send an exchange.
wtKeyer:Play("$CORRECT TU $CR NOW $GRABPARTNER $NEXT $GUESSEXCH $F2 $13");
Re-map Ä key with /P for Field Day
Practical in Field Day where a lot of stations are signing "/P" - especially with a German keyboard layout.
-- add /P to a callsign for Field Day operations wtApp:SendKeyCode(47); wtApp:SendKeyCode(112);