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 ///////////////////////////////////////////////////////////////////////////////
51 #define KEYEVENT InputRecord[i].Event.KeyEvent
53 // Paul Brannan 6/25/98
55 // #define KEYEVENT_CHAR KEYEVENT.AsciiChar
57 #define KEYEVENT_CHAR KEYEVENT.uChar.AsciiChar
60 #define KEYEVENT_PCHAR &KEYEVENT_CHAR
62 // This is for local echo (Paul Brannan 5/16/98)
63 inline void DoEcho(const char *p
, int l
, TConsole
&Console
,
64 TNetwork
&Network
, NetParams
*pParams
) {
65 // Pause the console (Paul Brannan 8/24/98)
66 if(Network
.get_local_echo()) {
67 ResetEvent(pParams
->hUnPause
);
68 SetEvent(pParams
->hPause
);
69 while (!*pParams
->bNetPaused
); // Pause
71 Console
.WriteCtrlString(p
, l
);
73 SetEvent(pParams
->hUnPause
); // Unpause
77 // This is for line mode (Paul Brannan 12/31/98)
78 static char buffer
[1024];
79 static unsigned int bufptr
= 0;
81 // Line mode -- currently uses sga/echo to determine when to enter line mode
82 // (as in RFC 858), but correct behaviour is as described in RFC 1184.
83 // (Paul Brannan 12/31/98)
84 // FIX ME!! What to do with unflushed data when we change from line mode
86 inline bool DoLineModeSpecial(char keychar
, TConsole
&Console
, TNetwork
&Network
,
88 if(keychar
== VK_BACK
) {
90 DoEcho("\b \b", 3, Console
, Network
, pParams
);
92 } else if(keychar
== VK_RETURN
) {
93 Network
.WriteString(buffer
, bufptr
);
94 Network
.WriteString("\012", 1);
95 DoEcho("\r\n", 2, Console
, Network
, pParams
);
102 inline void DoLineMode(const char *p
, int p_len
, TConsole
&Console
,
104 if(Network
.get_line_mode()) {
105 if(bufptr
< sizeof(buffer
) + p_len
- 1) {
106 memcpy(buffer
+ bufptr
, p
, p_len
);
112 Network
.WriteString(p
, p_len
);
116 // Paul Brannan 5/27/98
117 // Fixed this code for use with appliation cursor keys
118 // This should probably be optimized; it's pretty ugly as it is
119 // Rewrite #1: now uses ClosestStateKey (Paul Brannan 12/9/98)
120 const char *ClosestStateKey(WORD keyCode
, DWORD keyState
,
121 KeyTranslator
&KeyTrans
) {
124 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
))) return p
;
126 // Check numlock and scroll lock (Paul Brannan 9/23/98)
127 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~NUMLOCK_ON
))) return p
;
128 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~ENHANCED_KEY
129 & ~NUMLOCK_ON
))) return p
;
130 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~SCROLLLOCK_ON
))) return p
;
131 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~ENHANCED_KEY
132 & ~SCROLLLOCK_ON
))) return p
;
134 // John Ioannou (roryt@hol.gr)
135 // Athens 31/03/97 00:25am GMT+2
136 // fix for win95 CAPSLOCK bug
137 // first check if the user has keys with capslock and then we filter it
138 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~ENHANCED_KEY
))) return p
;
139 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~CAPSLOCK_ON
))) return p
;
140 if((p
= KeyTrans
.TranslateKey(keyCode
, keyState
& ~ENHANCED_KEY
141 & ~CAPSLOCK_ON
))) return p
;
143 return 0; // we couldn't find a suitable key translation
146 const char *FindClosestKey(WORD keyCode
, DWORD keyState
,
147 KeyTranslator
&KeyTrans
) {
150 // Paul Brannan 7/20/98
151 if(ini
.get_alt_erase()) {
152 if(keyCode
== VK_BACK
) {
154 keyState
|= ENHANCED_KEY
;
155 } else if(keyCode
== VK_DELETE
&& (keyState
& ENHANCED_KEY
)) {
157 keyState
&= ~ENHANCED_KEY
;
161 DWORD ext_mode
= KeyTrans
.get_ext_mode();
163 // Not as fast as an unrolled loop, but certainly more
164 // compact (Paul Brannan 12/9/98)
165 for(DWORD j
= ext_mode
; j
>= APP_KEY
; j
-= APP_KEY
) {
166 if((j
| ext_mode
) == ext_mode
) {
167 if((p
= ClosestStateKey(keyCode
, keyState
| j
,
168 KeyTrans
))) return p
;
172 return ClosestStateKey(keyCode
, keyState
, KeyTrans
);
175 // Paul Brannan Feb. 22, 1999
176 int do_op(tn_ops op
, TNetwork
&Network
, Tnclip
&Clipboard
) {
185 if(ini
.get_keyboard_paste()) Clipboard
.Paste();
189 Network
.WriteString("", 1);
192 Network
.WriteString("\r", 2); // CR must be followed by NUL
195 Network
.WriteString("\r\n", 2);
201 int telProcessConsole(NetParams
*pParams
, KeyTranslator
&KeyTrans
,
202 TConsole
&Console
, TNetwork
&Network
, TMouse
&Mouse
,
203 Tnclip
&Clipboard
, HANDLE hThread
)
205 KeyDefType_const keydef
;
210 HANDLE hConsole
= GetStdHandle(STD_INPUT_HANDLE
);
212 SetConsoleMode(hConsole
, ini
.get_enable_mouse() ? ENABLE_MOUSE_INPUT
: 0);
214 const DWORD nHandle
= 2;
215 HANDLE hHandle
[nHandle
] = {hConsole
, pParams
->hExit
};
219 switch (WaitForMultipleObjects(nHandle
, hHandle
, FALSE
, INFINITE
)) {
220 case WAIT_OBJECT_0
: {
222 // Paul Brannan 7/29/98
223 if(ini
.get_input_redir()) {
224 char InputBuffer
[10];
226 // Correction from Joe Manns <joe.manns@ardenenginneers.com>
227 // to fix race conditions (4/13/99)
229 bResult
= ReadFile(hConsole
, InputBuffer
, 10, &dwInput
, 0);
230 if(bResult
&& dwInput
== 0) return TNNOCON
;
232 // no key translation for redirected input
233 Network
.WriteString(InputBuffer
, dwInput
);
237 INPUT_RECORD InputRecord
[11];
238 if (!ReadConsoleInput(hConsole
, &InputRecord
[0], 10, &dwInput
))
241 for (i
= 0; (unsigned)i
< dwInput
; i
++){
242 switch (InputRecord
[i
].EventType
) {
244 if (KEYEVENT
.bKeyDown
) {
246 WORD keyCode
= KEYEVENT
.wVirtualKeyCode
;
247 DWORD keyState
= KEYEVENT
.dwControlKeyState
;
249 // Paul Brannan 5/27/98
250 // Moved the code that was here to FindClosestKey()
251 keydef
.szKeyDef
= FindClosestKey(keyCode
,
254 if(keydef
.szKeyDef
) {
255 if(!keydef
.op
->sendstr
)
256 if((opval
= do_op(keydef
.op
->the_op
, Network
,
261 if(Network
.get_line_mode()) {
262 if(DoLineModeSpecial(KEYEVENT_CHAR
, Console
, Network
, pParams
))
267 if (p
== NULL
) { // if we don't have a translator
268 if(!KEYEVENT_CHAR
) continue;
275 // Local echo (Paul Brannan 5/16/98)
276 DoEcho(p
, p_len
, Console
, Network
, pParams
);
277 // Line mode (Paul Brannan 12/31/98)
278 DoLineMode(p
, p_len
, Console
, Network
);
284 if(!InputRecord
[i
].Event
.MouseEvent
.dwEventFlags
) {
285 ResetEvent(pParams
->hUnPause
);
286 SetEvent(pParams
->hPause
);
287 while (!*pParams
->bNetPaused
); // thread paused
288 // SuspendThread(hThread);
290 // Put the mouse's X and Y coords back into the
293 WriteConsoleInput(hConsole
, &InputRecord
[i
], 1,
298 SetEvent(pParams
->hUnPause
);
299 // ResumeThread(hThread);
305 case WINDOW_BUFFER_SIZE_EVENT
:
306 // FIX ME!! This should take care of the window re-sizing bug
307 // Unfortunately, it doesn't.
309 Network
.do_naws(Console
.GetWidth(), Console
.GetHeight());
313 } // keep going until no more input
323 HANDLE hConsole
= GetStdHandle(STD_INPUT_HANDLE
);
324 INPUT_RECORD InputRecord
;
329 WaitForSingleObject( hConsole
, INFINITE
);
330 if (!ReadConsoleInput(hConsole
, &InputRecord
, 1, &dwInput
)){
334 if (InputRecord
.EventType
== KEY_EVENT
&&
335 InputRecord
.Event
.KeyEvent
.bKeyDown
) {
336 // Why not just return the key code? (Paul Brannan 12/5/98)
337 return InputRecord
.Event
.KeyEvent
.wVirtualKeyCode
;
338 } else if(InputRecord
.EventType
== MOUSE_EVENT
) {
339 if(!InputRecord
.Event
.MouseEvent
.dwEventFlags
) {
340 // Put the mouse's X and Y coords back into the input buffer
341 WriteConsoleInput(hConsole
, &InputRecord
, 1, &dwInput
);
349 // FIX ME!! This is more evidence that tncon.cpp ought to have class structure
350 // (Paul Brannan 12/10/98)
352 // Bryan Montgomery 10/14/98
354 void setTNetwork(TNetwork tnet
) {
358 // Thomas Briggs 8/17/98
359 BOOL WINAPI
ControlEventHandler(DWORD event
) {
361 case CTRL_BREAK_EVENT
:
362 // Bryan Montgomery 10/14/98
363 if(ini
.get_control_break_as_c()) net
.WriteString("\x3",1);