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 "dos_inc.h" 00021 #include "../ints/int10.h" 00022 #include <string.h> 00023 #include "inout.h" 00024 #include "shiftjis.h" 00025 #include "callback.h" 00026 00027 #define NUMBER_ANSI_DATA 10 00028 00029 extern bool DOS_BreakFlag; 00030 extern unsigned char pc98_function_row_mode; 00031 00032 Bitu INT10_Handler(void); 00033 Bitu INT16_Handler_Wrap(void); 00034 00035 bool inhibited_ControlFn(void); 00036 void pc98_function_row_user_toggle(void); 00037 void update_pc98_function_row(unsigned char setting,bool force_redraw=false); 00038 void PC98_GetFuncKeyEscape(size_t &len,unsigned char buf[16],const unsigned int i); 00039 void PC98_GetShiftFuncKeyEscape(size_t &len,unsigned char buf[16],const unsigned int i); 00040 void PC98_GetEditorKeyEscape(size_t &len,unsigned char buf[16],const unsigned int scan); 00041 void PC98_GetVFuncKeyEscape(size_t &len,unsigned char buf[16],const unsigned int i); 00042 void PC98_GetShiftVFuncKeyEscape(size_t &len,unsigned char buf[16],const unsigned int i); 00043 void PC98_GetCtrlFuncKeyEscape(size_t &len,unsigned char buf[16],const unsigned int i); 00044 void PC98_GetCtrlVFuncKeyEscape(size_t &len,unsigned char buf[16],const unsigned int i); 00045 00046 ShiftJISDecoder con_sjis; 00047 00048 Bit16u last_int16_code = 0; 00049 00050 static size_t dev_con_pos=0,dev_con_max=0; 00051 static unsigned char dev_con_readbuf[64]; 00052 00053 Bit8u DefaultANSIAttr() { 00054 return IS_PC98_ARCH ? 0xE1 : 0x07; 00055 } 00056 00057 class device_CON : public DOS_Device { 00058 public: 00059 device_CON(); 00060 bool Read(Bit8u * data,Bit16u * size); 00061 bool Write(const Bit8u * data,Bit16u * size); 00062 bool Seek(Bit32u * pos,Bit32u type); 00063 bool Close(); 00064 Bit16u GetInformation(void); 00065 bool ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { (void)bufptr; (void)size; (void)retcode; return false; } 00066 bool WriteToControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode) { (void)bufptr; (void)size; (void)retcode; return false; } 00067 bool ANSI_SYS_installed(); 00068 private: 00069 void ClearAnsi(void); 00070 void Output(Bit8u chr); 00071 Bit8u readcache; 00072 struct ansi { /* should create a constructor, which would fill them with the appropriate values */ 00073 bool installed; // ANSI.SYS is installed (and therefore escapes are handled) 00074 bool esc; 00075 bool sci; 00076 bool equcurp; // ????? ESC = Y X cursor pos (not sure if PC-98 specific or general to DOS ANSI.SYS) 00077 bool pc98rab; // PC-98 ESC [ > ... (right angle bracket) I will rename this variable if MS-DOS ANSI.SYS also supports this sequence 00078 bool enabled; 00079 Bit8u attr; // machine-specific 00080 Bit8u data[NUMBER_ANSI_DATA]; 00081 Bit8u numberofarg; 00082 Bit16u nrows; 00083 Bit16u ncols; 00084 Bit8u savecol; 00085 Bit8u saverow; 00086 bool warned; 00087 } ansi; 00088 00089 // ESC M 00090 void ESC_M(void) { 00091 LineFeedRev(); 00092 ClearAnsi(); 00093 } 00094 00095 // ESC D 00096 void ESC_D(void) { 00097 LineFeed(); 00098 ClearAnsi(); 00099 } 00100 00101 // ESC E 00102 void ESC_E(void) { 00103 Real_INT10_TeletypeOutputAttr('\n',ansi.attr,ansi.enabled); 00104 ClearAnsi(); 00105 } 00106 00107 // ESC [ A 00108 void ESC_BRACKET_A(void) { 00109 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00110 Bit8u tempdata; 00111 Bit8u col,row; 00112 00113 col=CURSOR_POS_COL(page) ; 00114 row=CURSOR_POS_ROW(page) ; 00115 tempdata = (ansi.data[0]? ansi.data[0] : 1); 00116 if(tempdata > row) { row=0; } 00117 else { row-=tempdata;} 00118 Real_INT10_SetCursorPos(row,col,page); 00119 ClearAnsi(); 00120 } 00121 00122 // ESC [ B 00123 void ESC_BRACKET_B(void) { 00124 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00125 Bit8u tempdata; 00126 Bit8u col,row; 00127 00128 col=CURSOR_POS_COL(page) ; 00129 row=CURSOR_POS_ROW(page) ; 00130 if (!IS_PC98_ARCH) 00131 ansi.nrows = real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS) + 1; 00132 tempdata = (ansi.data[0]? ansi.data[0] : 1); 00133 if(tempdata + static_cast<Bitu>(row) >= ansi.nrows) 00134 { row = ansi.nrows - 1;} 00135 else { row += tempdata; } 00136 Real_INT10_SetCursorPos(row,col,page); 00137 ClearAnsi(); 00138 } 00139 00140 // ESC [ C 00141 void ESC_BRACKET_C(void) { 00142 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00143 Bit8u tempdata; 00144 Bit8u col,row; 00145 00146 col=CURSOR_POS_COL(page); 00147 row=CURSOR_POS_ROW(page); 00148 if (!IS_PC98_ARCH) 00149 ansi.ncols = real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 00150 tempdata=(ansi.data[0]? ansi.data[0] : 1); 00151 if(tempdata + static_cast<Bitu>(col) >= ansi.ncols) 00152 { col = ansi.ncols - 1;} 00153 else { col += tempdata;} 00154 Real_INT10_SetCursorPos(row,col,page); 00155 ClearAnsi(); 00156 } 00157 00158 // ESC [ D 00159 void ESC_BRACKET_D(void) { 00160 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00161 Bit8u tempdata; 00162 Bit8u col,row; 00163 00164 col=CURSOR_POS_COL(page); 00165 row=CURSOR_POS_ROW(page); 00166 tempdata=(ansi.data[0]? ansi.data[0] : 1); 00167 if(tempdata > col) {col = 0;} 00168 else { col -= tempdata;} 00169 Real_INT10_SetCursorPos(row,col,page); 00170 ClearAnsi(); 00171 } 00172 00173 // ESC = Y X 00174 void ESC_EQU_cursor_pos(void) { 00175 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00176 00177 /* This is what the PC-98 ANSI driver does */ 00178 if(ansi.data[0] >= 0x20) ansi.data[0] -= 0x20; 00179 else ansi.data[0] = 0; 00180 if(ansi.data[1] >= 0x20) ansi.data[1] -= 0x20; 00181 else ansi.data[1] = 0; 00182 00183 if (!IS_PC98_ARCH) { 00184 ansi.ncols = real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 00185 ansi.nrows = real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS) + 1; 00186 } 00187 /* Turn them into positions that are on the screen */ 00188 if(ansi.data[0] >= ansi.nrows) ansi.data[0] = (Bit8u)ansi.nrows - 1; 00189 if(ansi.data[1] >= ansi.ncols) ansi.data[1] = (Bit8u)ansi.ncols - 1; 00190 Real_INT10_SetCursorPos(ansi.data[0],ansi.data[1],page); 00191 00192 ClearAnsi(); 00193 } 00194 00195 static void Real_INT10_SetCursorPos(Bit8u row,Bit8u col,Bit8u page) { 00196 Bit16u oldax,oldbx,olddx; 00197 00198 oldax=reg_ax; 00199 oldbx=reg_bx; 00200 olddx=reg_dx; 00201 00202 reg_ah=0x2; 00203 reg_dh=row; 00204 reg_dl=col; 00205 reg_bh=page; 00206 00207 /* FIXME: PC-98 emulation should eventually use CONIO emulation that 00208 * better emulates the actual platform. The purpose of this 00209 * hack is to allow our code to call into INT 10h without 00210 * setting up an INT 10h vector */ 00211 if (IS_PC98_ARCH) 00212 INT10_Handler(); 00213 else 00214 CALLBACK_RunRealInt(0x10); 00215 00216 reg_ax=oldax; 00217 reg_bx=oldbx; 00218 reg_dx=olddx; 00219 } 00220 00221 /* Common function to turn specific scan codes into ANSI codes. 00222 * This is a separate function so that both Read() and GetInformation() can use it. 00223 * GetInformation needs to handle the scan code on entry in order to correctly 00224 * assert whether Read() will return data or not. Some scan codes are ignored by 00225 * the CON driver, therefore even though the BIOS says there is key data, Read() 00226 * will not return anything and will block. */ 00227 bool CommonPC98ExtScanConversionToReadBuf(unsigned char code) { 00228 size_t esclen; 00229 00230 switch (code) { 00231 case 0x36: // ROLL UP 00232 case 0x37: // ROLL DOWN 00233 case 0x38: // INS 00234 case 0x39: // DEL 00235 case 0x3A: // UP ARROW 00236 case 0x3B: // LEFT ARROW 00237 case 0x3C: // RIGHT ARROW 00238 case 0x3D: // DOWN ARROW 00239 case 0x3E: // HOME/CLR 00240 case 0x3F: // HELP 00241 case 0x40: // KEYPAD - 00242 PC98_GetEditorKeyEscape(/*&*/esclen,dev_con_readbuf,code); dev_con_pos=0; dev_con_max=esclen; 00243 return (dev_con_max != 0)?true:false; 00244 case 0x52: // VF1 00245 case 0x53: // VF2 00246 case 0x54: // VF3 00247 case 0x55: // VF4 00248 case 0x56: // VF5 00249 PC98_GetVFuncKeyEscape(/*&*/esclen,dev_con_readbuf,code+1u-0x52u); dev_con_pos=0; dev_con_max=esclen; 00250 return (dev_con_max != 0)?true:false; 00251 case 0x62: // F1 00252 case 0x63: // F2 00253 case 0x64: // F3 00254 case 0x65: // F4 00255 case 0x66: // F5 00256 case 0x67: // F6 00257 case 0x68: // F7 00258 case 0x69: // F8 00259 case 0x6A: // F9 00260 case 0x6B: // F10 00261 PC98_GetFuncKeyEscape(/*&*/esclen,dev_con_readbuf,code+1u-0x62u); dev_con_pos=0; dev_con_max=esclen; 00262 return (dev_con_max != 0)?true:false; 00263 case 0x82: // Shift+F1 00264 case 0x83: // Shift+F2 00265 case 0x84: // Shift+F3 00266 case 0x85: // Shift+F4 00267 case 0x86: // Shift+F5 00268 case 0x87: // Shift+F6 00269 case 0x88: // Shift+F7 00270 case 0x89: // Shift+F8 00271 case 0x8A: // Shift+F9 00272 case 0x8B: // Shift+F10 00273 PC98_GetShiftFuncKeyEscape(/*&*/esclen,dev_con_readbuf,code+1u-0x82u); dev_con_pos=0; dev_con_max=esclen; 00274 return (dev_con_max != 0)?true:false; 00275 case 0x92: // Control+F1 00276 case 0x93: // Control+F2 00277 case 0x94: // Control+F3 00278 case 0x95: // Control+F4 00279 case 0x96: // Control+F5 00280 case 0x97: // Control+F6 00281 case 0x98: // Control+F7 00282 case 0x99: // Control+F8 00283 case 0x9A: // Control+F9 00284 case 0x9B: // Control+F10 00285 if (inhibited_ControlFn()) { 00286 PC98_GetCtrlFuncKeyEscape(/*&*/esclen,dev_con_readbuf,code+1u-0x92u); dev_con_pos=0; dev_con_max=esclen; 00287 return (dev_con_max != 0)?true:false; 00288 } 00289 else if (code == 0x97) {// CTRL+F6 Toggle 20/25-line text HANDLED INTERNALLY, NEVER RETURNED TO CONSOLE 00290 /* toggle the bit and change the text layer */ 00291 { 00292 Bit8u b = real_readb(0x60,0x113); 00293 real_writeb(0x60,0x113,b ^ 1); 00294 00295 reg_ah = 0x0A; /* Set CRT mode */ 00296 reg_al = b; 00297 CALLBACK_RunRealInt(0x18); 00298 00299 reg_ah = 0x11; /* show cursor (Func 0x0A hides the cursor) */ 00300 CALLBACK_RunRealInt(0x18); 00301 } 00302 00303 /* clear the screen */ 00304 { 00305 Bit8u page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00306 00307 /* it also redraws the function key row */ 00308 update_pc98_function_row(pc98_function_row_mode,true); 00309 00310 INT10_ScrollWindow(0,0,255,255,0,ansi.attr,page); 00311 Real_INT10_SetCursorPos(0,0,page); 00312 } 00313 } 00314 else if (code == 0x98) {// CTRL+F7 Toggle function key row HANDLED INTERNALLY, NEVER RETURNED TO CONSOLE 00315 void pc98_function_row_user_toggle(void); 00316 pc98_function_row_user_toggle(); 00317 } 00318 else if (code == 0x99) {// CTRL+F8 Clear screen, home cursor HANDLED INTERNALLY, NEVER RETURNED TO CONSOLE 00319 Bit8u page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00320 00321 /* it also redraws the function key row */ 00322 update_pc98_function_row(pc98_function_row_mode,true); 00323 00324 INT10_ScrollWindow(0,0,255,255,0,ansi.attr,page); 00325 Real_INT10_SetCursorPos(0,0,page); 00326 ClearAnsi(); 00327 } 00328 break; 00329 00330 case 0xC2: // VF1 00331 case 0xC3: // VF2 00332 case 0xC4: // VF3 00333 case 0xC5: // VF4 00334 case 0xC6: // VF5 00335 PC98_GetShiftVFuncKeyEscape(/*&*/esclen,dev_con_readbuf,code+1u-0xC2u); dev_con_pos=0; dev_con_max=esclen; 00336 return (dev_con_max != 0)?true:false; 00337 00338 case 0xD2: // VF1 00339 case 0xD3: // VF2 00340 case 0xD4: // VF3 00341 case 0xD5: // VF4 00342 case 0xD6: // VF5 00343 if (inhibited_ControlFn()) { 00344 PC98_GetCtrlVFuncKeyEscape(/*&*/esclen,dev_con_readbuf,code+1u-0xD2u); dev_con_pos=0; dev_con_max=esclen; 00345 return (dev_con_max != 0)?true:false; 00346 } 00347 break; 00348 #if 0 00349 // ROLL UP -- -- -- 00350 // POLL DOWN-- -- -- 00351 // COPY -- -- -- 00352 // HOME/CLR 0x1A 0x1E -- 00353 // HELP -- -- -- 00354 #endif 00355 } 00356 00357 return false; 00358 } 00359 00360 static void Real_INT10_TeletypeOutput(Bit8u xChar,Bit8u xAttr) { 00361 if (IS_PC98_ARCH) { 00362 if (con_sjis.take(xChar)) { 00363 BIOS_NCOLS; 00364 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00365 Bit8u cur_row=CURSOR_POS_ROW(page); 00366 Bit8u cur_col=CURSOR_POS_COL(page); 00367 unsigned char cw = con_sjis.doublewide ? 2 : 1; 00368 00369 /* FIXME: I'm not sure what NEC's ANSI driver does if a doublewide character is printed at column 79 */ 00370 if ((cur_col+cw) > ncols) { 00371 cur_col = (Bit8u)ncols; 00372 AdjustCursorPosition(cur_col,cur_row); 00373 } 00374 00375 /* JIS conversion to WORD value appropriate for text RAM */ 00376 if (con_sjis.b2 != 0) con_sjis.b1 -= 0x20; 00377 00378 INT10_WriteChar((con_sjis.b2 << 8) + con_sjis.b1,xAttr,0,1,true); 00379 00380 cur_col += cw; 00381 AdjustCursorPosition(cur_col,cur_row); 00382 Real_INT10_SetCursorPos(cur_row,cur_col,page); 00383 } 00384 } 00385 else { 00386 Bit16u oldax,oldbx; 00387 oldax=reg_ax; 00388 oldbx=reg_bx; 00389 00390 reg_ah=0xE; 00391 reg_al=xChar; 00392 reg_bl=xAttr; 00393 00394 CALLBACK_RunRealInt(0x10); 00395 00396 reg_ax=oldax; 00397 reg_bx=oldbx; 00398 } 00399 } 00400 00401 00402 static void Real_WriteChar(Bit8u cur_col,Bit8u cur_row, 00403 Bit8u page,Bit8u chr,Bit8u attr,Bit8u useattr) { 00404 //Cursor position 00405 Real_INT10_SetCursorPos(cur_row,cur_col,page); 00406 00407 //Write the character 00408 Bit16u oldax,oldbx,oldcx; 00409 oldax=reg_ax; 00410 oldbx=reg_bx; 00411 oldcx=reg_cx; 00412 00413 reg_al=chr; 00414 reg_bl=attr; 00415 reg_bh=page; 00416 reg_cx=1; 00417 if(useattr) 00418 reg_ah=0x9; 00419 else reg_ah=0x0A; 00420 00421 /* FIXME: PC-98 emulation should eventually use CONIO emulation that 00422 * better emulates the actual platform. The purpose of this 00423 * hack is to allow our code to call into INT 10h without 00424 * setting up an INT 10h vector */ 00425 if (IS_PC98_ARCH) 00426 INT10_Handler(); 00427 else 00428 CALLBACK_RunRealInt(0x10); 00429 00430 reg_ax=oldax; 00431 reg_bx=oldbx; 00432 reg_cx=oldcx; 00433 }//static void Real_WriteChar(cur_col,cur_row,page,chr,attr,useattr) 00434 00435 static void LineFeedRev(void) { // ESC M 00436 BIOS_NCOLS;BIOS_NROWS; 00437 auto defattr = DefaultANSIAttr(); 00438 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00439 Bit8u cur_row=CURSOR_POS_ROW(page); 00440 Bit8u cur_col=CURSOR_POS_COL(page); 00441 00442 if(cur_row==0) 00443 { 00444 INT10_ScrollWindow(0,0,(Bit8u)(nrows-1),(Bit8u)(ncols-1),1,defattr,0); 00445 } 00446 else { 00447 cur_row--; 00448 } 00449 00450 Real_INT10_SetCursorPos(cur_row,cur_col,page); 00451 } 00452 00453 static void LineFeed(void) { // ESC D 00454 BIOS_NCOLS;BIOS_NROWS; 00455 auto defattr = DefaultANSIAttr(); 00456 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00457 Bit8u cur_row=CURSOR_POS_ROW(page); 00458 Bit8u cur_col=CURSOR_POS_COL(page); 00459 00460 if (cur_row < nrows) cur_row++; 00461 00462 if(cur_row==nrows) 00463 { 00464 INT10_ScrollWindow(0,0,(Bit8u)(nrows-1),(Bit8u)(ncols-1),-1,defattr,0); 00465 cur_row--; 00466 } 00467 00468 Real_INT10_SetCursorPos(cur_row,cur_col,page); 00469 } 00470 00471 static void AdjustCursorPosition(Bit8u& cur_col,Bit8u& cur_row) { 00472 BIOS_NCOLS;BIOS_NROWS; 00473 auto defattr = DefaultANSIAttr(); 00474 //Need a new line? 00475 if(cur_col==ncols) 00476 { 00477 cur_col=0; 00478 cur_row++; 00479 00480 if (!IS_PC98_ARCH) 00481 Real_INT10_TeletypeOutput('\r',defattr); 00482 } 00483 00484 //Reached the bottom? 00485 if(cur_row==nrows) 00486 { 00487 if (IS_PC98_ARCH) 00488 INT10_ScrollWindow(0,0,(Bit8u)(nrows-1),(Bit8u)(ncols-1),-1,defattr,0); 00489 else 00490 Real_INT10_TeletypeOutput('\n',defattr); //Scroll up 00491 00492 cur_row--; 00493 } 00494 } 00495 00496 00497 void Real_INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr) { 00498 //TODO Check if this page thing is correct 00499 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00500 // BIOS_NCOLS;BIOS_NROWS; 00501 Bit8u cur_row=CURSOR_POS_ROW(page); 00502 Bit8u cur_col=CURSOR_POS_COL(page); 00503 switch (chr) 00504 { 00505 case 7: { 00506 // set timer (this should not be needed as the timer already is programmed 00507 // with those values, but the speaker stays silent without it) 00508 IO_Write(0x43,0xb6); 00509 IO_Write(0x42,1320&0xff); 00510 IO_Write(0x42,1320>>8); 00511 // enable speaker 00512 IO_Write(0x61,IO_Read(0x61)|0x3); 00513 for(Bitu i=0; i < 333; i++) CALLBACK_Idle(); 00514 IO_Write(0x61,IO_Read(0x61)&~0x3); 00515 break; 00516 } 00517 case 8: 00518 if(cur_col>0) 00519 cur_col--; 00520 break; 00521 case '\r': 00522 cur_col=0; 00523 break; 00524 case '\n': 00525 cur_col=0; 00526 cur_row++; 00527 break; 00528 case '\t': 00529 do { 00530 Real_INT10_TeletypeOutputAttr(' ',attr,useattr); 00531 cur_row=CURSOR_POS_ROW(page); 00532 cur_col=CURSOR_POS_COL(page); 00533 } while(cur_col%8); 00534 break; 00535 default: 00536 //* Draw the actual Character 00537 if (IS_PC98_ARCH) { 00538 if (con_sjis.take(chr)) { 00539 BIOS_NCOLS; 00540 unsigned char cw = con_sjis.doublewide ? 2 : 1; 00541 00542 /* FIXME: I'm not sure what NEC's ANSI driver does if a doublewide character is printed at column 79 */ 00543 if ((cur_col+cw) > ncols) { 00544 cur_col = (Bit8u)ncols; 00545 AdjustCursorPosition(cur_col,cur_row); 00546 } 00547 00548 /* JIS conversion to WORD value appropriate for text RAM */ 00549 if (con_sjis.b2 != 0) con_sjis.b1 -= 0x20; 00550 00551 INT10_WriteChar((con_sjis.b2 << 8) + con_sjis.b1,attr,0,1,true); 00552 00553 cur_col += cw; 00554 } 00555 } 00556 else { 00557 Real_WriteChar(cur_col,cur_row,page,chr,attr,useattr); 00558 cur_col++; 00559 } 00560 } 00561 00562 AdjustCursorPosition(cur_col,cur_row); 00563 Real_INT10_SetCursorPos(cur_row,cur_col,page); 00564 }//void Real_INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr) 00565 public: 00566 // INT DC interface: CL=0x10 AH=0x03 00567 void INTDC_CL10h_AH03h(Bit16u raw) { 00568 /* NTS: This emulates translation behavior seen in INT DCh interface: 00569 * 00570 * DX = raw 00571 * DX += 0x2020 00572 * XCHG DL, DH 00573 * CX = DX 00574 * CALL "ESC = HANDLING CODE" 00575 * 00576 * Technically this means there is a bug where if DL(X) is 0xE0 or larger it will carry into DH(Y) */ 00577 raw += 0x2020; 00578 00579 ansi.data[0] = (raw >> 8); // Y 00580 ansi.data[1] = raw & 0xFF; // X 00581 ESC_EQU_cursor_pos(); 00582 } 00583 00584 void INTDC_CL10h_AH04h(void) { 00585 ESC_D(); 00586 } 00587 00588 void INTDC_CL10h_AH05h(void) { 00589 ESC_M(); 00590 } 00591 00592 void INTDC_CL10h_AH06h(Bit16u count) { 00593 ansi.data[0] = (Bit8u)count; /* truncation is deliberate, just like the actual ANSI driver */ 00594 ESC_BRACKET_A(); 00595 } 00596 00597 void INTDC_CL10h_AH07h(Bit16u count) { 00598 ansi.data[0] = (Bit8u)count; /* truncation is deliberate, just like the actual ANSI driver */ 00599 ESC_BRACKET_B(); 00600 } 00601 00602 void INTDC_CL10h_AH08h(Bit16u count) { 00603 ansi.data[0] = (Bit8u)count; /* truncation is deliberate, just like the actual ANSI driver */ 00604 ESC_BRACKET_C(); 00605 } 00606 00607 void INTDC_CL10h_AH09h(Bit16u count) { 00608 ansi.data[0] = (Bit8u)count; /* truncation is deliberate, just like the actual ANSI driver */ 00609 ESC_BRACKET_D(); 00610 } 00611 00612 }; 00613 00614 // NEC-PC98 keyboard input notes 00615 // 00616 // on a system with KKCFUNC.SYS, NECAIK1.SYS, NECAIK2.SYS, NECAI.SYS loaded 00617 // 00618 // Key Normal Shift CTRL 00619 // ------------------------------------- 00620 // ESC 0x1B 0x1B 0x1B 00621 // TAB 0x09 0x09 0x09 00622 // F1 0x1B 0x53 <shortcut> -- 00623 // F2 0x1B 0x54 <shortcut> -- 00624 // F3 0x1B 0x55 <shortcut> -- 00625 // F4 0x1B 0x56 <shortcut> Toggles 'g' 00626 // F5 0x1B 0x57 <shortcut> -- 00627 // F6 0x1B 0x45 <shortcut> Toggle 20/25-line text mode 00628 // F7 0x1B 0x4A <shortcut> Toggle function row (C1/CU/etc, shortcuts, or off) 00629 // F8 0x1B 0x50 <shortcut> Clear screen, home cursor 00630 // F9 0x1B 0x51 <shortcut> -- 00631 // F10 0x1B 0x5A <shortcut> -- 00632 // INS 0x1B 0x50 0x1B 0x50 0x1B 0x50 00633 // DEL 0x1B 0x44 0x1B 0x44 0x1B 0x44 00634 // ROLL UP -- -- -- 00635 // POLL DOWN-- -- -- 00636 // COPY -- -- -- 00637 // HOME/CLR 0x1A 0x1E -- 00638 // HELP -- -- -- 00639 // UP ARROW 0x0B 0x0B 0x0B 00640 // LF ARROW 0x08 0x08 0x08 00641 // RT ARROW 0x0C 0x0C 0x0C 00642 // DN ARROW 0x0A 0x0A 0x0A 00643 // VF1 -- -- -- 00644 // VF2 -- -- -- 00645 // VF3 -- -- -- 00646 // VF4 -- -- -- 00647 // VF5 -- -- -- 00648 00649 // TODO for PC-98 mode: 00650 // 00651 // According to: 00652 // 00653 // http://hackipedia.org/browse.cgi/Computer/Platform/PC%2c%20NEC%20PC%2d98/Collections/PC%2d9801%20Bible%20%e6%9d%b1%e4%ba%ac%e7%90%86%e7%a7%91%e5%a4%a7%e5%ad%a6EIC%20%281994%29%2epdf 00654 // 00655 // Section 4-8. 00656 // 00657 // The PDF documents ANSI codes defined on PC-98, which may or may not be a complete listing. 00658 00659 bool device_CON::Read(Bit8u * data,Bit16u * size) { 00660 Bit16u oldax=reg_ax; 00661 Bit16u count=0; 00662 auto defattr=DefaultANSIAttr(); 00663 INT10_SetCurMode(); 00664 if ((readcache) && (*size)) { 00665 data[count++]=readcache; 00666 if(dos.echo) Real_INT10_TeletypeOutput(readcache,defattr); 00667 readcache=0; 00668 } 00669 while (*size>count) { 00670 if (dev_con_pos < dev_con_max) { 00671 data[count++] = (Bit8u)dev_con_readbuf[dev_con_pos++]; 00672 continue; 00673 } 00674 00675 reg_ah=(IS_EGAVGA_ARCH)?0x10:0x0; 00676 00677 /* FIXME: PC-98 emulation should eventually use CONIO emulation that 00678 * better emulates the actual platform. The purpose of this 00679 * hack is to allow our code to call into INT 16h without 00680 * setting up an INT 16h vector */ 00681 if (IS_PC98_ARCH) 00682 INT16_Handler_Wrap(); 00683 else 00684 CALLBACK_RunRealInt(0x16); 00685 00686 /* hack for DOSKEY emulation */ 00687 last_int16_code = reg_ax; 00688 00689 switch(reg_al) { 00690 case 13: 00691 data[count++]=0x0D; 00692 if (*size>count) data[count++]=0x0A; // it's only expanded if there is room for it. (NO cache) 00693 *size=count; 00694 reg_ax=oldax; 00695 if(dos.echo) { 00696 Real_INT10_TeletypeOutput(13,defattr); //maybe don't do this ( no need for it actually ) (but it's compatible) 00697 Real_INT10_TeletypeOutput(10,defattr); 00698 } 00699 return true; 00700 break; 00701 case 8: 00702 if(*size==1) data[count++]=reg_al; //one char at the time so give back that BS 00703 else if(count) { //Remove data if it exists (extended keys don't go right) 00704 data[count--]=0; 00705 Real_INT10_TeletypeOutput(8,defattr); 00706 Real_INT10_TeletypeOutput(' ',defattr); 00707 } else { 00708 continue; //no data read yet so restart whileloop. 00709 } 00710 break; 00711 case 0xe0: /* Extended keys in the int 16 0x10 case */ 00712 if(!reg_ah) { /*extended key if reg_ah isn't 0 */ 00713 data[count++] = reg_al; 00714 } else { 00715 data[count++] = 0; 00716 if (*size>count) data[count++] = reg_ah; 00717 else readcache = reg_ah; 00718 } 00719 break; 00720 case 0: /* Extended keys in the int 16 0x0 case */ 00721 if (IS_PC98_ARCH) { 00722 /* PC-98 does NOT return scan code, but instead returns nothing or 00723 * control/escape code */ 00724 CommonPC98ExtScanConversionToReadBuf(reg_ah); 00725 } 00726 else { 00727 /* IBM PC/XT/AT signals extended code by entering AL, AH. 00728 * Arrow keys for example become 0x00 0x48, 0x00 0x50, etc. */ 00729 data[count++]=reg_al; 00730 if (*size>count) data[count++]=reg_ah; 00731 else readcache=reg_ah; 00732 } 00733 break; 00734 default: 00735 data[count++]=reg_al; 00736 if (*size > 1 && reg_al == 3) 00737 { 00738 dos.errorcode=77; 00739 *size=count; 00740 reg_ax=oldax; 00741 return false; 00742 } 00743 break; 00744 } 00745 if(dos.echo) { //what to do if *size==1 and character is BS ????? 00746 // TODO: If CTRL+C checking is applicable do not echo (reg_al == 3) 00747 Real_INT10_TeletypeOutput(reg_al,defattr); 00748 } 00749 } 00750 dos.errorcode=0; 00751 *size=count; 00752 reg_ax=oldax; 00753 return true; 00754 } 00755 00756 bool log_dev_con = false; 00757 std::string log_dev_con_str; 00758 00759 bool device_CON::Write(const Bit8u * data,Bit16u * size) { 00760 Bit16u count=0; 00761 Bitu i; 00762 Bit8u col,row,page; 00763 00764 INT10_SetCurMode(); 00765 00766 if (IS_PC98_ARCH) { 00767 ansi.enabled = true; // ANSI is enabled at all times 00768 ansi.attr = mem_readb(0x71D); // 60:11D 00769 } 00770 00771 while (*size>count) { 00772 if (log_dev_con) { 00773 if (log_dev_con_str.size() >= 255 || data[count] == '\n' || data[count] == 27) { 00774 LOG_MSG("DOS CON: %s",log_dev_con_str.c_str()); 00775 log_dev_con_str.clear(); 00776 } 00777 00778 if (data[count] != '\n' && data[count] != '\r') 00779 log_dev_con_str += (char)data[count]; 00780 } 00781 00782 if (!ansi.esc){ 00783 if(data[count]=='\033' && ansi.installed) { 00784 /*clear the datastructure */ 00785 ClearAnsi(); 00786 /* start the sequence */ 00787 ansi.esc=true; 00788 count++; 00789 continue; 00790 } else if(data[count] == '\t' && !dos.direct_output) { 00791 /* expand tab if not direct output */ 00792 page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00793 do { 00794 Output(' '); 00795 col=CURSOR_POS_COL(page); 00796 } while(col%8); 00797 count++; 00798 continue; 00799 } else if (data[count] == 0x1A && IS_PC98_ARCH) { 00800 page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00801 00802 /* it also redraws the function key row */ 00803 update_pc98_function_row(pc98_function_row_mode,true); 00804 00805 INT10_ScrollWindow(0,0,255,255,0,ansi.attr,page); 00806 Real_INT10_SetCursorPos(0,0,page); 00807 } else if (data[count] == 0x1E && IS_PC98_ARCH) { 00808 page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00809 00810 Real_INT10_SetCursorPos(0,0,page); 00811 } else { 00812 Output(data[count]); 00813 count++; 00814 continue; 00815 } 00816 } 00817 00818 if(!ansi.sci){ 00819 00820 switch(data[count]){ 00821 case '[': 00822 ansi.sci=true; 00823 break; 00824 case '*':/* PC-98: clear screen (same code path as CTRL+Z) */ 00825 if (IS_PC98_ARCH) { 00826 page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00827 00828 /* it also redraws the function key row */ 00829 update_pc98_function_row(pc98_function_row_mode,true); 00830 00831 INT10_ScrollWindow(0,0,255,255,0,ansi.attr,page); 00832 Real_INT10_SetCursorPos(0,0,page); 00833 ClearAnsi(); 00834 } 00835 else { 00836 LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: unknown char %c after a esc",data[count]); /*prob () */ 00837 ClearAnsi(); 00838 } 00839 break; 00840 case 'D':/* cursor DOWN (with scrolling) */ 00841 ESC_D(); 00842 break; 00843 case 'E':/* cursor DOWN, carriage return (with scrolling) */ 00844 ESC_E(); 00845 break; 00846 case 'M':/* cursor UP (with scrolling) */ 00847 ESC_M(); 00848 break; 00849 case '=':/* cursor position */ 00850 ansi.equcurp=true; 00851 ansi.sci=true; 00852 break; 00853 case '7': /* save cursor pos + attr TODO */ 00854 case '8': /* restore this TODO */ 00855 default: 00856 LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: unknown char %c after a esc",data[count]); /*prob () */ 00857 ClearAnsi(); 00858 break; 00859 } 00860 count++; 00861 continue; 00862 } 00863 /*ansi.esc and ansi.sci are true */ 00864 if (!dos.internal_output) ansi.enabled=true; 00865 page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00866 if (ansi.equcurp) { /* proprietary ESC = Y X command */ 00867 ansi.data[ansi.numberofarg++] = data[count]; 00868 if (ansi.numberofarg >= 2) { 00869 ESC_EQU_cursor_pos(); /* clears ANSI state */ 00870 } 00871 } 00872 else if (isdigit(data[count])) { 00873 assert(ansi.numberofarg < NUMBER_ANSI_DATA); 00874 ansi.data[ansi.numberofarg]=10*ansi.data[ansi.numberofarg]+(data[count]-'0'); 00875 } 00876 else if (data[count] == ';') { 00877 if ((ansi.numberofarg+1) < NUMBER_ANSI_DATA) 00878 ansi.numberofarg++; 00879 } 00880 else if (ansi.pc98rab) { 00881 assert(IS_PC98_ARCH); 00882 00883 switch(data[count]){ 00884 case 'h': /* SET MODE (if code =7 enable linewrap) */ 00885 case 'l': /* RESET MODE */ 00886 switch (ansi.data[0]) { 00887 case 1: // show/hide function key row 00888 update_pc98_function_row(data[count] == 'l'); 00889 ansi.nrows = real_readb(0x60,0x112)+1; 00890 break; 00891 case 3: // clear screen (doesn't matter if l or h) 00892 INT10_ScrollWindow(0,0,255,255,0,ansi.attr,page); 00893 Real_INT10_SetCursorPos(0,0,page); 00894 break; 00895 case 5: // show/hide cursor 00896 void PC98_show_cursor(bool show); 00897 PC98_show_cursor(data[count] == 'l'); 00898 mem_writeb(0x71B,data[count] == 'l' ? 0x01 : 0x00); /* 60:11B cursor display state */ 00899 break; 00900 default: 00901 LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: unhandled esc [ > %d %c",ansi.data[0],data[count]); 00902 break; 00903 }; 00904 00905 ClearAnsi(); 00906 break; 00907 default: 00908 LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: unhandled char %c in esc [ >",data[count]); 00909 ClearAnsi(); 00910 break; 00911 } 00912 } 00913 else { 00914 switch(data[count]){ 00915 case 'm': /* SGR */ 00916 // NEC's ANSI driver always resets at the beginning 00917 if(IS_PC98_ARCH) { 00918 ansi.attr = DefaultANSIAttr(); 00919 } 00920 for(i=0;i<=ansi.numberofarg;i++){ 00921 const Bit8u COLORFLAGS[][8] = { 00922 // Black Red Green Yellow Blue Pink Cyan White 00923 { 0x0, 0x4, 0x2, 0x6, 0x1, 0x5, 0x3, 0x7 }, /* IBM */ 00924 { 0x0, 0x40, 0x80, 0xC0, 0x20, 0x60, 0xA0, 0xE0 }, /* PC-98 */ 00925 }; 00926 const auto &flagset = COLORFLAGS[IS_PC98_ARCH]; 00927 00928 if(IS_PC98_ARCH) { 00929 // Convert alternate color codes to regular ones 00930 if(ansi.data[i] >= 17 && ansi.data[i] <= 23) { 00931 const Bit8u convtbl[] = { 00932 31, 34, 35, 32, 33, 36, 37 00933 }; 00934 ansi.data[i] = convtbl[ansi.data[i] - 17]; 00935 } 00936 } 00937 00938 switch(ansi.data[i]){ 00939 case 0: /* normal */ 00940 //Real ansi does this as well. (should do current defaults) 00941 ansi.attr = DefaultANSIAttr(); 00942 break; 00943 case 1: /* bold mode on*/ 00944 // FIXME: According to http://www.ninton.co.jp/?p=11, this 00945 // should set some sort of "highlight" flag in monochrome 00946 // mode, but I have no idea how to even enter that mode. 00947 ansi.attr |= IS_PC98_ARCH ? 0 : 0x08; 00948 break; 00949 case 2: /* PC-98 "Bit 4" */ 00950 ansi.attr |= IS_PC98_ARCH ? 0x10 : 0; 00951 break; 00952 case 4: /* underline */ 00953 if(IS_PC98_ARCH) { 00954 ansi.attr |= 0x08; 00955 } else { 00956 LOG(LOG_IOCTL, LOG_NORMAL)("ANSI:no support for underline yet"); 00957 } 00958 break; 00959 case 5: /* blinking */ 00960 ansi.attr |= IS_PC98_ARCH ? 0x02 : 0x80; 00961 break; 00962 case 7: /* reverse */ 00963 //Just like real ansi. (should do use current colors reversed) 00964 if(IS_PC98_ARCH) { 00965 ansi.attr |= 0x04; 00966 } else { 00967 ansi.attr = 0x70; 00968 } 00969 break; 00970 case 8: /* PC-98 secret */ 00971 case 16: 00972 ansi.attr &= IS_PC98_ARCH ? 0xFE : 0xFF; 00973 break; 00974 case 30: /* fg color black */ 00975 case 31: /* fg color red */ 00976 case 32: /* fg color green */ 00977 case 33: /* fg color yellow */ 00978 case 34: /* fg color blue */ 00979 case 35: /* fg color magenta */ 00980 case 36: /* fg color cyan */ 00981 case 37: /* fg color white */ 00982 ansi.attr &= ~(flagset[7]); 00983 ansi.attr |= (flagset[ansi.data[i] - 30]); 00984 break; 00985 case 40: 00986 case 41: 00987 case 42: 00988 case 43: 00989 case 44: 00990 case 45: 00991 case 46: 00992 case 47: { 00993 Bit8u shift = IS_PC98_ARCH ? 0 : 4; 00994 ansi.attr &= ~(flagset[7] << shift); 00995 ansi.attr |= (flagset[ansi.data[i] - 40] << shift); 00996 ansi.attr |= IS_PC98_ARCH ? 0x04 : 0; 00997 break; 00998 } 00999 default: 01000 break; 01001 } 01002 } 01003 if (IS_PC98_ARCH) mem_writeb(0x71D,ansi.attr); // 60:11D 01004 ClearAnsi(); 01005 break; 01006 case 'f': 01007 case 'H':/* Cursor Pos*/ 01008 if(!ansi.warned) { //Inform the debugger that ansi is used. 01009 ansi.warned = true; 01010 LOG(LOG_IOCTL,LOG_WARN)("ANSI SEQUENCES USED"); 01011 } 01012 if (!IS_PC98_ARCH) { 01013 ansi.ncols = real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 01014 ansi.nrows = real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS) + 1; 01015 } 01016 /* Turn them into positions that are on the screen */ 01017 if(ansi.data[0] == 0) ansi.data[0] = 1; 01018 if(ansi.data[1] == 0) ansi.data[1] = 1; 01019 if(ansi.data[0] > ansi.nrows) ansi.data[0] = (Bit8u)ansi.nrows; 01020 if(ansi.data[1] > ansi.ncols) ansi.data[1] = (Bit8u)ansi.ncols; 01021 Real_INT10_SetCursorPos(--(ansi.data[0]),--(ansi.data[1]),page); /*ansi=1 based, int10 is 0 based */ 01022 ClearAnsi(); 01023 break; 01024 /* cursor up down and forward and backward only change the row or the col not both */ 01025 case 'A': /* cursor up*/ 01026 ESC_BRACKET_A(); 01027 break; 01028 case 'B': /*cursor Down */ 01029 ESC_BRACKET_B(); 01030 break; 01031 case 'C': /*cursor forward */ 01032 ESC_BRACKET_C(); 01033 break; 01034 case 'D': /*Cursor Backward */ 01035 ESC_BRACKET_D(); 01036 break; 01037 case 'J': /*erase screen and move cursor home*/ 01038 if(ansi.data[0]==0) ansi.data[0]=2; 01039 if(ansi.data[0]!=2) {/* every version behaves like type 2 */ 01040 LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: esc[%dJ called : not supported handling as 2",ansi.data[0]); 01041 } 01042 INT10_ScrollWindow(0,0,255,255,0,ansi.attr,page); 01043 ClearAnsi(); 01044 Real_INT10_SetCursorPos(0,0,page); 01045 break; 01046 case 'h': /* SET MODE (if code =7 enable linewrap) */ 01047 case 'I': /* RESET MODE */ 01048 LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: set/reset mode called(not supported)"); 01049 ClearAnsi(); 01050 break; 01051 case 'u': /* Restore Cursor Pos */ 01052 Real_INT10_SetCursorPos(ansi.saverow,ansi.savecol,page); 01053 ClearAnsi(); 01054 break; 01055 case 's': /* SAVE CURSOR POS */ 01056 ansi.savecol=CURSOR_POS_COL(page); 01057 ansi.saverow=CURSOR_POS_ROW(page); 01058 ClearAnsi(); 01059 break; 01060 case 'K': /* erase till end of line (don't touch cursor) */ 01061 col = CURSOR_POS_COL(page); 01062 row = CURSOR_POS_ROW(page); 01063 if (!IS_PC98_ARCH) { 01064 ansi.ncols = real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 01065 } 01066 INT10_WriteChar(' ',ansi.attr,page,ansi.ncols-col,true); //Real_WriteChar(ansi.ncols-col,row,page,' ',ansi.attr,true); 01067 01068 //for(i = col;i<(Bitu) ansi.ncols; i++) INT10_TeletypeOutputAttr(' ',ansi.attr,true); 01069 Real_INT10_SetCursorPos(row,col,page); 01070 ClearAnsi(); 01071 break; 01072 case 'M': /* delete line (NANSI) */ 01073 row = CURSOR_POS_ROW(page); 01074 if (!IS_PC98_ARCH) { 01075 ansi.ncols = real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 01076 ansi.nrows = real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS) + 1; 01077 } 01078 INT10_ScrollWindow(row,0,ansi.nrows-1,ansi.ncols-1,ansi.data[0]? -ansi.data[0] : -1,ansi.attr,0xFF); 01079 ClearAnsi(); 01080 break; 01081 case '>':/* proprietary NEC PC-98 MS-DOS codes (??) */ 01082 if (IS_PC98_ARCH) { 01083 ansi.pc98rab = true; 01084 } 01085 else { 01086 LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: ESC [ > not supported outside PC-98 mode"); 01087 ClearAnsi(); 01088 } 01089 break; 01090 case 'l':/* (if code =7) disable linewrap */ 01091 case 'p':/* reassign keys (needs strings) */ 01092 case 'i':/* printer stuff */ 01093 default: 01094 LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: unhandled char %c in esc[",data[count]); 01095 ClearAnsi(); 01096 break; 01097 } 01098 } 01099 count++; 01100 } 01101 *size=count; 01102 return true; 01103 } 01104 01105 bool device_CON::Seek(Bit32u * pos,Bit32u type) { 01106 (void)pos; // UNUSED 01107 (void)type; // UNUSED 01108 // seek is valid 01109 *pos = 0; 01110 return true; 01111 } 01112 01113 bool device_CON::Close() { 01114 return true; 01115 } 01116 01117 extern bool dos_con_use_int16_to_detect_input; 01118 01119 Bit16u device_CON::GetInformation(void) { 01120 if (dos_con_use_int16_to_detect_input || IS_PC98_ARCH) { 01121 Bit16u ret = 0x80D3; /* No Key Available */ 01122 01123 /* DOSBox-X behavior: Use INT 16h AH=0x11 Query keyboard status/preview key. 01124 * The reason we do this is some DOS programs actually rely on hooking INT 16h 01125 * to manipulate, hide, or transform what the DOS CON driver sees as well as 01126 * itself. Perhaps the most disgusting example of this behavior would be the 01127 * SCANDISK.EXE utility in Microsoft MS-DOS 6.22, which apparently relies on 01128 * hooking INT 16h in this way to catch the Escape, CTRL+C, and some other 01129 * scan codes in order to "eat" the scan codes before they get back to DOS. 01130 * The reason they can get away with it apparently and still respond properly 01131 * to those keys, is because the MS-DOS 6.22 CON driver always calls INT 16h 01132 * AH=0x11 first before calling INT 16h AH=0x10 to fetch the scan code. 01133 * 01134 * Without this fix, SCANDISK.EXE does not respond properly to Escape and 01135 * a few other keys. Pressing Escape will do nothing until you hit any other 01136 * key, at which point it suddenly acts upon the Escape key. 01137 * 01138 * Since Scandisk is using INT 21h AH=0x0B to query STDIN during this time, 01139 * this implementation is a good "halfway" compromise in that this call 01140 * will trigger the INT 16h AH=0x11 hook it relies on. */ 01141 if (readcache || dev_con_pos < dev_con_max) return 0x8093; /* key available */ 01142 01143 Bit16u saved_ax = reg_ax; 01144 01145 reg_ah = (IS_EGAVGA_ARCH)?0x11:0x1; // check for keystroke 01146 01147 /* FIXME: PC-98 emulation should eventually use CONIO emulation that 01148 * better emulates the actual platform. The purpose of this 01149 * hack is to allow our code to call into INT 16h without 01150 * setting up an INT 16h vector */ 01151 if (IS_PC98_ARCH) 01152 INT16_Handler_Wrap(); 01153 else 01154 CALLBACK_RunRealInt(0x16); 01155 01156 if (!GETFLAG(ZF)) { /* key is present, waiting to be returned on AH=0x10 or AH=0x00 */ 01157 if (IS_PC98_ARCH && reg_al == 0) { 01158 /* some scan codes are ignored by CON, and wouldn't read anything. 01159 * while we're at it, take the scan code and convert it into ANSI here 01160 * so that Read() returns it immediately instead of doing this conversion itself. 01161 * This way we never block when we SAID a key was available that gets ignored. */ 01162 if (CommonPC98ExtScanConversionToReadBuf(reg_ah)) 01163 ret = 0x8093; /* Key Available */ 01164 else 01165 ret = 0x80D3; /* No Key Available */ 01166 01167 /* need to consume the key. if it generated anything it will be returned to Read() 01168 * through dev_con_readbuf[] */ 01169 reg_ah=0x0; 01170 01171 /* FIXME: PC-98 emulation should eventually use CONIO emulation that 01172 * better emulates the actual platform. The purpose of this 01173 * hack is to allow our code to call into INT 16h without 01174 * setting up an INT 16h vector */ 01175 INT16_Handler_Wrap(); 01176 } 01177 else { 01178 ret = 0x8093; /* Key Available */ 01179 } 01180 } 01181 01182 reg_ax = saved_ax; 01183 return ret; 01184 } 01185 else { 01186 /* DOSBox mainline behavior: alternate "fast" way through direct manipulation of keyboard scan buffer */ 01187 Bit16u head=mem_readw(BIOS_KEYBOARD_BUFFER_HEAD); 01188 Bit16u tail=mem_readw(BIOS_KEYBOARD_BUFFER_TAIL); 01189 01190 if ((head==tail) && !readcache) return 0x80D3; /* No Key Available */ 01191 if (readcache || real_readw(0x40,head)) return 0x8093; /* Key Available */ 01192 01193 /* remove the zero from keyboard buffer */ 01194 Bit16u start=mem_readw(BIOS_KEYBOARD_BUFFER_START); 01195 Bit16u end =mem_readw(BIOS_KEYBOARD_BUFFER_END); 01196 head+=2; 01197 if (head>=end) head=start; 01198 mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,head); 01199 } 01200 01201 return 0x80D3; /* No Key Available */ 01202 } 01203 01204 device_CON::device_CON() { 01205 Section_prop *section=static_cast<Section_prop *>(control->GetSection("dos")); 01206 01207 SetName("CON"); 01208 readcache=0; 01209 01210 if (IS_PC98_ARCH) { 01211 /* On real MS-DOS for PC-98, ANSI.SYS is effectively part of the DOS kernel, and cannot be turned off. */ 01212 ansi.installed=true; 01213 } 01214 else { 01215 /* Otherwise (including IBM systems), ANSI.SYS is not installed by default but can be added to CONFIG.SYS. 01216 * For compatibility with DOSBox SVN and other forks ANSI.SYS is installed by default. */ 01217 ansi.installed=section->Get_bool("ansi.sys"); 01218 } 01219 01220 ansi.enabled=false; 01221 ansi.attr=DefaultANSIAttr(); 01222 if (IS_PC98_ARCH) { 01223 // NTS: On real hardware, the BIOS does NOT manage the console at all. 01224 // TTY handling is entirely handled by MS-DOS. 01225 ansi.ncols=80; 01226 ansi.nrows=25 - 1; 01227 // the DOS kernel will call on this function to disable, and SDLmain 01228 // will call on to enable 01229 } 01230 ansi.saverow=0; 01231 ansi.savecol=0; 01232 ansi.warned=false; 01233 ClearAnsi(); 01234 } 01235 01236 void device_CON::ClearAnsi(void){ 01237 for(Bit8u i=0; i<NUMBER_ANSI_DATA;i++) ansi.data[i]=0; 01238 ansi.pc98rab=false; 01239 ansi.equcurp=false; 01240 ansi.esc=false; 01241 ansi.sci=false; 01242 ansi.numberofarg=0; 01243 } 01244 01245 void device_CON::Output(Bit8u chr) { 01246 if (dos.internal_output || ansi.enabled) { 01247 if (CurMode->type==M_TEXT) { 01248 Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 01249 Bit8u col=CURSOR_POS_COL(page); 01250 Bit8u row=CURSOR_POS_ROW(page); 01251 BIOS_NCOLS;BIOS_NROWS; 01252 if (nrows==row+1 && (chr=='\n' || (ncols==col+1 && chr!='\r' && chr!=8 && chr!=7))) { 01253 INT10_ScrollWindow(0,0,(Bit8u)(nrows-1),(Bit8u)(ncols-1),-1,ansi.attr,page); 01254 INT10_SetCursorPos(row-1,col,page); 01255 } 01256 } 01257 Real_INT10_TeletypeOutputAttr(chr,ansi.attr,true); 01258 } else Real_INT10_TeletypeOutput(chr,DefaultANSIAttr()); 01259 } 01260 01261 bool device_CON::ANSI_SYS_installed() { 01262 return ansi.installed; 01263 } 01264