Reactos
at master 366 lines 10 kB view raw
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 6// 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. 11// 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. 16// 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. 20// 21//I.Ioannou 22//roryt@hol.gr 23// 24/////////////////////////////////////////////////////////////////////////// 25 26/////////////////////////////////////////////////////////////////////////////// 27// 28// Module: tncon.cpp 29// 30// Contents: telnet console processing 31// 32// Product: telnet 33// 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 40// Version 2.0 41// 42// 02.Apr.1995 igor.milavec@uni-lj.si 43// Original code 44// 45/////////////////////////////////////////////////////////////////////////////// 46 47#include "precomp.h" 48 49#define KEYEVENT InputRecord[i].Event.KeyEvent 50 51// Paul Brannan 6/25/98 52// #ifdef __MINGW32__ 53// #define KEYEVENT_CHAR KEYEVENT.AsciiChar 54// #else 55#define KEYEVENT_CHAR KEYEVENT.uChar.AsciiChar 56// #endif 57 58#define KEYEVENT_PCHAR &KEYEVENT_CHAR 59 60// This is for local echo (Paul Brannan 5/16/98) 61inline 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 68 69 Console.WriteCtrlString(p, l); 70 71 SetEvent(pParams->hUnPause); // Unpause 72 } 73} 74 75// This is for line mode (Paul Brannan 12/31/98) 76static char buffer[1024]; 77static unsigned int bufptr = 0; 78 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 83// to character mode? 84inline bool DoLineModeSpecial(char keychar, TConsole &Console, TNetwork &Network, 85 NetParams *pParams) { 86 if(keychar == VK_BACK) { 87 if(bufptr) bufptr--; 88 DoEcho("\b \b", 3, Console, Network, pParams); 89 return true; 90 } else if(keychar == VK_RETURN) { 91 Network.WriteString(buffer, bufptr); 92 Network.WriteString("\012", 1); 93 DoEcho("\r\n", 2, Console, Network, pParams); 94 bufptr = 0; 95 return true; 96 } 97 return false; 98} 99 100inline void DoLineMode(const char *p, int p_len, TConsole &Console, 101 TNetwork &Network) { 102 if(Network.get_line_mode()) { 103 if(bufptr < sizeof(buffer) + p_len - 1) { 104 memcpy(buffer + bufptr, p, p_len); 105 bufptr += p_len; 106 } else { 107 Console.Beep(); 108 } 109 } else { 110 Network.WriteString(p, p_len); 111 } 112} 113 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) 118const char *ClosestStateKey(WORD keyCode, DWORD keyState, 119 KeyTranslator &KeyTrans) { 120 char const *p; 121 122 if((p = KeyTrans.TranslateKey(keyCode, keyState))) return p; 123 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; 131 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; 140 141 return 0; // we couldn't find a suitable key translation 142} 143 144const char *FindClosestKey(WORD keyCode, DWORD keyState, 145 KeyTranslator &KeyTrans) { 146 char const *p; 147 148 // Paul Brannan 7/20/98 149 if(ini.get_alt_erase()) { 150 if(keyCode == VK_BACK) { 151 keyCode = VK_DELETE; 152 keyState |= ENHANCED_KEY; 153 } else if(keyCode == VK_DELETE && (keyState & ENHANCED_KEY)) { 154 keyCode = VK_BACK; 155 keyState &= ~ENHANCED_KEY; 156 } 157 } 158 159 DWORD ext_mode = KeyTrans.get_ext_mode(); 160 if(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; 167 } 168 } 169 } 170 return ClosestStateKey(keyCode, keyState, KeyTrans); 171} 172 173// Paul Brannan Feb. 22, 1999 174int do_op(tn_ops op, TNetwork &Network, Tnclip &Clipboard) { 175 switch(op) { 176 case TN_ESCAPE: 177 return TNPROMPT; 178 case TN_SCROLLBACK: 179 return TNSCROLLBACK; 180 case TN_DIAL: 181 return TNSPAWN; 182 case TN_PASTE: 183 if(ini.get_keyboard_paste()) Clipboard.Paste(); 184 else return 0; 185 break; 186 case TN_NULL: 187 Network.WriteString("", 1); 188 return 0; 189 case TN_CR: 190 Network.WriteString("\r", 2); // CR must be followed by NUL 191 return 0; 192 case TN_CRLF: 193 Network.WriteString("\r\n", 2); 194 return 0; 195 } 196 return 0; 197} 198 199int telProcessConsole(NetParams *pParams, KeyTranslator &KeyTrans, 200 TConsole &Console, TNetwork &Network, TMouse &Mouse, 201 Tnclip &Clipboard, HANDLE hThread) 202{ 203 KeyDefType_const keydef; 204 const char *p; 205 int p_len; 206 unsigned int i; 207 int opval; 208 HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE); 209 210 SetConsoleMode(hConsole, ini.get_enable_mouse() ? ENABLE_MOUSE_INPUT : 0); 211 212 const DWORD nHandle = 2; 213 HANDLE hHandle[nHandle] = {hConsole, pParams->hExit}; 214 215 for (;;) { 216 DWORD dwInput; 217 switch (WaitForMultipleObjects(nHandle, hHandle, FALSE, INFINITE)) { 218 case WAIT_OBJECT_0: { 219 220 // Paul Brannan 7/29/98 221 if(ini.get_input_redir()) { 222 char InputBuffer[10]; 223 224 // Correction from Joe Manns <joe.manns@ardenenginneers.com> 225 // to fix race conditions (4/13/99) 226 int bResult; 227 bResult = ReadFile(hConsole, InputBuffer, 10, &dwInput, 0); 228 if(bResult && dwInput == 0) return TNNOCON; 229 230 // no key translation for redirected input 231 Network.WriteString(InputBuffer, dwInput); 232 break; 233 } 234 235 INPUT_RECORD InputRecord[11]; 236 if (!ReadConsoleInput(hConsole, &InputRecord[0], 10, &dwInput)) 237 return TNPROMPT; 238 239 for (i = 0; (unsigned)i < dwInput; i++){ 240 switch (InputRecord[i].EventType) { 241 case KEY_EVENT:{ 242 if (KEYEVENT.bKeyDown) { 243 244 WORD keyCode = KEYEVENT.wVirtualKeyCode; 245 DWORD keyState = KEYEVENT.dwControlKeyState; 246 247 // Paul Brannan 5/27/98 248 // Moved the code that was here to FindClosestKey() 249 keydef.szKeyDef = FindClosestKey(keyCode, 250 keyState, KeyTrans); 251 252 if(keydef.szKeyDef) { 253 if(!keydef.op->sendstr) 254 if((opval = do_op(keydef.op->the_op, Network, 255 Clipboard)) != 0) 256 return opval; 257 } 258 259 if(Network.get_line_mode()) { 260 if(DoLineModeSpecial(KEYEVENT_CHAR, Console, Network, pParams)) 261 continue; 262 } 263 264 p = keydef.szKeyDef; 265 if (p == NULL) { // if we don't have a translator 266 if(!KEYEVENT_CHAR) continue; 267 p_len = 1; 268 p = KEYEVENT_PCHAR; 269 } else { 270 p_len = strlen(p); 271 } 272 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); 277 } 278 } 279 break; 280 281 case MOUSE_EVENT: 282 if(!InputRecord[i].Event.MouseEvent.dwEventFlags) { 283 ResetEvent(pParams->hUnPause); 284 SetEvent(pParams->hPause); 285 while (!*pParams->bNetPaused); // thread paused 286 // SuspendThread(hThread); 287 288 // Put the mouse's X and Y coords back into the 289 // input buffer 290 DWORD Result; 291 WriteConsoleInput(hConsole, &InputRecord[i], 1, 292 &Result); 293 294 Mouse.doMouse(); 295 296 SetEvent(pParams->hUnPause); 297 // ResumeThread(hThread); 298 } 299 break; 300 301 case FOCUS_EVENT: 302 break; 303 case WINDOW_BUFFER_SIZE_EVENT: 304 // FIX ME!! This should take care of the window re-sizing bug 305 // Unfortunately, it doesn't. 306 Console.sync(); 307 Network.do_naws(Console.GetWidth(), Console.GetHeight()); 308 break; 309 } 310 311 } // keep going until no more input 312 break; 313 } 314 default: 315 return TNNOCON; 316 } 317 } 318} 319 320WORD scrollkeys() { 321 HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE); 322 INPUT_RECORD InputRecord; 323 BOOL done = FALSE; 324 325 while (!done) { 326 DWORD dwInput; 327 WaitForSingleObject( hConsole, INFINITE ); 328 if (!ReadConsoleInput(hConsole, &InputRecord, 1, &dwInput)){ 329 done = TRUE; 330 continue; 331 } 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); 340 return SC_MOUSE; 341 } 342 } 343 } 344 return SC_ESC; 345} 346 347// FIX ME!! This is more evidence that tncon.cpp ought to have class structure 348// (Paul Brannan 12/10/98) 349 350// Bryan Montgomery 10/14/98 351static TNetwork net; 352void setTNetwork(TNetwork tnet) { 353 net = tnet; 354} 355 356// Thomas Briggs 8/17/98 357BOOL WINAPI ControlEventHandler(DWORD event) { 358 switch(event) { 359 case CTRL_BREAK_EVENT: 360 // Bryan Montgomery 10/14/98 361 if(ini.get_control_break_as_c()) net.WriteString("\x3",1); 362 return TRUE; 363 default: 364 return FALSE; 365 } 366}