1 /* 2 * CHOICE.C - internal command. 3 * 4 * 5 * History: 6 * 7 * 12 Aug 1999 (Eric Kohl) 8 * started. 9 * 10 * 01 Sep 1999 (Eric Kohl) 11 * Fixed help text. 12 * 13 * 26 Sep 1999 (Paolo Pantaleo) 14 * Fixed timeout. 15 * 16 * 02 Apr 2005 (Magnus Olsen) 17 * Remove hardcoded strings so that they can be translated. 18 * 19 */ 20 21 #include "precomp.h" 22 23 #ifdef INCLUDE_CMD_CHOICE 24 25 26 #define GC_TIMEOUT -1 27 #define GC_NOKEY 0 //an event occurred but it wasn't a key pressed 28 #define GC_KEYREAD 1 //a key has been read 29 30 31 static INT 32 GetCharacterTimeout (LPTCH ch, DWORD dwMilliseconds) 33 { 34 //-------------------------------------------- 35 // Get a character from standard input but with a timeout. 36 // The function will wait a limited amount 37 // of time, then the function returns GC_TIMEOUT. 38 // 39 // dwMilliseconds is the timeout value, that can 40 // be set to INFINITE, so the function works like 41 // stdio.h's getchar() 42 43 HANDLE hInput; 44 DWORD dwRead; 45 46 INPUT_RECORD lpBuffer; 47 48 hInput = GetStdHandle (STD_INPUT_HANDLE); 49 50 //if the timeout expired return GC_TIMEOUT 51 if (WaitForSingleObject (hInput, dwMilliseconds) == WAIT_TIMEOUT) 52 return GC_TIMEOUT; 53 54 //otherwise get the event 55 ReadConsoleInput (hInput, &lpBuffer, 1, &dwRead); 56 57 //if the event is a key pressed 58 if ((lpBuffer.EventType == KEY_EVENT) && 59 (lpBuffer.Event.KeyEvent.bKeyDown != FALSE)) 60 { 61 //read the key 62 #ifdef _UNICODE 63 *ch = lpBuffer.Event.KeyEvent.uChar.UnicodeChar; 64 #else 65 *ch = lpBuffer.Event.KeyEvent.uChar.AsciiChar; 66 #endif 67 return GC_KEYREAD; 68 } 69 70 //else return no key 71 return GC_NOKEY; 72 } 73 74 static INT 75 IsKeyInString (LPTSTR lpString, TCHAR cKey, BOOL bCaseSensitive) 76 { 77 LPTCH p = lpString; 78 INT val = 0; 79 80 while (*p) 81 { 82 if (bCaseSensitive) 83 { 84 if (*p == cKey) 85 return val; 86 } 87 else 88 { 89 if (_totlower (*p) == _totlower (cKey)) 90 return val; 91 } 92 93 val++; 94 p++; 95 } 96 97 return -1; 98 } 99 100 101 INT 102 CommandChoice (LPTSTR param) 103 { 104 LPTSTR lpOptions; 105 TCHAR Options[6]; 106 LPTSTR lpText = NULL; 107 BOOL bNoPrompt = FALSE; 108 BOOL bCaseSensitive = FALSE; 109 BOOL bTimeout = FALSE; 110 INT nTimeout = 0; 111 TCHAR cDefault = _T('\0'); 112 INPUT_RECORD ir; 113 LPTSTR p, np; 114 LPTSTR *arg; 115 INT argc; 116 INT i; 117 INT val; 118 119 INT GCret; 120 TCHAR Ch; 121 DWORD amount,clk; 122 123 LoadString(CMD_ModuleHandle, STRING_CHOICE_OPTION, Options, 4); 124 lpOptions = Options; 125 126 if (_tcsncmp (param, _T("/?"), 2) == 0) 127 { 128 ConOutResPaging(TRUE,STRING_CHOICE_HELP); 129 return 0; 130 } 131 132 /* retrieve text */ 133 p = param; 134 135 while (TRUE) 136 { 137 if (*p == _T('\0')) 138 break; 139 140 if (*p != _T('/')) 141 { 142 lpText = p; 143 break; 144 } 145 np = _tcschr (p, _T(' ')); 146 if (!np) 147 break; 148 p = np + 1; 149 } 150 151 /* build parameter array */ 152 arg = split (param, &argc, FALSE, FALSE); 153 154 /* evaluate arguments */ 155 if (argc > 0) 156 { 157 for (i = 0; i < argc; i++) 158 { 159 if (_tcsnicmp (arg[i], _T("/c"), 2) == 0) 160 { 161 if (arg[i][2] == _T(':')) 162 lpOptions = &arg[i][3]; 163 else 164 lpOptions = &arg[i][2]; 165 166 if (_tcslen (lpOptions) == 0) 167 { 168 ConErrResPuts(STRING_CHOICE_ERROR); 169 freep (arg); 170 return 1; 171 } 172 } 173 else if (_tcsnicmp (arg[i], _T("/n"), 2) == 0) 174 { 175 bNoPrompt = TRUE; 176 } 177 else if (_tcsnicmp (arg[i], _T("/s"), 2) == 0) 178 { 179 bCaseSensitive = TRUE; 180 } 181 else if (_tcsnicmp (arg[i], _T("/t"), 2) == 0) 182 { 183 LPTSTR s; 184 185 if (arg[i][2] == _T(':')) 186 { 187 cDefault = arg[i][3]; 188 s = &arg[i][4]; 189 } 190 else 191 { 192 cDefault = arg[i][2]; 193 s = &arg[i][3]; 194 } 195 196 if (*s != _T(',')) 197 { 198 ConErrResPuts(STRING_CHOICE_ERROR_TXT); 199 freep (arg); 200 return 1; 201 } 202 203 s++; 204 nTimeout = _ttoi(s); 205 bTimeout = TRUE; 206 } 207 else if (arg[i][0] == _T('/')) 208 { 209 ConErrResPrintf(STRING_CHOICE_ERROR_OPTION, arg[i]); 210 freep (arg); 211 return 1; 212 } 213 } 214 } 215 216 /* print text */ 217 if (lpText) 218 ConOutPrintf (_T("%s"), lpText); 219 220 /* print options */ 221 if (bNoPrompt == FALSE) 222 { 223 ConOutPrintf (_T("[%c"), lpOptions[0]); 224 225 for (i = 1; (unsigned)i < _tcslen (lpOptions); i++) 226 ConOutPrintf (_T(",%c"), lpOptions[i]); 227 228 ConOutPrintf (_T("]?")); 229 } 230 231 ConInFlush (); 232 233 if (!bTimeout) 234 { 235 while (TRUE) 236 { 237 ConInKey (&ir); 238 239 val = IsKeyInString (lpOptions, 240 #ifdef _UNICODE 241 ir.Event.KeyEvent.uChar.UnicodeChar, 242 #else 243 ir.Event.KeyEvent.uChar.AsciiChar, 244 #endif 245 bCaseSensitive); 246 247 if (val >= 0) 248 { 249 ConOutPrintf (_T("%c\n"), lpOptions[val]); 250 251 nErrorLevel = val + 1; 252 253 break; 254 } 255 256 Beep (440, 50); 257 } 258 259 freep (arg); 260 TRACE ("ErrorLevel: %d\n", nErrorLevel); 261 return 0; 262 } 263 264 clk = GetTickCount (); 265 amount = nTimeout*1000; 266 267 loop: 268 GCret = GetCharacterTimeout (&Ch, amount - (GetTickCount () - clk)); 269 270 switch (GCret) 271 { 272 case GC_TIMEOUT: 273 TRACE ("GC_TIMEOUT\n"); 274 TRACE ("elapsed %d msecs\n", GetTickCount () - clk); 275 break; 276 277 case GC_NOKEY: 278 TRACE ("GC_NOKEY\n"); 279 TRACE ("elapsed %d msecs\n", GetTickCount () - clk); 280 goto loop; 281 282 case GC_KEYREAD: 283 TRACE ("GC_KEYREAD\n"); 284 TRACE ("elapsed %d msecs\n", GetTickCount () - clk); 285 TRACE ("read %c\n", Ch); 286 if ((val=IsKeyInString(lpOptions,Ch,bCaseSensitive))==-1) 287 { 288 Beep (440, 50); 289 goto loop; 290 } 291 cDefault=Ch; 292 break; 293 } 294 295 TRACE ("exiting wait loop after %d msecs\n", 296 GetTickCount () - clk); 297 298 val = IsKeyInString (lpOptions, cDefault, bCaseSensitive); 299 ConOutPrintf(_T("%c\n"), lpOptions[val]); 300 301 nErrorLevel = val + 1; 302 303 freep (arg); 304 305 TRACE ("ErrorLevel: %d\n", nErrorLevel); 306 307 return 0; 308 } 309 #endif /* INCLUDE_CMD_CHOICE */ 310 311 /* EOF */ 312