DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include "dosbox.h" 00021 #include "bios.h" 00022 #include "bios_disk.h" 00023 #include "setup.h" 00024 #include "support.h" 00025 #include "../ints/int10.h" 00026 #include "regs.h" 00027 #include "callback.h" 00028 #include "mapper.h" 00029 #include "drives.h" 00030 #include "dos_inc.h" 00031 #include "control.h" 00032 00033 #include "dos_codepages.h" 00034 #include "dos_keyboard_layout_data.h" 00035 00036 #if defined (WIN32) 00037 #include <windows.h> 00038 #endif 00039 00040 00041 static FILE* OpenDosboxFile(const char* name) { 00042 Bit8u drive; 00043 char fullname[DOS_PATHLENGTH]; 00044 00045 localDrive* ldp=0; 00046 // try to build dos name 00047 if (DOS_MakeName(name,fullname,&drive)) { 00048 try { 00049 // try to open file on mounted drive first 00050 ldp=dynamic_cast<localDrive*>(Drives[drive]); 00051 if (ldp) { 00052 FILE *tmpfile=ldp->GetSystemFilePtr(fullname, "rb"); 00053 if (tmpfile != NULL) return tmpfile; 00054 } 00055 } 00056 catch(...) {} 00057 } 00058 FILE *tmpfile=fopen(name, "rb"); 00059 return tmpfile; 00060 } 00061 00062 00063 class keyboard_layout { 00064 public: 00065 keyboard_layout() { 00066 this->reset(); 00067 language_codes=NULL; 00068 use_foreign_layout=false; 00069 sprintf(current_keyboard_file_name, "none"); 00070 }; 00071 00072 ~keyboard_layout(); 00073 00074 // read in a codepage from a .cpi-file 00075 Bitu read_codepage_file(const char* codepage_file_name, Bit32s codepage_id); 00076 Bit16u extract_codepage(const char* keyboard_file_name); 00077 // read in a keyboard layout from a .kl-file 00078 Bitu read_keyboard_file(const char* keyboard_file_name, Bit32s req_cp); 00079 00080 // call layout_key to apply the current language layout 00081 bool layout_key(Bitu key, Bit8u flags1, Bit8u flags2, Bit8u flags3); 00082 00083 Bitu switch_keyboard_layout(const char* new_layout, keyboard_layout* &created_layout, Bit32s& tried_cp); 00084 void switch_foreign_layout(); 00085 const char* get_layout_name(); 00086 const char* main_language_code(); 00087 00088 00089 private: 00090 static const Bit8u layout_pages=12; 00091 Bit16u current_layout[(MAX_SCAN_CODE+1)*layout_pages]; 00092 struct { 00093 Bit16u required_flags,forbidden_flags; 00094 Bit16u required_userflags,forbidden_userflags; 00095 } current_layout_planes[layout_pages-4]; 00096 Bit8u additional_planes = 0; 00097 Bit8u used_lock_modifiers; 00098 00099 // diacritics table 00100 Bit8u diacritics[2048] = {}; 00101 Bit16u diacritics_entries; 00102 Bit16u diacritics_character; 00103 Bit16u user_keys; 00104 00105 char current_keyboard_file_name[256]; 00106 bool use_foreign_layout; 00107 00108 // language code storage used when switching layouts 00109 char** language_codes; 00110 Bitu language_code_count; 00111 00112 void reset(); 00113 void read_keyboard_file(Bit32s specific_layout); 00114 Bitu read_keyboard_file(const char* keyboard_file_name, Bit32s specific_layout, Bit32s requested_codepage); 00115 bool map_key(Bitu key, Bit16u layouted_key, bool is_command, bool is_keypair); 00116 }; 00117 00118 00119 keyboard_layout::~keyboard_layout() { 00120 if (language_codes) { 00121 for (Bitu i=0; i<language_code_count; i++) 00122 delete[] language_codes[i]; 00123 delete[] language_codes; 00124 language_codes=NULL; 00125 } 00126 } 00127 00128 void keyboard_layout::reset() { 00129 for (Bit32u i=0; i<(MAX_SCAN_CODE+1)*layout_pages; i++) current_layout[i]=0; 00130 for (Bit32u i=0; i<layout_pages-4; i++) { 00131 current_layout_planes[i].required_flags=0; 00132 current_layout_planes[i].forbidden_flags=0xffff; 00133 current_layout_planes[i].required_userflags=0; 00134 current_layout_planes[i].forbidden_userflags=0xffff; 00135 } 00136 used_lock_modifiers=0x0f; 00137 diacritics_entries=0; // no diacritics loaded 00138 diacritics_character=0; 00139 user_keys=0; // all userkeys off 00140 language_code_count=0; 00141 } 00142 00143 Bitu keyboard_layout::read_keyboard_file(const char* keyboard_file_name, Bit32s req_cp) { 00144 return this->read_keyboard_file(keyboard_file_name, -1, req_cp); 00145 } 00146 00147 // switch to a different layout 00148 void keyboard_layout::read_keyboard_file(Bit32s specific_layout) { 00149 if (strcmp(current_keyboard_file_name,"none")) 00150 this->read_keyboard_file(current_keyboard_file_name, specific_layout, dos.loaded_codepage); 00151 } 00152 00153 static Bit32u read_kcl_file(const char* kcl_file_name, const char* layout_id, bool first_id_only) { 00154 FILE* tempfile = OpenDosboxFile(kcl_file_name); 00155 if (tempfile==0) return 0; 00156 00157 static Bit8u rbuf[8192]; 00158 00159 // check ID-bytes of file 00160 Bit32u dr=(Bit32u)fread(rbuf, sizeof(Bit8u), 7, tempfile); 00161 if ((dr<7) || (rbuf[0]!=0x4b) || (rbuf[1]!=0x43) || (rbuf[2]!=0x46)) { 00162 fclose(tempfile); 00163 return 0; 00164 } 00165 00166 fseek(tempfile, 7+rbuf[6], SEEK_SET); 00167 00168 for (;;) { 00169 Bit32u cur_pos=(Bit32u)(ftell(tempfile)); 00170 dr=(Bit32u)fread(rbuf, sizeof(Bit8u), 5, tempfile); 00171 if (dr<5) break; 00172 Bit16u len=host_readw(&rbuf[0]); 00173 00174 Bit8u data_len=rbuf[2]; 00175 00176 char lng_codes[258]; 00177 fseek(tempfile, -2, SEEK_CUR); 00178 // get all language codes for this layout 00179 for (Bitu i=0; i<data_len;) { 00180 size_t readResult = fread(rbuf, sizeof(Bit8u), 2, tempfile); 00181 if (readResult != 2) { 00182 LOG(LOG_IO, LOG_ERROR) ("Reading error in read_kcl_file\n"); 00183 return 0; 00184 } 00185 Bit16u lcnum=host_readw(&rbuf[0]); 00186 i+=2; 00187 Bitu lcpos=0; 00188 for (;i<data_len;) { 00189 readResult = fread(rbuf, sizeof(Bit8u), 1, tempfile); 00190 if (readResult != 1) { 00191 LOG(LOG_IO, LOG_ERROR) ("Reading error in read_kcl_file\n"); 00192 return 0; 00193 } 00194 i++; 00195 if (((char)rbuf[0])==',') break; 00196 lng_codes[lcpos++]=(char)rbuf[0]; 00197 } 00198 lng_codes[lcpos]=0; 00199 if (strcasecmp(lng_codes, layout_id)==0) { 00200 // language ID found in file, return file position 00201 fclose(tempfile); 00202 return cur_pos; 00203 } 00204 if (first_id_only) break; 00205 if (lcnum) { 00206 sprintf(&lng_codes[lcpos],"%d",lcnum); 00207 if (strcasecmp(lng_codes, layout_id)==0) { 00208 // language ID found in file, return file position 00209 return cur_pos; 00210 } 00211 } 00212 } 00213 fseek(tempfile, long(cur_pos+3+len), SEEK_SET); 00214 } 00215 00216 fclose(tempfile); 00217 return 0; 00218 } 00219 00220 static Bit32u read_kcl_data(const Bit8u* kcl_data, Bit32u kcl_data_size, const char* layout_id, bool first_id_only) { 00221 // check ID-bytes 00222 if ((kcl_data[0]!=0x4b) || (kcl_data[1]!=0x43) || (kcl_data[2]!=0x46)) { 00223 return 0; 00224 } 00225 00226 Bit32u dpos=7u+kcl_data[6]; 00227 00228 for (;;) { 00229 if (dpos+5>kcl_data_size) break; 00230 Bit32u cur_pos=dpos; 00231 Bit16u len=host_readw(&kcl_data[dpos]); 00232 Bit8u data_len=kcl_data[dpos+2]; 00233 dpos+=5; 00234 00235 char lng_codes[258]; 00236 // get all language codes for this layout 00237 for (Bitu i=0; i<data_len;) { 00238 Bit16u lcnum=host_readw(&kcl_data[dpos-2]); 00239 i+=2; 00240 Bitu lcpos=0; 00241 for (;i<data_len;) { 00242 if (dpos+1>kcl_data_size) break; 00243 char lc=(char)kcl_data[dpos]; 00244 dpos++; 00245 i++; 00246 if (lc==',') break; 00247 lng_codes[lcpos++]=lc; 00248 } 00249 lng_codes[lcpos]=0; 00250 if (strcasecmp(lng_codes, layout_id)==0) { 00251 // language ID found, return position 00252 return cur_pos; 00253 } 00254 if (first_id_only) break; 00255 if (lcnum) { 00256 sprintf(&lng_codes[lcpos],"%d",lcnum); 00257 if (strcasecmp(lng_codes, layout_id)==0) { 00258 // language ID found, return position 00259 return cur_pos; 00260 } 00261 } 00262 dpos+=2; 00263 } 00264 dpos=cur_pos+3+len; 00265 } 00266 return 0; 00267 } 00268 00269 Bitu keyboard_layout::read_keyboard_file(const char* keyboard_file_name, Bit32s specific_layout, Bit32s requested_codepage) { 00270 this->reset(); 00271 00272 if (specific_layout==-1) strcpy(current_keyboard_file_name, keyboard_file_name); 00273 if (!strcmp(keyboard_file_name,"none")) return KEYB_NOERROR; 00274 00275 static Bit8u read_buf[65535]; 00276 Bit32u read_buf_size, read_buf_pos, bytes_read; 00277 Bit32u start_pos=5; 00278 00279 char nbuf[512]; 00280 read_buf_size = 0; 00281 sprintf(nbuf, "%s.kl", keyboard_file_name); 00282 FILE* tempfile = OpenDosboxFile(nbuf); 00283 if (tempfile==NULL) { 00284 // try keyboard layout libraries next 00285 if ((start_pos=read_kcl_file("keyboard.sys",keyboard_file_name,true))) { 00286 tempfile = OpenDosboxFile("keyboard.sys"); 00287 } else if ((start_pos=read_kcl_file("keybrd2.sys",keyboard_file_name,true))) { 00288 tempfile = OpenDosboxFile("keybrd2.sys"); 00289 } else if ((start_pos=read_kcl_file("keybrd3.sys",keyboard_file_name,true))) { 00290 tempfile = OpenDosboxFile("keybrd3.sys"); 00291 } else if ((start_pos=read_kcl_file("keyboard.sys",keyboard_file_name,false))) { 00292 tempfile = OpenDosboxFile("keyboard.sys"); 00293 } else if ((start_pos=read_kcl_file("keybrd2.sys",keyboard_file_name,false))) { 00294 tempfile = OpenDosboxFile("keybrd2.sys"); 00295 } else if ((start_pos=read_kcl_file("keybrd3.sys",keyboard_file_name,false))) { 00296 tempfile = OpenDosboxFile("keybrd3.sys"); 00297 } else if ((start_pos=read_kcl_data(layout_keyboardsys,33196,keyboard_file_name,true))) { 00298 read_buf_size=0; 00299 for (Bitu ct=start_pos+2; ct<33196; ct++) read_buf[read_buf_size++]=layout_keyboardsys[ct]; 00300 } else if ((start_pos=read_kcl_data(layout_keybrd2sys,25431,keyboard_file_name,true))) { 00301 read_buf_size=0; 00302 for (Bitu ct=start_pos+2; ct<25431; ct++) read_buf[read_buf_size++]=layout_keybrd2sys[ct]; 00303 } else if ((start_pos=read_kcl_data(layout_keybrd3sys,27122,keyboard_file_name,true))) { 00304 read_buf_size=0; 00305 for (Bitu ct=start_pos+2; ct<27122; ct++) read_buf[read_buf_size++]=layout_keybrd3sys[ct]; 00306 } else if ((start_pos=read_kcl_data(layout_keyboardsys,33196,keyboard_file_name,false))) { 00307 read_buf_size=0; 00308 for (Bitu ct=start_pos+2; ct<33196; ct++) read_buf[read_buf_size++]=layout_keyboardsys[ct]; 00309 } else if ((start_pos=read_kcl_data(layout_keybrd2sys,25431,keyboard_file_name,false))) { 00310 read_buf_size=0; 00311 for (Bitu ct=start_pos+2; ct<25431; ct++) read_buf[read_buf_size++]=layout_keybrd2sys[ct]; 00312 } else if ((start_pos=read_kcl_data(layout_keybrd3sys,27122,keyboard_file_name,false))) { 00313 read_buf_size=0; 00314 for (Bitu ct=start_pos+2; ct<27122; ct++) read_buf[read_buf_size++]=layout_keybrd3sys[ct]; 00315 } else { 00316 LOG(LOG_BIOS,LOG_ERROR)("Keyboard layout file %s not found",keyboard_file_name); 00317 return KEYB_FILENOTFOUND; 00318 } 00319 if (tempfile) { 00320 fseek(tempfile, long(start_pos+2), SEEK_SET); 00321 read_buf_size=(Bit32u)fread(read_buf, sizeof(Bit8u), 65535, tempfile); 00322 fclose(tempfile); 00323 } 00324 start_pos=0; 00325 } else { 00326 // check ID-bytes of file 00327 Bit32u dr=(Bit32u)fread(read_buf, sizeof(Bit8u), 4, tempfile); 00328 if ((dr<4) || (read_buf[0]!=0x4b) || (read_buf[1]!=0x4c) || (read_buf[2]!=0x46)) { 00329 LOG(LOG_BIOS,LOG_ERROR)("Invalid keyboard layout file %s",keyboard_file_name); 00330 return KEYB_INVALIDFILE; 00331 } 00332 00333 fseek(tempfile, 0, SEEK_SET); 00334 read_buf_size=(Bit32u)fread(read_buf, sizeof(Bit8u), 65535, tempfile); 00335 fclose(tempfile); 00336 } 00337 00338 Bit8u data_len,submappings; 00339 data_len=read_buf[start_pos++]; 00340 00341 language_codes=new char*[data_len]; 00342 language_code_count=0; 00343 // get all language codes for this layout 00344 for (Bitu i=0; i<data_len;) { 00345 language_codes[language_code_count]=new char[256]; 00346 i+=2; 00347 Bitu lcpos=0; 00348 for (;i<data_len;) { 00349 char lcode=char(read_buf[start_pos+i]); 00350 i++; 00351 if (lcode==',') break; 00352 language_codes[language_code_count][lcpos++]=lcode; 00353 } 00354 language_codes[language_code_count][lcpos]=0; 00355 language_code_count++; 00356 } 00357 00358 start_pos+=data_len; // start_pos==absolute position of KeybCB block 00359 00360 submappings=read_buf[start_pos]; 00361 additional_planes=read_buf[start_pos+1]; 00362 00363 // four pages always occupied by normal,shift,flags,commandbits 00364 if (additional_planes>(layout_pages-4)) additional_planes=(layout_pages-4); 00365 00366 // seek to plane descriptor 00367 read_buf_pos=start_pos+0x14u+submappings*8u; 00368 for (Bit16u cplane=0; cplane<additional_planes; cplane++) { 00369 Bit16u plane_flags; 00370 00371 // get required-flags (shift/alt/ctrl-states etc.) 00372 plane_flags=host_readw(&read_buf[read_buf_pos]); 00373 read_buf_pos+=2; 00374 current_layout_planes[cplane].required_flags=plane_flags; 00375 used_lock_modifiers |= (plane_flags&0x70); 00376 // get forbidden-flags 00377 plane_flags=host_readw(&read_buf[read_buf_pos]); 00378 read_buf_pos+=2; 00379 current_layout_planes[cplane].forbidden_flags=plane_flags; 00380 00381 // get required-userflags 00382 plane_flags=host_readw(&read_buf[read_buf_pos]); 00383 read_buf_pos+=2; 00384 current_layout_planes[cplane].required_userflags=plane_flags; 00385 // get forbidden-userflags 00386 plane_flags=host_readw(&read_buf[read_buf_pos]); 00387 read_buf_pos+=2; 00388 current_layout_planes[cplane].forbidden_userflags=plane_flags; 00389 } 00390 00391 bool found_matching_layout=false; 00392 00393 // check all submappings and use them if general submapping or same codepage submapping 00394 for (Bit16u sub_map=0; (sub_map<submappings) && (!found_matching_layout); sub_map++) { 00395 Bit16u submap_cp, table_offset; 00396 00397 if ((sub_map!=0) && (specific_layout!=-1)) sub_map=(Bit16u)(specific_layout&0xffff); 00398 00399 // read codepage of submapping 00400 submap_cp=host_readw(&read_buf[start_pos+0x14u+sub_map*8u]); 00401 if ((submap_cp!=0) && (submap_cp!=requested_codepage) && (specific_layout==-1)) 00402 continue; // skip nonfitting submappings 00403 00404 if (submap_cp==requested_codepage) found_matching_layout=true; 00405 00406 // get table offset 00407 table_offset=host_readw(&read_buf[start_pos+0x18u+sub_map*8u]); 00408 diacritics_entries=0; 00409 if (table_offset!=0) { 00410 // process table 00411 Bit16u i,j; 00412 for (i=0; i<2048;) { 00413 if (read_buf[start_pos+table_offset+i]==0) break; // end of table 00414 diacritics_entries++; 00415 i+=read_buf[start_pos+table_offset+i+1]*2+2; 00416 } 00417 // copy diacritics table 00418 for (j=0; j<=i; j++) diacritics[j]=read_buf[start_pos+table_offset+j]; 00419 } 00420 00421 00422 // get table offset 00423 table_offset=host_readw(&read_buf[start_pos+0x16u+sub_map*8u]); 00424 if (table_offset==0) continue; // non-present table 00425 00426 read_buf_pos=start_pos+table_offset; 00427 00428 bytes_read=read_buf_size-read_buf_pos; 00429 00430 // process submapping table 00431 for (Bit32u i=0; i<bytes_read;) { 00432 Bit8u scan=read_buf[read_buf_pos++]; 00433 if (scan==0) break; 00434 Bit8u scan_length=(read_buf[read_buf_pos]&7)+1; // length of data struct 00435 read_buf_pos+=2; 00436 i+=3; 00437 if (((scan&0x7f)<=MAX_SCAN_CODE) && (scan_length>0)) { 00438 // add all available mappings 00439 for (Bit16u addmap=0; addmap<scan_length; addmap++) { 00440 if (addmap>additional_planes+2) break; 00441 Bitu charptr=read_buf_pos+addmap*((read_buf[read_buf_pos-2u]&0x80u)?2u:1u); 00442 Bit16u kchar=read_buf[charptr]; 00443 00444 if (kchar!=0) { // key remapped 00445 if (read_buf[read_buf_pos-2]&0x80) kchar|=read_buf[charptr+1]<<8; // scancode/char pair 00446 // overwrite mapping 00447 current_layout[scan*layout_pages+addmap]=kchar; 00448 // clear command bit 00449 current_layout[scan*layout_pages+layout_pages-2]&=~(1<<addmap); 00450 // add command bit 00451 current_layout[scan*layout_pages+layout_pages-2]|=(read_buf[read_buf_pos-1] & (1<<addmap)); 00452 } 00453 } 00454 00455 // calculate max length of entries, taking into account old number of entries 00456 Bit8u new_flags=current_layout[scan*layout_pages+layout_pages-1]&0x7; 00457 if ((read_buf[read_buf_pos-2]&0x7) > new_flags) new_flags = read_buf[read_buf_pos-2]&0x7; 00458 00459 // merge flag bits in as well 00460 new_flags |= (read_buf[read_buf_pos-2] | current_layout[scan*layout_pages+layout_pages-1]) & 0xf0; 00461 00462 current_layout[scan*layout_pages+layout_pages-1]=new_flags; 00463 if (read_buf[read_buf_pos-2]&0x80) scan_length*=2; // granularity flag (S) 00464 } 00465 i+=scan_length; // advance pointer 00466 read_buf_pos+=scan_length; 00467 } 00468 if (specific_layout==sub_map) break; 00469 } 00470 00471 if (found_matching_layout) { 00472 if (specific_layout==-1) LOG(LOG_BIOS,LOG_NORMAL)("Keyboard layout %s successfully loaded",keyboard_file_name); 00473 else LOG(LOG_BIOS,LOG_NORMAL)("Keyboard layout %s (%i) successfully loaded",keyboard_file_name,specific_layout); 00474 this->use_foreign_layout=true; 00475 return KEYB_NOERROR; 00476 } 00477 00478 LOG(LOG_BIOS,LOG_ERROR)("No matching keyboard layout found in %s",keyboard_file_name); 00479 00480 // reset layout data (might have been changed by general layout) 00481 this->reset(); 00482 00483 return KEYB_LAYOUTNOTFOUND; 00484 } 00485 00486 bool keyboard_layout::layout_key(Bitu key, Bit8u flags1, Bit8u flags2, Bit8u flags3) { 00487 if (key>MAX_SCAN_CODE) return false; 00488 if (!this->use_foreign_layout) return false; 00489 00490 bool is_special_pair=(current_layout[key*layout_pages+layout_pages-1] & 0x80)==0x80; 00491 00492 if ((((flags1&used_lock_modifiers)&0x7c)==0) && ((flags3&2)==0)) { 00493 // check if shift/caps is active: 00494 // (left_shift OR right_shift) XOR (key_affected_by_caps AND caps_locked) 00495 if ((((flags1&2)>>1) | (flags1&1)) ^ (((current_layout[key*layout_pages+layout_pages-1] & 0x40) & (flags1 & 0x40))>>6)) { 00496 // shift plane 00497 if (current_layout[key*layout_pages+1]!=0) { 00498 // check if command-bit is set for shift plane 00499 bool is_command=(current_layout[key*layout_pages+layout_pages-2]&2)!=0; 00500 if (this->map_key(key, current_layout[key*layout_pages+1], 00501 is_command, is_special_pair)) return true; 00502 } 00503 } else { 00504 // normal plane 00505 if (current_layout[key*layout_pages]!=0) { 00506 // check if command-bit is set for normal plane 00507 bool is_command=(current_layout[key*layout_pages+layout_pages-2]&1)!=0; 00508 if (this->map_key(key, current_layout[key*layout_pages], 00509 is_command, is_special_pair)) return true; 00510 } 00511 } 00512 } 00513 00514 // calculate current flags 00515 Bit16u current_flags=(flags1&0x7f) | (((flags2&3) | (flags3&0xc))<<8); 00516 if (flags1&3) current_flags|=0x4000; // either shift key active 00517 if (flags3&2) current_flags|=0x1000; // e0 prefixed 00518 00519 // check all planes if flags fit 00520 for (Bit16u cplane=0; cplane<additional_planes; cplane++) { 00521 Bit16u req_flags=current_layout_planes[cplane].required_flags; 00522 Bit16u req_userflags=current_layout_planes[cplane].required_userflags; 00523 // test flags 00524 if (((current_flags & req_flags)==req_flags) && 00525 ((user_keys & req_userflags)==req_userflags) && 00526 ((current_flags & current_layout_planes[cplane].forbidden_flags)==0) && 00527 ((user_keys & current_layout_planes[cplane].forbidden_userflags)==0)) { 00528 // remap key 00529 if (current_layout[key*layout_pages+2+cplane]!=0) { 00530 // check if command-bit is set for this plane 00531 bool is_command=((current_layout[key*layout_pages+layout_pages-2]>>(cplane+2))&1)!=0; 00532 if (this->map_key(key, current_layout[key*layout_pages+2+cplane], 00533 is_command, is_special_pair)) return true; 00534 } else break; // abort plane checking 00535 } 00536 } 00537 00538 if (diacritics_character>0) { 00539 // ignore state-changing keys 00540 switch(key) { 00541 case 0x1d: /* Ctrl Pressed */ 00542 case 0x2a: /* Left Shift Pressed */ 00543 case 0x36: /* Right Shift Pressed */ 00544 case 0x38: /* Alt Pressed */ 00545 case 0x3a: /* Caps Lock */ 00546 case 0x45: /* Num Lock */ 00547 case 0x46: /* Scroll Lock */ 00548 break; 00549 default: 00550 if (diacritics_character-200>=diacritics_entries) { 00551 diacritics_character=0; 00552 return true; 00553 } 00554 Bit16u diacritics_start=0; 00555 // search start of subtable 00556 for (Bit16u i=0; i<diacritics_character-200; i++) 00557 diacritics_start+=diacritics[diacritics_start+1]*2+2; 00558 00559 BIOS_AddKeyToBuffer((Bit16u)(key<<8) | diacritics[diacritics_start]); 00560 diacritics_character=0; 00561 } 00562 } 00563 00564 return false; 00565 } 00566 00567 bool keyboard_layout::map_key(Bitu key, Bit16u layouted_key, bool is_command, bool is_keypair) { 00568 if (is_command) { 00569 Bit8u key_command=(Bit8u)(layouted_key&0xff); 00570 // check if diacritics-command 00571 if ((key_command>=200) && (key_command<235)) { 00572 // diacritics command 00573 diacritics_character=key_command; 00574 if (diacritics_character-200>=diacritics_entries) diacritics_character=0; 00575 return true; 00576 } else if ((key_command>=120) && (key_command<140)) { 00577 // switch layout command 00578 this->read_keyboard_file(key_command-119); 00579 return true; 00580 } else if ((key_command>=180) && (key_command<188)) { 00581 // switch user key off 00582 user_keys&=~(1<<(key_command-180)); 00583 return true; 00584 } else if ((key_command>=188) && (key_command<196)) { 00585 // switch user key on 00586 user_keys|=(1<<(key_command-188)); 00587 return true; 00588 } else if (key_command==160) return true; // nop command 00589 } else { 00590 // non-command 00591 if (diacritics_character>0) { 00592 if (diacritics_character-200>=diacritics_entries) diacritics_character = 0; 00593 else { 00594 Bit16u diacritics_start=0; 00595 // search start of subtable 00596 for (Bit16u i=0; i<diacritics_character-200; i++) 00597 diacritics_start+=diacritics[diacritics_start+1]*2+2; 00598 00599 Bit8u diacritics_length=diacritics[diacritics_start+1]; 00600 diacritics_start+=2; 00601 diacritics_character=0; // reset 00602 00603 // search scancode 00604 for (Bit16u i=0; i<diacritics_length; i++) { 00605 if (diacritics[diacritics_start+i*2]==(layouted_key&0xff)) { 00606 // add diacritics to keybuf 00607 BIOS_AddKeyToBuffer((Bit16u)(key<<8) | diacritics[diacritics_start+i*2+1]); 00608 return true; 00609 } 00610 } 00611 // add standard-diacritics to keybuf 00612 BIOS_AddKeyToBuffer((Bit16u)(key<<8) | diacritics[diacritics_start-2]); 00613 } 00614 } 00615 00616 // add remapped key to keybuf 00617 if (is_keypair) BIOS_AddKeyToBuffer(layouted_key); 00618 else BIOS_AddKeyToBuffer((Bit16u)(key<<8) | (layouted_key&0xff)); 00619 00620 return true; 00621 } 00622 return false; 00623 } 00624 00625 Bit16u keyboard_layout::extract_codepage(const char* keyboard_file_name) { 00626 if (!strcmp(keyboard_file_name,"none")) return (IS_PC98_ARCH ? 932 : 437); 00627 00628 Bit32u read_buf_size; 00629 static Bit8u read_buf[65535]; 00630 Bit32u start_pos=5; 00631 00632 char nbuf[512]; 00633 sprintf(nbuf, "%s.kl", keyboard_file_name); 00634 FILE* tempfile = OpenDosboxFile(nbuf); 00635 if (tempfile==NULL) { 00636 // try keyboard layout libraries next 00637 if ((start_pos=read_kcl_file("keyboard.sys",keyboard_file_name,true))) { 00638 tempfile = OpenDosboxFile("keyboard.sys"); 00639 } else if ((start_pos=read_kcl_file("keybrd2.sys",keyboard_file_name,true))) { 00640 tempfile = OpenDosboxFile("keybrd2.sys"); 00641 } else if ((start_pos=read_kcl_file("keybrd3.sys",keyboard_file_name,true))) { 00642 tempfile = OpenDosboxFile("keybrd3.sys"); 00643 } else if ((start_pos=read_kcl_file("keyboard.sys",keyboard_file_name,false))) { 00644 tempfile = OpenDosboxFile("keyboard.sys"); 00645 } else if ((start_pos=read_kcl_file("keybrd2.sys",keyboard_file_name,false))) { 00646 tempfile = OpenDosboxFile("keybrd2.sys"); 00647 } else if ((start_pos=read_kcl_file("keybrd3.sys",keyboard_file_name,false))) { 00648 tempfile = OpenDosboxFile("keybrd3.sys"); 00649 } else if ((start_pos=read_kcl_data(layout_keyboardsys,33196,keyboard_file_name,true))) { 00650 read_buf_size=0; 00651 for (Bitu ct=start_pos+2; ct<33196; ct++) read_buf[read_buf_size++]=layout_keyboardsys[ct]; 00652 } else if ((start_pos=read_kcl_data(layout_keybrd2sys,25431,keyboard_file_name,true))) { 00653 read_buf_size=0; 00654 for (Bitu ct=start_pos+2; ct<25431; ct++) read_buf[read_buf_size++]=layout_keybrd2sys[ct]; 00655 } else if ((start_pos=read_kcl_data(layout_keybrd3sys,27122,keyboard_file_name,true))) { 00656 read_buf_size=0; 00657 for (Bitu ct=start_pos+2; ct<27122; ct++) read_buf[read_buf_size++]=layout_keybrd3sys[ct]; 00658 } else if ((start_pos=read_kcl_data(layout_keyboardsys,33196,keyboard_file_name,false))) { 00659 read_buf_size=0; 00660 for (Bitu ct=start_pos+2; ct<33196; ct++) read_buf[read_buf_size++]=layout_keyboardsys[ct]; 00661 } else if ((start_pos=read_kcl_data(layout_keybrd2sys,25431,keyboard_file_name,false))) { 00662 read_buf_size=0; 00663 for (Bitu ct=start_pos+2; ct<25431; ct++) read_buf[read_buf_size++]=layout_keybrd2sys[ct]; 00664 } else if ((start_pos=read_kcl_data(layout_keybrd3sys,27122,keyboard_file_name,false))) { 00665 read_buf_size=0; 00666 for (Bitu ct=start_pos+2; ct<27122; ct++) read_buf[read_buf_size++]=layout_keybrd3sys[ct]; 00667 } else { 00668 start_pos=0; 00669 LOG(LOG_BIOS,LOG_ERROR)("Keyboard layout file %s not found",keyboard_file_name); 00670 return (IS_PC98_ARCH ? 932 : 437); 00671 } 00672 if (tempfile) { 00673 fseek(tempfile, long(start_pos+2), SEEK_SET); 00674 read_buf_size=(Bit32u)fread(read_buf, sizeof(Bit8u), 65535, tempfile); 00675 fclose(tempfile); 00676 } 00677 start_pos=0; 00678 } else { 00679 // check ID-bytes of file 00680 Bit32u dr=(Bit32u)fread(read_buf, sizeof(Bit8u), 4, tempfile); 00681 if ((dr<4) || (read_buf[0]!=0x4b) || (read_buf[1]!=0x4c) || (read_buf[2]!=0x46)) { 00682 LOG(LOG_BIOS,LOG_ERROR)("Invalid keyboard layout file %s",keyboard_file_name); 00683 return (IS_PC98_ARCH ? 932 : 437); 00684 } 00685 00686 fseek(tempfile, 0, SEEK_SET); 00687 read_buf_size=(Bit32u)fread(read_buf, sizeof(Bit8u), 65535, tempfile); 00688 fclose(tempfile); 00689 } 00690 00691 Bit8u data_len,submappings; 00692 data_len=read_buf[start_pos++]; 00693 00694 start_pos+=data_len; // start_pos==absolute position of KeybCB block 00695 00696 submappings=read_buf[start_pos]; 00697 00698 // check all submappings and use them if general submapping or same codepage submapping 00699 for (Bit16u sub_map=0; (sub_map<submappings); sub_map++) { 00700 Bit16u submap_cp; 00701 00702 // read codepage of submapping 00703 submap_cp=host_readw(&read_buf[start_pos+0x14u+sub_map*8u]); 00704 00705 if (submap_cp!=0) return submap_cp; 00706 } 00707 return (IS_PC98_ARCH ? 932 : 437); 00708 } 00709 00710 Bitu keyboard_layout::read_codepage_file(const char* codepage_file_name, Bit32s codepage_id) { 00711 char cp_filename[512]; 00712 strcpy(cp_filename, codepage_file_name); 00713 if (!strcmp(cp_filename,"none")) return KEYB_NOERROR; 00714 00715 if (codepage_id==dos.loaded_codepage) return KEYB_NOERROR; 00716 00717 if (!strcmp(cp_filename,"auto")) { 00718 // select matching .cpi-file for specified codepage 00719 switch (codepage_id) { 00720 case 437: case 850: case 852: case 853: case 857: case 858: 00721 sprintf(cp_filename, "EGA.CPI"); break; 00722 case 775: case 859: case 1116: case 1117: 00723 sprintf(cp_filename, "EGA2.CPI"); break; 00724 case 771: case 772: case 808: case 855: case 866: case 872: 00725 sprintf(cp_filename, "EGA3.CPI"); break; 00726 case 848: case 849: case 1125: case 1131: case 61282: 00727 sprintf(cp_filename, "EGA4.CPI"); break; 00728 case 737: case 851: case 869: 00729 sprintf(cp_filename, "EGA5.CPI"); break; 00730 case 113: case 899: case 59829: case 60853: 00731 sprintf(cp_filename, "EGA6.CPI"); break; 00732 case 58152: case 58210: case 59234: case 60258: case 62306: 00733 sprintf(cp_filename, "EGA7.CPI"); break; 00734 case 770: case 773: case 774: case 777: case 778: 00735 sprintf(cp_filename, "EGA8.CPI"); break; 00736 case 860: case 861: case 863: case 865: 00737 sprintf(cp_filename, "EGA9.CPI"); break; 00738 case 667: case 668: case 790: case 867: case 991: case 57781: 00739 sprintf(cp_filename, "EGA10.CPI"); break; 00740 default: 00741 LOG_MSG("No matching cpi file for codepage %i",codepage_id); 00742 return KEYB_INVALIDCPFILE; 00743 } 00744 } 00745 00746 Bit32u start_pos; 00747 Bit16u number_of_codepages; 00748 00749 char nbuf[512]; 00750 sprintf(nbuf, "%s", cp_filename); 00751 FILE* tempfile=OpenDosboxFile(nbuf); 00752 if (tempfile==NULL) { 00753 size_t strsz=strlen(nbuf); 00754 if (strsz) { 00755 char plc=(char)toupper(*reinterpret_cast<unsigned char*>(&nbuf[strsz-1])); 00756 if (plc=='I') { 00757 // try CPX-extension as well 00758 nbuf[strsz-1]='X'; 00759 tempfile=OpenDosboxFile(nbuf); 00760 } else if (plc=='X') { 00761 // try CPI-extension as well 00762 nbuf[strsz-1]='I'; 00763 tempfile=OpenDosboxFile(nbuf); 00764 } 00765 } 00766 } 00767 00768 static Bit8u cpi_buf[65536]; 00769 Bit32u cpi_buf_size=0,size_of_cpxdata=0; 00770 bool upxfound=false; 00771 Bit16u found_at_pos=5; 00772 if (tempfile==NULL) { 00773 // check if build-in codepage is available 00774 switch (codepage_id) { 00775 case 437: case 850: case 852: case 853: case 857: case 858: 00776 for (Bitu bct=0; bct<6322; bct++) cpi_buf[bct]=font_ega_cpx[bct]; 00777 cpi_buf_size=6322; 00778 break; 00779 case 771: case 772: case 808: case 855: case 866: case 872: 00780 for (Bitu bct=0; bct<5455; bct++) cpi_buf[bct]=font_ega3_cpx[bct]; 00781 cpi_buf_size=5455; 00782 break; 00783 case 737: case 851: case 869: 00784 for (Bitu bct=0; bct<5720; bct++) cpi_buf[bct]=font_ega5_cpx[bct]; 00785 cpi_buf_size=5720; 00786 break; 00787 default: 00788 return KEYB_INVALIDCPFILE; 00789 } 00790 upxfound=true; 00791 found_at_pos=0x29; 00792 size_of_cpxdata=cpi_buf_size; 00793 } else { 00794 Bit32u dr=(Bit32u)fread(cpi_buf, sizeof(Bit8u), 5, tempfile); 00795 // check if file is valid 00796 if (dr<5) { 00797 LOG(LOG_BIOS,LOG_ERROR)("Codepage file %s invalid",cp_filename); 00798 return KEYB_INVALIDCPFILE; 00799 } 00800 // check if non-compressed cpi file 00801 if ((cpi_buf[0]!=0xff) || (cpi_buf[1]!=0x46) || (cpi_buf[2]!=0x4f) || 00802 (cpi_buf[3]!=0x4e) || (cpi_buf[4]!=0x54)) { 00803 // check if dr-dos custom cpi file 00804 if ((cpi_buf[0]==0x7f) && (cpi_buf[1]!=0x44) && (cpi_buf[2]!=0x52) && 00805 (cpi_buf[3]!=0x46) && (cpi_buf[4]!=0x5f)) { 00806 LOG(LOG_BIOS,LOG_ERROR)("Codepage file %s has unsupported DR-DOS format",cp_filename); 00807 return KEYB_INVALIDCPFILE; 00808 } 00809 // check if compressed cpi file 00810 Bit8u next_byte=0; 00811 for (Bitu i=0; i<100; i++) { 00812 size_t readResult = fread(&next_byte, sizeof(Bit8u), 1, tempfile); 00813 if (readResult != 1) { 00814 LOG(LOG_IO, LOG_ERROR) ("Reading error in read_codepage_file\n"); 00815 } 00816 found_at_pos++; 00817 while (next_byte == 0x55) { 00818 readResult = fread(&next_byte, sizeof(Bit8u), 1, tempfile); 00819 if (readResult != 1) { 00820 LOG(LOG_IO, LOG_ERROR) ("Reading error in read_codepage_file\n"); 00821 } 00822 found_at_pos++; 00823 if (next_byte == 0x50) { 00824 readResult = fread(&next_byte, sizeof(Bit8u), 1, tempfile); 00825 if (readResult != 1) { 00826 LOG(LOG_IO, LOG_ERROR) ("Reading error in read_codepage_file\n"); 00827 } 00828 found_at_pos++; 00829 if (next_byte == 0x58) { 00830 readResult = fread(&next_byte, sizeof(Bit8u), 1, tempfile); 00831 if (readResult != 1) { 00832 LOG(LOG_IO, LOG_ERROR) ("Reading error in read_codepage_file\n"); 00833 } 00834 found_at_pos++; 00835 if (next_byte == 0x21) { 00836 // read version ID 00837 readResult = fread(&next_byte, sizeof(Bit8u), 1, tempfile); 00838 if (readResult != 1) { 00839 LOG(LOG_IO, LOG_ERROR) ("Reading error in read_codepage_file\n"); 00840 } 00841 found_at_pos++; 00842 upxfound=true; 00843 break; 00844 } 00845 } 00846 } 00847 } 00848 if (upxfound) break; 00849 } 00850 if (!upxfound) { 00851 LOG(LOG_BIOS,LOG_ERROR)("Codepage file %s invalid: %x",cp_filename,cpi_buf[0]); 00852 return KEYB_INVALIDCPFILE; 00853 } else { 00854 if (next_byte<10) E_Exit("UPX-compressed cpi file, but upx-version too old"); 00855 00856 // read in compressed CPX-file 00857 fseek(tempfile, 0, SEEK_SET); 00858 size_of_cpxdata=(Bit32u)fread(cpi_buf, sizeof(Bit8u), 65536, tempfile); 00859 } 00860 } else { 00861 // standard uncompressed cpi-file 00862 fseek(tempfile, 0, SEEK_SET); 00863 cpi_buf_size=(Bit32u)fread(cpi_buf, sizeof(Bit8u), 65536, tempfile); 00864 } 00865 } 00866 00867 if (upxfound) { 00868 if (size_of_cpxdata>0xfe00) E_Exit("Size of cpx-compressed data too big"); 00869 00870 found_at_pos+=19; 00871 // prepare for direct decompression 00872 cpi_buf[found_at_pos]=0xcb; 00873 00874 Bit16u seg=0; 00875 Bit16u size=0x1500; 00876 if (!DOS_AllocateMemory(&seg,&size)) E_Exit("Not enough free low memory to unpack data"); 00877 MEM_BlockWrite(((unsigned int)seg<<4u)+0x100u,cpi_buf,size_of_cpxdata); 00878 00879 // setup segments 00880 Bit16u save_ds=SegValue(ds); 00881 Bit16u save_es=SegValue(es); 00882 Bit16u save_ss=SegValue(ss); 00883 Bit32u save_esp=reg_esp; 00884 SegSet16(ds,seg); 00885 SegSet16(es,seg); 00886 SegSet16(ss,seg+0x1000); 00887 reg_esp=0xfffe; 00888 00889 // let UPX unpack the file 00890 CALLBACK_RunRealFar(seg,0x100); 00891 00892 SegSet16(ds,save_ds); 00893 SegSet16(es,save_es); 00894 SegSet16(ss,save_ss); 00895 reg_esp=save_esp; 00896 00897 // get unpacked content 00898 MEM_BlockRead(((unsigned int)seg<<4u)+0x100u,cpi_buf,65536u); 00899 cpi_buf_size=65536; 00900 00901 DOS_FreeMemory(seg); 00902 } 00903 00904 00905 start_pos=host_readd(&cpi_buf[0x13]); 00906 number_of_codepages=host_readw(&cpi_buf[start_pos]); 00907 start_pos+=4; 00908 00909 // search if codepage is provided by file 00910 for (Bit16u test_codepage=0; test_codepage<number_of_codepages; test_codepage++) { 00911 Bit16u device_type, font_codepage, font_type; 00912 00913 // device type can be display/printer (only the first is supported) 00914 device_type=host_readw(&cpi_buf[start_pos+0x04]); 00915 font_codepage=host_readw(&cpi_buf[start_pos+0x0e]); 00916 00917 Bit32u font_data_header_pt; 00918 font_data_header_pt=host_readd(&cpi_buf[start_pos+0x16]); 00919 00920 font_type=host_readw(&cpi_buf[font_data_header_pt]); 00921 00922 if ((device_type==0x0001) && (font_type==0x0001) && (font_codepage==codepage_id)) { 00923 // valid/matching codepage found 00924 00925 Bit16u number_of_fonts;//,font_data_length; 00926 number_of_fonts=host_readw(&cpi_buf[font_data_header_pt+0x02]); 00927 // font_data_length=host_readw(&cpi_buf[font_data_header_pt+0x04]); 00928 00929 bool font_changed=false; 00930 Bit32u font_data_start=font_data_header_pt+0x06; 00931 00932 // load all fonts if possible 00933 for (Bit16u current_font=0; current_font<number_of_fonts; current_font++) { 00934 Bit8u font_height=cpi_buf[font_data_start]; 00935 font_data_start+=6; 00936 if (font_height==0x10) { 00937 // 16x8 font, IF supported by the video card 00938 if (int10.rom.font_16 != 0) { 00939 PhysPt font16pt=Real2Phys(int10.rom.font_16); 00940 for (Bit16u i=0;i<256*16;i++) { 00941 phys_writeb(font16pt+i,cpi_buf[font_data_start+i]); 00942 } 00943 // terminate alternate list to prevent loading 00944 phys_writeb(Real2Phys(int10.rom.font_16_alternate),0); 00945 font_changed=true; 00946 } 00947 } else if (font_height==0x0e) { 00948 // 14x8 font, IF supported by the video card 00949 if (int10.rom.font_14 != 0) { 00950 PhysPt font14pt=Real2Phys(int10.rom.font_14); 00951 for (Bit16u i=0;i<256*14;i++) { 00952 phys_writeb(font14pt+i,cpi_buf[font_data_start+i]); 00953 } 00954 // terminate alternate list to prevent loading 00955 phys_writeb(Real2Phys(int10.rom.font_14_alternate),0); 00956 font_changed=true; 00957 } 00958 } else if (font_height==0x08) { 00959 // 8x8 fonts. All video cards support it 00960 if (int10.rom.font_8_first != 0) { 00961 PhysPt font8pt=Real2Phys(int10.rom.font_8_first); 00962 for (Bit16u i=0;i<128*8;i++) { 00963 phys_writeb(font8pt+i,cpi_buf[font_data_start+i]); 00964 } 00965 font_changed=true; 00966 } 00967 if (int10.rom.font_8_second != 0) { 00968 PhysPt font8pt=Real2Phys(int10.rom.font_8_second); 00969 for (Bit16u i=0;i<128*8;i++) { 00970 phys_writeb(font8pt+i,cpi_buf[font_data_start+i+128*8]); 00971 } 00972 font_changed=true; 00973 } 00974 } 00975 font_data_start+=font_height*256u; 00976 } 00977 00978 LOG(LOG_BIOS,LOG_NORMAL)("Codepage %i successfully loaded",codepage_id); 00979 00980 // set codepage entries 00981 dos.loaded_codepage=(Bit16u)(codepage_id&0xffff); 00982 00983 // update font if necessary (EGA/VGA/SVGA only) 00984 if (font_changed && (CurMode->type==M_TEXT) && (IS_EGAVGA_ARCH)) { 00985 INT10_ReloadFont(); 00986 } 00987 INT10_SetupRomMemoryChecksum(); 00988 00989 return KEYB_NOERROR; 00990 } 00991 00992 start_pos=host_readd(&cpi_buf[start_pos]); 00993 start_pos+=2; 00994 } 00995 00996 LOG(LOG_BIOS,LOG_ERROR)("Codepage %i not found",codepage_id); 00997 00998 return KEYB_INVALIDCPFILE; 00999 } 01000 01001 Bitu keyboard_layout::switch_keyboard_layout(const char* new_layout, keyboard_layout*& created_layout, Bit32s& tried_cp) { 01002 if (strncasecmp(new_layout,"US",2)) { 01003 // switch to a foreign layout 01004 char tbuf[256]; 01005 strcpy(tbuf, new_layout); 01006 size_t newlen=strlen(tbuf); 01007 01008 bool language_code_found=false; 01009 // check if language code is present in loaded foreign layout 01010 for (Bitu i=0; i<language_code_count; i++) { 01011 if (!strncasecmp(tbuf,language_codes[i],newlen)) { 01012 language_code_found=true; 01013 break; 01014 } 01015 } 01016 01017 if (language_code_found) { 01018 if (!this->use_foreign_layout) { 01019 // switch to foreign layout 01020 this->use_foreign_layout=true; 01021 diacritics_character=0; 01022 LOG(LOG_BIOS,LOG_NORMAL)("Switched to layout %s",tbuf); 01023 } 01024 } else { 01025 keyboard_layout * temp_layout=new keyboard_layout(); 01026 Bit16u req_codepage=temp_layout->extract_codepage(new_layout); 01027 tried_cp = req_codepage; 01028 Bitu kerrcode=temp_layout->read_keyboard_file(new_layout, req_codepage); 01029 if (kerrcode) { 01030 delete temp_layout; 01031 return kerrcode; 01032 } 01033 // ...else keyboard layout loaded successfully, change codepage accordingly 01034 kerrcode=temp_layout->read_codepage_file("auto", req_codepage); 01035 if (kerrcode) { 01036 delete temp_layout; 01037 return kerrcode; 01038 } 01039 // Everything went fine, switch to new layout 01040 created_layout=temp_layout; 01041 } 01042 } else if (this->use_foreign_layout) { 01043 // switch to the US layout 01044 this->use_foreign_layout=false; 01045 diacritics_character=0; 01046 LOG(LOG_BIOS,LOG_NORMAL)("Switched to US layout"); 01047 } 01048 return KEYB_NOERROR; 01049 } 01050 01051 void keyboard_layout::switch_foreign_layout() { 01052 this->use_foreign_layout=!this->use_foreign_layout; 01053 diacritics_character=0; 01054 if (this->use_foreign_layout) LOG(LOG_BIOS,LOG_NORMAL)("Switched to foreign layout"); 01055 else LOG(LOG_BIOS,LOG_NORMAL)("Switched to US layout"); 01056 } 01057 01058 const char* keyboard_layout::get_layout_name() { 01059 // get layout name (language ID or NULL if default layout) 01060 if (use_foreign_layout) { 01061 if (strcmp(current_keyboard_file_name,"none") != 0) { 01062 return (const char*)¤t_keyboard_file_name; 01063 } 01064 } 01065 return NULL; 01066 } 01067 01068 const char* keyboard_layout::main_language_code() { 01069 if (language_codes) { 01070 return language_codes[0]; 01071 } 01072 return NULL; 01073 } 01074 01075 01076 static keyboard_layout* loaded_layout=NULL; 01077 01078 // CTRL-ALT-F2 switches between foreign and US-layout using this function 01079 /* static void switch_keyboard_layout(bool pressed) { 01080 if (!pressed) 01081 return; 01082 if (loaded_layout) loaded_layout->switch_foreign_layout(); 01083 } */ 01084 01085 // called by int9-handler 01086 bool DOS_LayoutKey(Bitu key, Bit8u flags1, Bit8u flags2, Bit8u flags3) { 01087 if (loaded_layout) return loaded_layout->layout_key(key, flags1, flags2, flags3); 01088 else return false; 01089 } 01090 01091 Bitu DOS_LoadKeyboardLayout(const char * layoutname, Bit32s codepage, const char * codepagefile) { 01092 keyboard_layout * temp_layout=new keyboard_layout(); 01093 // try to read the layout for the specified codepage 01094 Bitu kerrcode=temp_layout->read_keyboard_file(layoutname, codepage); 01095 if (kerrcode) { 01096 delete temp_layout; 01097 return kerrcode; 01098 } 01099 // ...else keyboard layout loaded successfully, change codepage accordingly 01100 kerrcode=temp_layout->read_codepage_file(codepagefile, codepage); 01101 if (kerrcode) { 01102 delete temp_layout; 01103 return kerrcode; 01104 } 01105 // Everything went fine, switch to new layout 01106 loaded_layout=temp_layout; 01107 return KEYB_NOERROR; 01108 } 01109 01110 Bitu DOS_SwitchKeyboardLayout(const char* new_layout, Bit32s& tried_cp) { 01111 if (loaded_layout) { 01112 keyboard_layout* changed_layout=NULL; 01113 Bitu ret_code=loaded_layout->switch_keyboard_layout(new_layout, changed_layout, tried_cp); 01114 if (changed_layout) { 01115 // Remove old layout, activate new layout 01116 delete loaded_layout; 01117 loaded_layout=changed_layout; 01118 } 01119 return ret_code; 01120 } else return 0xff; 01121 } 01122 01123 // get currently loaded layout name (NULL if no layout is loaded) 01124 const char* DOS_GetLoadedLayout(void) { 01125 if (loaded_layout) { 01126 return loaded_layout->get_layout_name(); 01127 } 01128 return NULL; 01129 } 01130 01131 01132 class DOS_KeyboardLayout: public Module_base { 01133 public: 01134 DOS_KeyboardLayout(Section* configuration):Module_base(configuration){ 01135 const Section_prop* section = static_cast<Section_prop*>(configuration); 01136 dos.loaded_codepage=(IS_PC98_ARCH ? 932 : 437); // US codepage already initialized 01137 loaded_layout=new keyboard_layout(); 01138 01139 const char * layoutname=section->Get_string("keyboardlayout"); 01140 01141 Bits wants_dos_codepage = -1; 01142 if (!strncmp(layoutname,"auto",4)) { 01143 #if defined (WIN32) 01144 WORD cur_kb_layout = LOWORD(GetKeyboardLayout(0)); 01145 WORD cur_kb_subID = 0; 01146 char layoutID_string[KL_NAMELENGTH]; 01147 if (GetKeyboardLayoutName(layoutID_string)) { 01148 if (strlen(layoutID_string) == 8) { 01149 int cur_kb_layout_by_name = (int)ConvHexWord((char*)&layoutID_string[4]); 01150 layoutID_string[4] = 0; 01151 int subID = (int)ConvHexWord((char*)&layoutID_string[0]); 01152 if ((cur_kb_layout_by_name>0) && (cur_kb_layout_by_name<65536)) { 01153 // use layout ID extracted from the layout string 01154 cur_kb_layout = (WORD)cur_kb_layout_by_name; 01155 } 01156 if ((subID>=0) && (subID<100)) { 01157 // use sublanguage ID extracted from the layout string 01158 cur_kb_subID = (WORD)subID; 01159 } 01160 } 01161 } 01162 // try to match emulated keyboard layout with host-keyboardlayout 01163 // codepage 437 (standard) is preferred 01164 switch (cur_kb_layout) { 01165 /* case 1026: 01166 layoutname = "bg241"; 01167 break; */ 01168 case 1029: 01169 layoutname = "cz243"; 01170 break; 01171 case 1030: 01172 layoutname = "dk"; 01173 break; 01174 case 1031: 01175 layoutname = "gr"; 01176 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01177 break; 01178 case 1033: 01179 // US 01180 return; 01181 case 1032: 01182 layoutname = "gk"; 01183 break; 01184 case 1034: 01185 layoutname = "sp"; 01186 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01187 break; 01188 case 1035: 01189 layoutname = "su"; 01190 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01191 break; 01192 case 1036: 01193 layoutname = "fr"; 01194 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01195 break; 01196 case 1038: 01197 if (cur_kb_subID==1) layoutname = "hu"; 01198 else layoutname = "hu208"; 01199 break; 01200 case 1039: 01201 layoutname = "is161"; 01202 break; 01203 case 1040: 01204 layoutname = "it"; 01205 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01206 break; 01207 case 1043: 01208 layoutname = "nl"; 01209 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01210 break; 01211 case 1044: 01212 layoutname = "no"; 01213 break; 01214 case 1045: 01215 layoutname = "pl"; 01216 break; 01217 case 1046: 01218 layoutname = "br"; 01219 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01220 break; 01221 /* case 1048: 01222 layoutname = "ro446"; 01223 break; */ 01224 case 1049: 01225 layoutname = "ru"; 01226 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01227 break; 01228 case 1050: 01229 layoutname = "hr"; 01230 break; 01231 case 1051: 01232 layoutname = "sk"; 01233 break; 01234 /* case 1052: 01235 layoutname = "sq448"; 01236 break; */ 01237 case 1053: 01238 layoutname = "sv"; 01239 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01240 break; 01241 case 1055: 01242 layoutname = "tr"; 01243 break; 01244 case 1058: 01245 layoutname = "ur"; 01246 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01247 break; 01248 case 1059: 01249 layoutname = "bl"; 01250 break; 01251 case 1060: 01252 layoutname = "si"; 01253 break; 01254 case 1061: 01255 layoutname = "et"; 01256 break; 01257 /* case 1062: 01258 layoutname = "lv"; 01259 break; */ 01260 /* case 1063: 01261 layoutname = "lt221"; 01262 break; */ 01263 /* case 1064: 01264 layoutname = "tj"; 01265 break; 01266 case 1066: 01267 layoutname = "vi"; 01268 break; 01269 case 1067: 01270 layoutname = "hy"; 01271 break; */ 01272 case 2055: 01273 layoutname = "sg"; 01274 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01275 break; 01276 case 2070: 01277 layoutname = "po"; 01278 break; 01279 case 4108: 01280 layoutname = "sf"; 01281 wants_dos_codepage = (IS_PC98_ARCH ? 932 : 437); 01282 break; 01283 case 1041: 01284 layoutname = "jp"; 01285 break; 01286 default: 01287 break; 01288 } 01289 #endif 01290 } 01291 01292 bool extract_codepage = true; 01293 if (wants_dos_codepage>0) { 01294 if ((loaded_layout->read_codepage_file("auto", (Bit32s)wants_dos_codepage)) == KEYB_NOERROR) { 01295 // preselected codepage was successfully loaded 01296 extract_codepage = false; 01297 } 01298 } 01299 if (extract_codepage) { 01300 // try to find a good codepage for the requested layout 01301 Bit16u req_codepage = loaded_layout->extract_codepage(layoutname); 01302 loaded_layout->read_codepage_file("auto", req_codepage); 01303 } 01304 01305 /* if (strncmp(layoutname,"auto",4) && strncmp(layoutname,"none",4)) { 01306 LOG_MSG("Loading DOS keyboard layout %s ...",layoutname); 01307 } */ 01308 if (loaded_layout->read_keyboard_file(layoutname, dos.loaded_codepage)) { 01309 if (strncmp(layoutname,"auto",4)) { 01310 LOG_MSG("Error loading keyboard layout %s",layoutname); 01311 } 01312 } else { 01313 const char* lcode = loaded_layout->main_language_code(); 01314 if (lcode) { 01315 LOG_MSG("DOS keyboard layout loaded with main language code %s for layout %s",lcode,layoutname); 01316 } 01317 } 01318 } 01319 01320 ~DOS_KeyboardLayout(){ 01321 if ((dos.loaded_codepage!=(IS_PC98_ARCH ? 932 : 437)) && (CurMode->type==M_TEXT)) { 01322 INT10_ReloadRomFonts(); 01323 dos.loaded_codepage=(IS_PC98_ARCH ? 932 : 437); // US codepage 01324 } 01325 if (loaded_layout) { 01326 delete loaded_layout; 01327 loaded_layout=NULL; 01328 } 01329 } 01330 }; 01331 01332 static DOS_KeyboardLayout* test; 01333 01334 void DOS_KeyboardLayout_ShutDown(Section* /*sec*/) { 01335 if (test != NULL) { 01336 delete test; 01337 test = NULL; 01338 } 01339 } 01340 01341 void DOS_KeyboardLayout_Startup(Section* sec) { 01342 (void)sec;//UNUSED 01343 if (test == NULL) { 01344 LOG(LOG_MISC,LOG_DEBUG)("Reinitializing DOS keyboard layout support"); 01345 test = new DOS_KeyboardLayout(control->GetSection("dos")); 01346 } 01347 } 01348 01349 void DOS_KeyboardLayout_Init() { 01350 LOG(LOG_MISC,LOG_DEBUG)("Initializing DOS keyboard layout emulation"); 01351 01352 AddExitFunction(AddExitFunctionFuncPair(DOS_KeyboardLayout_ShutDown),true); 01353 AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(DOS_KeyboardLayout_ShutDown)); 01354 AddVMEventFunction(VM_EVENT_DOS_EXIT_BEGIN,AddVMEventFunctionFuncPair(DOS_KeyboardLayout_ShutDown)); 01355 } 01356