1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998-2000 Paul Brannan
4 //Copyright (C) 1998 I.Ioannou
5 //Copyright (C) 1997 Brad Johnson
7 //This program is free software; you can redistribute it and/or
8 //modify it under the terms of the GNU General Public License
9 //as published by the Free Software Foundation; either version 2
10 //of the License, or (at your option) any later version.
12 //This program is distributed in the hope that it will be useful,
13 //but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 //GNU General Public License for more details.
17 //You should have received a copy of the GNU General Public License
18 //along with this program; if not, write to the Free Software
19 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 ///////////////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////////////////
30 // Contents: telnet console processing
34 // Revisions: August 30, 1998 Paul Brannan <pbranna@clemson.edu>
35 // July 29, 1998 Paul Brannan
36 // June 15, 1998 Paul Brannan
37 // May 16, 1998 Paul Brannan
38 // 5.April.1997 jbj@nounname.com
39 // 9.Dec.1996 jbj@nounname.com
42 // 02.Apr.1995 igor.milavec@uni-lj.si
45 ///////////////////////////////////////////////////////////////////////////////
49 #define KEYEVENT InputRecord[i].Event.KeyEvent
51 // Paul Brannan 6/25/98
53 // #define KEYEVENT_CHAR KEYEVENT.AsciiChar
55 #define KEYEVENT_CHAR KEYEVENT.uChar.AsciiChar
58 #define KEYEVENT_PCHAR &KEYEVENT_CHAR
60 // This is for local echo (Paul Brannan 5/16/98)
61 inline void DoEcho(const char *p
, int l
, TConsole
&Console
,
62 TNetwork
&Network
, NetParams
*pParams
) {
63 // Pause the console (Paul Brannan 8/24/98)
64 if(Network
.get_local_echo()) {
65 ResetEvent(pParams
->hUnPause
);
66 SetEvent(pParams
->hPause
);
67 while (!*pParams
->bNetPaused
); // Pause
69 Console
.WriteCtrlString(p
, l
);
71 SetEvent(pParams
->hUnPause
); // Unpause
75 // This is for line mode (Paul Brannan 12/31/98)
76 static char buffer
[1024];
77 static unsigned int bufptr
= 0;
79 // Line mode -- currently uses sga/echo to determine when to enter line mode
80 // (as in RFC 858), but correct behaviour is as described in RFC 1184.
81 // (Paul Brannan 12/31/98)
82 // FIX ME!! What to do with unflushed data when we change from line mode
84 inline bool DoLineModeSpecial(char keychar
, TConsole
&Console
, TNetwork
&Network
,
86 if(keychar
== VK_BACK
) {
88 DoEcho("\b \b", 3, Console
, Network
, pParams
);
90 } else if(keychar
== VK_RETURN
) {
91 Network
.WriteString(buffer
, bufptr
);
92 Network
.WriteString("\012", 1);
93 DoEcho("\r\n", 2, Console
, Network
, pParams
);
100 inline void DoLineMode(const char *p
, int p_len
, TConsole
&Console
,
102 if(Network
.get_line_mode()) {
103 if(bufptr
< sizeof(buffer
) + p_len
- 1) {
104 memcpy(buffer
+ bufptr
, p
, p_len
);
110 Network
.WriteString(p
, p_len
);
114 // Paul Brannan 5/27/98
115 // Fixed this code for use with appliation cursor keys
116 // This should probably be optimized; it's pretty ugly as it is
117 // Rewrite #1: now uses ClosestStateKey (Paul Brannan 12/9/98)
118 const char *ClosestStateKey(WORD keyCode
, DWORD keyState
,
119 KeyTranslator
&KeyTrans
) {
122 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
))) return p
;
124 // Check numlock and scroll lock (Paul Brannan 9/23/98)
125 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~NUMLOCK_ON
))) return p
;
126 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~ENHANCED_KEY
127 & ~NUMLOCK_ON
))) return p
;
128 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~SCROLLLOCK_ON
))) return p
;
129 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~ENHANCED_KEY
130 & ~SCROLLLOCK_ON
))) return p
;
132 // John Ioannou (roryt@hol.gr)
133 // Athens 31/03/97 00:25am GMT+2
134 // fix for win95 CAPSLOCK bug
135 // first check if the user has keys with capslock and then we filter it
136 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~ENHANCED_KEY
))) return p
;
137 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~CAPSLOCK_ON
))) return p
;
138 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~ENHANCED_KEY
139 & ~CAPSLOCK_ON
))) return p
;
141 return 0; // we couldn't find a suitable key translation
144 const char *FindClosestKey(WORD keyCode
, DWORD keyState
,
145 KeyTranslator
&KeyTrans
) {
148 // Paul Brannan 7/20/98
149 if(ini
.get_alt_erase()) {
150 if(keyCode
== VK_BACK
) {
152 keyState
|= ENHANCED_KEY
;
153 } else if(keyCode
== VK_DELETE
&& (keyState
& ENHANCED_KEY
)) {
155 keyState
&= ~ENHANCED_KEY
;
159 DWORD ext_mode
= KeyTrans
.get_ext_mode();
161 // Not as fast as an unrolled loop, but certainly more
162 // compact (Paul Brannan 12/9/98)
163 for(DWORD j
= ext_mode
; j
>= APP_KEY
; j
-= APP_KEY
) {
164 if((j
| ext_mode
) == ext_mode
) {
165 if((p
= ClosestStateKey(keyCode
, keyState
| j
,
166 KeyTrans
))) return p
;
170 return ClosestStateKey(keyCode
, keyState
, KeyTrans
);
173 // Paul Brannan Feb. 22, 1999
174 int do_op(tn_ops op
, TNetwork
&Network
, Tnclip
&Clipboard
) {
183 if(ini
.get_keyboard_paste()) Clipboard
.Paste();
187 Network
.WriteString("", 1);
190 Network
.WriteString("\r", 2); // CR must be followed by NUL
193 Network
.WriteString("\r\n", 2);
199 int telProcessConsole(NetParams
*pParams
, KeyTranslator
&KeyTrans
,
200 TConsole
&Console
, TNetwork
&Network
, TMouse
&Mouse
,
201 Tnclip
&Clipboard
, HANDLE hThread
)
203 KeyDefType_const keydef
;
208 HANDLE hConsole
= GetStdHandle(STD_INPUT_HANDLE
);
210 SetConsoleMode(hConsole
, ini
.get_enable_mouse() ? ENABLE_MOUSE_INPUT
: 0);
212 const DWORD nHandle
= 2;
213 HANDLE hHandle
[nHandle
] = {hConsole
, pParams
->hExit
};
217 switch (WaitForMultipleObjects(nHandle
, hHandle
, FALSE
, INFINITE
)) {
218 case WAIT_OBJECT_0
: {
220 // Paul Brannan 7/29/98
221 if(ini
.get_input_redir()) {
222 char InputBuffer
[10];
224 // Correction from Joe Manns <joe.manns@ardenenginneers.com>
225 // to fix race conditions (4/13/99)
227 bResult
= ReadFile(hConsole
, InputBuffer
, 10, &dwInput
, 0);
228 if(bResult
&& dwInput
== 0) return TNNOCON
;
230 // no key translation for redirected input
231 Network
.WriteString(InputBuffer
, dwInput
);
235 INPUT_RECORD InputRecord
[11];
236 if (!ReadConsoleInput(hConsole
, &InputRecord
[0], 10, &dwInput
))
239 for (i
= 0; (unsigned)i
< dwInput
; i
++){
240 switch (InputRecord
[i
].EventType
) {
242 if (KEYEVENT
.bKeyDown
) {
244 WORD keyCode
= KEYEVENT
.wVirtualKeyCode
;
245 DWORD keyState
= KEYEVENT
.dwControlKeyState
;
247 // Paul Brannan 5/27/98
248 // Moved the code that was here to FindClosestKey()
249 keydef
.szKeyDef
= FindClosestKey(keyCode
,
252 if(keydef
.szKeyDef
) {
253 if(!keydef
.op
->sendstr
)
254 if((opval
= do_op(keydef
.op
->the_op
, Network
,
259 if(Network
.get_line_mode()) {
260 if(DoLineModeSpecial(KEYEVENT_CHAR
, Console
, Network
, pParams
))
265 if (p
== NULL
) { // if we don't have a translator
266 if(!KEYEVENT_CHAR
) continue;
273 // Local echo (Paul Brannan 5/16/98)
274 DoEcho(p
, p_len
, Console
, Network
, pParams
);
275 // Line mode (Paul Brannan 12/31/98)
276 DoLineMode(p
, p_len
, Console
, Network
);
282 if(!InputRecord
[i
].Event
.MouseEvent
.dwEventFlags
) {
283 ResetEvent(pParams
->hUnPause
);
284 SetEvent(pParams
->hPause
);
285 while (!*pParams
->bNetPaused
); // thread paused
286 // SuspendThread(hThread);
288 // Put the mouse's X and Y coords back into the
291 WriteConsoleInput(hConsole
, &InputRecord
[i
], 1,
296 SetEvent(pParams
->hUnPause
);
297 // ResumeThread(hThread);
303 case WINDOW_BUFFER_SIZE_EVENT
:
304 // FIX ME!! This should take care of the window re-sizing bug
305 // Unfortunately, it doesn't.
307 Network
.do_naws(Console
.GetWidth(), Console
.GetHeight());
311 } // keep going until no more input
321 HANDLE hConsole
= GetStdHandle(STD_INPUT_HANDLE
);
322 INPUT_RECORD InputRecord
;
327 WaitForSingleObject( hConsole
, INFINITE
);
328 if (!ReadConsoleInput(hConsole
, &InputRecord
, 1, &dwInput
)){
332 if (InputRecord
.EventType
== KEY_EVENT
&&
333 InputRecord
.Event
.KeyEvent
.bKeyDown
) {
334 // Why not just return the key code? (Paul Brannan 12/5/98)
335 return InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
;
336 } else if(InputRecord
.EventType
== MOUSE_EVENT
) {
337 if(!InputRecord
.Event
.MouseEvent
.dwEventFlags
) {
338 // Put the mouse's X and Y coords back into the input buffer
339 WriteConsoleInput(hConsole
, &InputRecord
, 1, &dwInput
);
347 // FIX ME!! This is more evidence that tncon.cpp ought to have class structure
348 // (Paul Brannan 12/10/98)
350 // Bryan Montgomery 10/14/98
352 void setTNetwork(TNetwork tnet
) {
356 // Thomas Briggs 8/17/98
357 BOOL WINAPI
ControlEventHandler(DWORD event
) {
359 case CTRL_BREAK_EVENT
:
360 // Bryan Montgomery 10/14/98
361 if(ini
.get_control_break_as_c()) net
.WriteString("\x3",1);