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 // Class TMapLoader - Key/Character Mappings // 28 // - Loads from telnet.cfg // 29 // originally part of KeyTrans.cpp // 30 ///////////////////////////////////////////////////////// 31 32 #include "precomp.h" 33 34 // It's probably a good idea to turn off the "identifier was truncated" warning 35 // in MSVC (Paul Brannan 5/25/98) 36 #ifdef _MSC_VER 37 #pragma warning(disable: 4786) 38 #endif 39 40 // AVS 41 // skip inline comments, empty lines 42 static char * getline(istream& i, char* buf, int size){ 43 44 int len = 0; 45 46 while (1) { 47 memset(buf,0,size); 48 if (i.eof()) break; 49 i.getline(buf,size,'\n'); 50 51 while (buf[len]) { 52 if ( /*(buf[len]>=0) &&*/ buf[len]< ' ' ) buf[len] = ' '; 53 len++; 54 }; 55 len = 0; 56 57 // not so fast, but work ;) 58 while ( buf[len] ) { 59 if ( (buf[len] == ' ') && (buf[len+1] == ' ')) { 60 memmove(buf+len, buf+len+1, strlen(buf+len)); 61 } else len++; 62 }; 63 64 if (buf[0] == ' ') memmove(buf, buf+1, size-1); 65 66 // empty or comment 67 if ((buf[0]==0)||(buf[0]==';')) continue; 68 69 len = 0; // look for comment like this one 70 while (buf[len]) 71 { 72 if ((buf[len] == '/') && (buf[len + 1] == '/')) buf[len] = 0; 73 else len++; 74 75 if (len && (buf[len - 1] == ' ')) { 76 len--; 77 buf[len] = 0; 78 }; 79 } 80 // in case for comment like this one (in line just a comment) 81 if (buf[0] == 0) continue; 82 83 break; 84 }; 85 return (buf); 86 }; 87 88 //AVS 89 // use string as FIFO queue for lines 90 static int getline(string&str, char* buf, size_t sz) { 91 92 if ( !str.length() ) return 0; 93 const char * p = strchr(str.c_str(),'\n'); 94 unsigned int len; // Changed to unsigned (Paul Brannan 6/23/98) 95 if ( p==NULL ) 96 len = str.length(); 97 else 98 len = p - str.c_str(); 99 100 len = len<sz?len:sz-1; 101 102 strncpy(buf,str.c_str(), len); 103 buf[len]=0; 104 // DJGPP also uses erase rather than remove (Paul Brannan 6/23/98) 105 #ifndef __BORLANDC__ 106 str.erase(0, len + 1); 107 #else 108 str.remove(0,len+1); 109 #endif 110 return 1; 111 }; 112 113 //AVS 114 // parse \nnn and \Xhh 115 static int getbyte(const char*str) { 116 unsigned char retval = 0; 117 int base = 10; 118 int readed = 0; 119 120 if ( (*str == 'x') || (*str == 'X') ) { 121 base = 16; 122 readed++; 123 }; 124 125 while (readed != 3 && str[readed]) { 126 unsigned char ch = toupper(str[readed]); 127 if ( isdigit(ch) ) { 128 retval = retval*base + (ch -'0'); 129 } else if (base == 16 && ch >= 'A' && ch <= 'F') { 130 retval = retval*base + (ch-'A'+10); 131 } else { 132 return -1; 133 }; 134 readed++; 135 }; 136 // Ioannou: If we discard the 0x00 we can't undefine a key !!! 137 // if ( retval == 0 ) { 138 // return -1; 139 // }; 140 return retval; 141 }; 142 143 //AVS 144 // a little optimization 145 DWORD Fix_ControlKeyState(char * Next_Token) { 146 if (stricmp(Next_Token, "RIGHT_ALT" ) == 0) return RIGHT_ALT_PRESSED; 147 if (stricmp(Next_Token, "LEFT_ALT" ) == 0) return LEFT_ALT_PRESSED; 148 if (stricmp(Next_Token, "RIGHT_CTRL") == 0) return RIGHT_CTRL_PRESSED; 149 if (stricmp(Next_Token, "LEFT_CTRL" ) == 0) return LEFT_CTRL_PRESSED; 150 if (stricmp(Next_Token, "SHIFT" ) == 0) return SHIFT_PRESSED; 151 if (stricmp(Next_Token, "NUMLOCK" ) == 0) return NUMLOCK_ON; 152 if (stricmp(Next_Token, "SCROLLLOCK") == 0) return SCROLLLOCK_ON; 153 if (stricmp(Next_Token, "CAPSLOCK" ) == 0) return CAPSLOCK_ON; 154 if (stricmp(Next_Token, "ENHANCED" ) == 0) return ENHANCED_KEY; 155 156 // Paul Brannan 5/27/98 157 if (stricmp(Next_Token, "APP_KEY" ) == 0) return APP_KEY; 158 // Paul Brannan 6/28/98 159 if (stricmp(Next_Token, "APP2_KEY" ) == 0) return APP2_KEY; 160 // Paul Brannan 8/28/98 161 if (stricmp(Next_Token, "APP3_KEY" ) == 0) return APP3_KEY; 162 // Paul Brannan 12/9/98 163 if (stricmp(Next_Token, "APP4_KEY" ) == 0) return APP4_KEY; 164 165 return 0; 166 } 167 168 169 // AVS 170 // rewrited to suppert \xhh notation, a little optimized 171 char* Fix_Tok(char * tok) { 172 static char s[256]; 173 int i,j,n; 174 175 // setmem is nonstandard; memset is standard (Paul Brannan 5/25/98) 176 memset(s, 0, 256); 177 // setmem(s, 256, 0); 178 i = j = n = 0; 179 if ( tok != NULL ) { 180 for ( ; tok[i] != 0; ) { 181 switch ( tok[i] ) { 182 case '\\' : 183 switch ( tok[i+1] ) { 184 case '\\': 185 s[j++] = '\\'; 186 i += 2; 187 break; 188 default: 189 n = getbyte(tok+i+1); 190 if ( n < 0 ) 191 s[j++] = tok[i++]; 192 else { 193 s[j++]=n; 194 i += 4; 195 } ; 196 break; 197 }; 198 break; 199 case '^' : 200 if ( tok[i+1] >= '@' ) { 201 s[j++] = tok[i+1] - '@'; 202 i += 2; 203 break; 204 } 205 default : 206 s[j++] = tok[i++]; 207 } 208 } 209 } 210 return s; 211 }; 212 213 // AVS 214 // perform 'normalization' for lines like [some text], and some checks 215 // maybe it will be done faster - but no time for it 216 int normalizeSplitter(string& buf) { 217 if ( buf.length() <= 2 ) return 0; 218 if ( buf[0] == '[' && buf[buf.length()-1] == ']' ) { 219 while ( buf[1] == ' ' ) 220 // DJGPP also uses erase rather than remove (Paul Brannan 6/23/98) 221 #ifndef __BORLANDC__ 222 buf.erase(1, 1); 223 #else 224 buf.remove(1,1); 225 #endif 226 while ( buf[buf.length()-2] == ' ' ) 227 // Paul Brannan 6/23/98 228 #ifndef __BORLANDC__ 229 buf.erase(buf.length()-2,1); 230 #else 231 buf.remove(buf.length()-2,1); 232 #endif 233 return 1; 234 } 235 return 0; 236 }; 237 238 // AVS 239 // looking for part in string array, see Load(..) for more info 240 int TMapLoader::LookForPart(stringArray& sa, const char* partType, const char* partName) { 241 if ( !sa.IsEmpty() ) { 242 string cmpbuf("["); 243 cmpbuf += partType; 244 cmpbuf += " "; 245 cmpbuf += partName; 246 cmpbuf += "]"; 247 normalizeSplitter(cmpbuf); // if no parttype, [global] for example 248 int max = sa.GetItemsInContainer(); 249 for ( int i = 0; i<max; i++ ) 250 // I found some strange behavior if strnicmp was used here 251 if (strnicmp(cmpbuf.c_str(),sa[i].c_str(),cmpbuf.length()) == 0) 252 return i; 253 }; 254 return INT_MAX; 255 }; 256 257 // AVS 258 // load globals to 'globals' 259 // in buf must be a [global] part of input file 260 int TMapLoader::LoadGlobal(string& buf) { 261 262 char wbuf[128]; 263 while ( buf.length() ) { 264 wbuf[0]=0; 265 if (!getline(buf,wbuf,sizeof(wbuf))) break; 266 if ( wbuf[0]==0 ) break; 267 char* Name = strtok(wbuf, TOKEN_DELIMITERS); 268 if ( stricmp(Name, "[global]")==0 ) continue; 269 270 char* Value = strtok(NULL, TOKEN_DELIMITERS); 271 if ( Value == NULL ) { 272 // cerr << "[global] -> no value for " << Name << endl; 273 printm(0, FALSE, MSG_KEYNOVAL, Name); 274 continue; 275 }; 276 int val = atoi(Value); 277 if ( val > 0 && val <= 0xff ) { 278 if ( !KeyTrans.AddGlobalDef(val, Name)) return 0; 279 } 280 else { 281 // cerr << "[global] -> bad value for " << Name << endl; 282 printm(0, FALSE, MSG_KEYBADVAL, Name); 283 continue; 284 }; 285 }; 286 return 1; 287 }; 288 289 // AVS 290 // perform parsing of strings like 'VK_CODE shifts text' 291 // returns text on success 292 char* TMapLoader::ParseKeyDef(const char* buf, WORD& vk_code, DWORD& control) { 293 char wbuf[256]; 294 strcpy(wbuf,buf); 295 char* ptr = strtok(wbuf, TOKEN_DELIMITERS); 296 if ( ptr == NULL ) return NULL; 297 298 int i = KeyTrans.LookOnGlobal(ptr); 299 if ( i == INT_MAX ) return NULL; 300 301 vk_code = KeyTrans.GetGlobalCode(i); 302 303 control = 0; 304 DWORD st; 305 while (1) { 306 ptr = strtok(NULL, TOKEN_DELIMITERS); 307 if ((ptr == NULL) || ((st = Fix_ControlKeyState(ptr)) == 0)) break; 308 control |= st; 309 }; 310 311 if ( ptr == NULL ) return NULL; 312 313 return Fix_Tok(ptr); 314 }; 315 316 // AVS 317 // load keymap to current map 318 // be aware - buf must passed by value, its destroyed 319 int TMapLoader::LoadKeyMap(string buf) { 320 321 char wbuf[128]; 322 WORD vk_code; 323 DWORD control; 324 int i; 325 326 // Paul Brannan Feb. 22, 1999 327 strcpy(wbuf, "VK_"); 328 wbuf[4] = 0; 329 wbuf[3] = ini.get_escape_key(); 330 i = KeyTrans.LookOnGlobal(wbuf); 331 if (i != INT_MAX) { 332 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), RIGHT_ALT_PRESSED, TN_ESCAPE); 333 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), LEFT_ALT_PRESSED, TN_ESCAPE); 334 } 335 wbuf[3] = ini.get_scrollback_key(); 336 i = KeyTrans.LookOnGlobal(wbuf); 337 if (i != INT_MAX) { 338 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), RIGHT_ALT_PRESSED, TN_SCROLLBACK); 339 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), LEFT_ALT_PRESSED, TN_SCROLLBACK); 340 } 341 wbuf[3] = ini.get_dial_key(); 342 i = KeyTrans.LookOnGlobal(wbuf); 343 if (i != INT_MAX) { 344 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), RIGHT_ALT_PRESSED, TN_DIAL); 345 KeyTrans.AddKeyDef(KeyTrans.GetGlobalCode(i), LEFT_ALT_PRESSED, TN_DIAL); 346 } 347 KeyTrans.AddKeyDef(VK_INSERT, SHIFT_PRESSED, TN_PASTE); 348 349 while ( buf.length() ) { 350 wbuf[0] = 0; 351 if (!getline(buf,wbuf,sizeof(wbuf))) break; 352 if ( wbuf[0]==0 ) break; 353 if ( strnicmp(wbuf,"[keymap",7)==0 ) continue; 354 355 char * keydef = ParseKeyDef(wbuf,vk_code,control); 356 357 if ( keydef != NULL ) { 358 359 // Check to see if keydef is a "special" code (Paul Brannan 3/29/00) 360 if(!strnicmp(keydef, "\\tn_escape", strlen("\\tn_escape"))) { 361 if(!KeyTrans.AddKeyDef(vk_code, control, TN_ESCAPE)) return 0; 362 } else if(!strnicmp(keydef, "\\tn_scrollback", strlen("\\tn_scrollback"))) { 363 if(!KeyTrans.AddKeyDef(vk_code, control, TN_SCROLLBACK)) return 0; 364 } else if(!strnicmp(keydef, "\\tn_dial", strlen("\\tn_dial"))) { 365 if(!KeyTrans.AddKeyDef(vk_code, control, TN_DIAL)) return 0; 366 } else if(!strnicmp(keydef, "\\tn_paste", strlen("\\tn_paste"))) { 367 if(!KeyTrans.AddKeyDef(vk_code, control, TN_PASTE)) return 0; 368 } else if(!strnicmp(keydef, "\\tn_null", strlen("\\tn_null"))) { 369 if(!KeyTrans.AddKeyDef(vk_code, control, TN_NULL)) return 0; 370 } else if(!strnicmp(keydef, "\\tn_cr", strlen("\\tn_cr"))) { 371 if(!KeyTrans.AddKeyDef(vk_code, control, TN_CR)) return 0; 372 } else if(!strnicmp(keydef, "\\tn_crlf", strlen("\\tn_crlf"))) { 373 if(!KeyTrans.AddKeyDef(vk_code, control, TN_CRLF)) return 0; 374 } else 375 if(!KeyTrans.AddKeyDef(vk_code,control,keydef)) return 0; 376 // else DeleteKeyDef() ???? - I'm not sure... 377 } 378 }; 379 380 return 1; 381 }; 382 383 // AVS 384 // load [charmap ...] part to xlat 385 int TMapLoader::LoadCharMap(string buf) { 386 char wbuf[128]; 387 char charmapname[128]; 388 charmapname[0] = 0; 389 390 // xlat.init(); now it done by KeyTranslator::Load() 391 392 while ( buf.length() ) { 393 wbuf[0]=0; 394 if (!getline(buf,wbuf,sizeof(wbuf))) break; 395 if ( wbuf[0]==0 ) break; 396 if ( strnicmp(wbuf,"[charmap",8)==0 ) { 397 strcpy(charmapname,wbuf); 398 continue; 399 }; 400 char * host = strtok(wbuf, " "); 401 char * console = strtok(NULL, " "); 402 403 int bHost; 404 int bConsole; 405 406 if ( host == NULL || console == NULL ) { 407 // cerr << charmapname << " -> Bad structure" << endl; 408 printm(0, FALSE, MSG_KEYBADSTRUCT, charmapname); 409 return 0; 410 }; 411 if ( strlen(host) > 1 && host[0] == '\\' ) 412 bHost = getbyte(host+1); 413 else 414 bHost = (unsigned char)host[0]; 415 416 if ( strlen(console) > 1 && console[0] == '\\' ) 417 bConsole = getbyte(console+1); 418 else 419 bConsole = (unsigned char)console[0]; 420 421 if ( bHost <= 0 || bConsole <= 0 ) { 422 // cerr << charmapname << " -> Bad chars? " 423 // << host << " -> " << console << endl; 424 printm(0, FALSE, MSG_KEYBADCHARS, charmapname, host, console); 425 return 0; 426 }; 427 // xlat.table[bHost] = bConsole; 428 Charmap.modmap(bHost, 'B', bConsole); 429 }; 430 return (Charmap.enabled = 1); 431 }; 432 433 // AVS 434 // ignore long comment [comment] ... [end comment] 435 // recursive! 436 int getLongComment(istream& is, char* wbuf, size_t sz) { 437 438 int bufLen; 439 while ( is ) { 440 wbuf[0] = 0; 441 getline(is, wbuf, sz); 442 if ( wbuf[0]==0 ) return 1; 443 bufLen = strlen(wbuf); 444 if ( wbuf[0] == '[' && wbuf[bufLen-1] == ']' ) { 445 string temps(wbuf); 446 447 if (!normalizeSplitter(temps)) { 448 // cerr << "Unexpected line '" << temps << "'\n"; 449 printm(0, FALSE, MSG_KEYUNEXPLINE, temps.c_str()); 450 return 0; 451 }; 452 if ( stricmp(temps.c_str(),"[comment]") == 0 ) { 453 // do recursive call 454 if ( !getLongComment(is, wbuf, sz) ) return 0; 455 continue; 456 }; 457 if ( stricmp(temps.c_str(),"[end comment]") == 0 ) return 1; 458 }; 459 }; 460 // we get a warning if we don't put a return here (Paul Brannan 5/25/98) 461 return 0; 462 }; 463 464 // AVS 465 // completelly rewrited to support new conceptions 466 int TMapLoader::Load(const char * filename, const char * szActiveEmul) { 467 char buf[256]; 468 int bufLen; 469 470 ifstream inpfile(filename); 471 KeyTrans.DeleteAllDefs(); 472 Charmap.init(); 473 474 // it is an array for store [...] ... [end ...] parts from file 475 stringArray SA(0,0,sizeof(string)); 476 int AllOk = 0; 477 478 while ( inpfile ) { 479 480 getline(inpfile, buf, 255); 481 bufLen = strlen(buf); 482 if ( !bufLen ) continue; 483 484 if ( buf[0] == '[' && buf[bufLen-1] == ']' ) { 485 // is a part splitter [...] 486 string temps(buf); 487 488 if (!normalizeSplitter(temps)) { 489 printm(0, FALSE, MSG_KEYUNEXPLINE, temps.c_str()); 490 AllOk = 0; 491 break; 492 }; 493 // if a comment 494 if ( stricmp(temps.c_str(),"[comment]") == 0 ) { 495 #ifdef KEYDEBUG 496 printit(temps.c_str()); 497 #endif 498 if ( !getLongComment(inpfile, buf, sizeof(buf)) ) { 499 printm(0, FALSE, MSG_KEYUNEXPEOF); 500 break; 501 }; 502 #ifdef KEYDEBUG 503 printit("\r \r"); 504 #endif 505 continue; 506 }; 507 508 509 string back = temps; 510 // prepare line for make it as [end ...] 511 // and check it 512 if ( strnicmp(back.c_str(), "[global]", 8) == 0 ) {} // do nothing 513 else if ( strnicmp(back.c_str(), "[keymap", 7) == 0 ) { 514 // DJGPP also uses erase rather than remove (Paul Brannan 6/23/98) 515 #ifndef __BORLANDC__ 516 back.erase(7); 517 #else 518 back.remove(7); 519 #endif 520 back += "]"; 521 } 522 else if ( strnicmp(back.c_str(), "[charmap", 8) == 0 ) { 523 // Paul Brannan 6/23/98 524 #ifndef __BORLANDC__ 525 back.erase(8); 526 #else 527 back.remove(8); 528 #endif 529 back += "]"; 530 } 531 else if ( strnicmp(back.c_str(), "[config", 7) == 0 ) { 532 // Paul Brannan 6/23/98 533 #ifndef __BORLANDC__ 534 back.erase(7); 535 #else 536 back.remove(7); 537 #endif 538 back += "]"; 539 } 540 else { 541 // cerr << "Unexpected token " << back << endl; 542 printm(0, FALSE, MSG_KEYUNEXPTOK, back.c_str()); 543 break; 544 }; 545 546 back.insert(1,"END "); // now it looks like [END ...] 547 #ifdef KEYDEBUG 548 printit(temps.c_str()); 549 #endif 550 551 int ok = 0; 552 // fetch it to temps 553 while ( 1 ) { 554 getline(inpfile, buf, sizeof(buf)); 555 bufLen = strlen(buf); 556 if ( !bufLen ) break; 557 if ( buf[0] == '[' && buf[bufLen-1] == ']' ) { 558 string t(buf); 559 if ( !normalizeSplitter(t) ) break; 560 561 if ( stricmp(t.c_str(),back.c_str()) == 0 ) { 562 ok = 1; 563 break; 564 }; 565 566 // AVS 31.12.97 fix [comment] block inside another block 567 if ( stricmp(t.c_str(),"[comment]") == 0 && 568 getLongComment(inpfile, buf, sizeof(buf)) ) continue; 569 570 break; 571 }; 572 temps += "\n"; 573 temps += buf; 574 }; 575 if ( !ok ) { 576 // cerr << "Unexpected end of file or token" << endl; 577 printm(0, FALSE, MSG_KEYUNEXP); 578 AllOk = 0; 579 break; 580 }; 581 #ifdef KEYDEBUG 582 printit("\r \r"); 583 #endif 584 AllOk = SA.Add(temps); 585 if ( !AllOk ) break; 586 } else { 587 // cerr << "Unexpected line '" << buf << "'\n"; 588 printm(0, FALSE, MSG_KEYUNEXPLINE, buf); 589 AllOk = 0; 590 break; 591 }; 592 }; 593 594 inpfile.close(); 595 596 if ( !AllOk ) return 0; 597 598 // now all file are in SA, comments are stripped 599 600 int i = LookForPart(SA, "global", ""); 601 if ( i == INT_MAX ) { 602 // cerr << "No [GLOBAL] definition!" << endl; 603 printm(0, FALSE, MSG_KEYNOGLOBAL); 604 return 0; 605 }; 606 if ( !LoadGlobal(SA[i]) ) { 607 return 0; 608 }; 609 610 // look for need configuration 611 i = LookForPart(SA, "config", szActiveEmul); 612 if ( i == INT_MAX ) { 613 // cerr << "No [CONFIG " << szActiveEmul << "]\n"; 614 printm(0, FALSE, MSG_KEYNOCONFIG, szActiveEmul); 615 return 0; 616 }; 617 // cerr << "use configuration: " << szActiveEmul << endl; 618 printm(0, FALSE, MSG_KEYUSECONFIG, szActiveEmul); 619 BOOL hadKeys = FALSE; 620 621 string config = SA[i]; 622 // parse it 623 while ( config.length() ) { 624 buf[0] = 0; 625 getline(config,buf,sizeof(buf)); 626 bufLen = strlen(buf); 627 if ( !bufLen || (buf[0] == '[' && buf[bufLen-1] == ']') ) continue; 628 if ( strnicmp(buf,"keymap",6) == 0 ) { 629 string orig(buf); 630 printit("\t"); printit(buf); printit("\n"); 631 char * mapdef = strtok(buf,":"); 632 char * switchKey = strtok(NULL,"\n"); 633 634 if ( !KeyTrans.mapArray.IsEmpty() && switchKey == NULL ) { 635 // cerr << "no switch Key for '" << mapdef 636 // << "'" << endl; 637 printm(0, FALSE, MSG_KEYNOSWKEY, mapdef); 638 break; 639 }; 640 if ( KeyTrans.mapArray.IsEmpty() ) { 641 if ( switchKey != NULL ) { // create default keymap 642 // cerr << "You cannot define switch key for default keymap -> ignored" 643 // << endl; 644 printm(0, FALSE, MSG_KEYCANNOTDEF); 645 }; 646 TKeyDef empty; 647 KeyTrans.mapArray.Add(KeyMap(string(mapdef))); 648 KeyTrans.switchMap(empty); // set it as current keymap 649 KeyTrans.mainKeyMap = KeyTrans.currentKeyMap; 650 } 651 else { 652 string keydef(switchKey); 653 keydef += " !*!*!*"; // just for check 654 WORD vk_code; 655 DWORD control; 656 switchKey = ParseKeyDef(keydef.c_str(),vk_code,control); 657 if ( switchKey != NULL ) { 658 TKeyDef swi(NULL,control,vk_code); 659 if ( KeyTrans.switchMap(swi) > 0 ) { 660 // cerr << "Duplicate switching key\n"; 661 printm(0, FALSE, MSG_KEYDUPSWKEY); 662 break; 663 }; 664 KeyTrans.mapArray.Add(KeyMap(swi, orig)); 665 KeyTrans.switchMap(swi); // set it as current keymap 666 } 667 }; 668 mapdef+=7; // 'keymap ' 669 // now load defined keymaps to current 670 while ((mapdef != NULL)&& 671 (mapdef = strtok(mapdef,TOKEN_DELIMITERS)) != NULL ) { 672 i = LookForPart(SA,"keymap",mapdef); 673 if ( i == INT_MAX ) { 674 // cerr << "Unknown KEYMAP " << mapdef << endl; 675 printm(0, FALSE, MSG_KEYUNKNOWNMAP, mapdef); 676 } else { 677 mapdef = strtok(NULL,"\n"); // strtok is used in LoadKeyMap 678 // so - save pointer! 679 hadKeys = LoadKeyMap(SA[i]); // load it 680 }; 681 }; 682 683 } 684 else if ( strnicmp(buf,"charmap",7) == 0 ) { 685 printit("\t"); printit(buf); printit("\n"); 686 char * mapdef = buf + 8;// 'charmap ' 687 int SuccesLoaded = 0; 688 // now load defined charmaps to current 689 while ((mapdef != NULL)&& 690 (mapdef = strtok(mapdef,TOKEN_DELIMITERS)) != NULL ) { 691 i = LookForPart(SA,"charmap",mapdef); 692 if ( i == INT_MAX ) { 693 // cerr << "Unknown KEYMAP " << mapdef << endl; 694 printm(0, FALSE, MSG_KEYUNKNOWNMAP, mapdef); 695 } else { 696 mapdef = strtok(NULL,"\n"); // strtok is used in LoadKeyMap 697 // so - save pointer! 698 if (LoadCharMap(SA[i])) // load it 699 SuccesLoaded++; 700 }; 701 }; 702 if (!SuccesLoaded) { 703 // cerr << "No charmaps loaded\n"; 704 printm(0, FALSE, MSG_KEYNOCHARMAPS); 705 Charmap.init(); 706 }; 707 /* strtok(buf," "); 708 709 char* name = strtok(NULL," "); 710 if ( name == NULL ) { 711 cerr << "No name for CHARMAP" << endl; 712 } else { 713 i = LookForPart(SA,"charmap", name); 714 if ( i == INT_MAX ) { 715 cerr << "Unknown CHARMAP " << name << endl; 716 } else { 717 LoadCharMap(SA[i]); 718 }; 719 }; 720 */ 721 } 722 else { 723 // cerr << "unexpected token in " << szActiveEmul << endl; 724 printm(0, FALSE, MSG_KEYUNEXPTOKIN, szActiveEmul); 725 } 726 } 727 728 if ( hadKeys) { 729 TKeyDef empty; 730 KeyTrans.switchMap(empty); // switch to default 731 KeyTrans.mainKeyMap = KeyTrans.currentKeyMap; // save it's number 732 // cerr << "There are " << (KeyTrans.mapArray.GetItemsInContainer()) << " maps\n"; 733 char s[12]; // good enough for a long int (32-bit) 734 itoa(KeyTrans.mapArray.GetItemsInContainer(), s, 10); 735 printm(0, FALSE, MSG_KEYNUMMAPS, s); 736 return 1; 737 }; 738 return 0; 739 } 740 741 void TMapLoader::Display() { 742 743 int max = KeyTrans.mapArray.GetItemsInContainer(); 744 if (max == 0) { 745 printm(0, FALSE, MSG_KEYNOKEYMAPS); 746 return; 747 }; 748 for ( int i = 0; i < max; i++ ) { 749 char buf[20]; 750 itoa(i,buf,10); 751 printit("\t"); 752 // Ioannou : we can show the current 753 if (KeyTrans.currentKeyMap == i) 754 printit("*"); 755 else 756 printit(" "); 757 strcat(buf," "); 758 printit(buf); 759 char * msg = new char [KeyTrans.mapArray[i].orig.length()+1]; 760 strcpy(msg,KeyTrans.mapArray[i].orig.c_str()); 761 printit(msg); 762 delete[] msg; 763 printit("\n"); 764 }; 765 }; 766