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 /* TODO: If biosps2=true and aux=false, also allow an option (default disabled) 00020 * where if set, we don't bother to fire IRQ 12 at all but simply call the 00021 * device callback directly. */ 00022 00023 #include <string.h> 00024 #include <math.h> 00025 00026 00027 #include "dosbox.h" 00028 #include "callback.h" 00029 #include "mem.h" 00030 #include "regs.h" 00031 #include "cpu.h" 00032 #include "mouse.h" 00033 #include "pic.h" 00034 #include "inout.h" 00035 #include "int10.h" 00036 #include "bios.h" 00037 #include "dos_inc.h" 00038 #include "support.h" 00039 #include "setup.h" 00040 #include "control.h" 00041 00042 #if defined(_MSC_VER) 00043 # pragma warning(disable:4244) /* const fmath::local::uint64_t to double possible loss of data */ 00044 #endif 00045 00046 /* ints/bios.cpp */ 00047 void bios_enable_ps2(); 00048 00049 /* hardware/keyboard.cpp */ 00050 void AUX_INT33_Takeover(); 00051 int KEYBOARD_AUX_Active(); 00052 void KEYBOARD_AUX_Event(float x,float y,Bitu buttons,int scrollwheel); 00053 00054 bool en_int33=false; 00055 bool en_bios_ps2mouse=false; 00056 bool cell_granularity_disable=false; 00057 bool en_int33_hide_if_polling=false; 00058 bool en_int33_hide_if_intsub=false; 00059 bool en_int33_pc98_show_graphics=true; // NEC MOUSE.COM behavior 00060 00061 double int33_last_poll = 0; 00062 00063 void DisableINT33() { 00064 if (en_int33) { 00065 LOG(LOG_MOUSE, LOG_DEBUG)("Disabling INT 33 services"); 00066 00067 en_int33 = false; 00068 /* TODO: Also unregister INT 33h handler */ 00069 } 00070 } 00071 00072 void CALLBACK_DeAllocate(Bitu in); 00073 00074 static Bitu int74_ret_callback = 0; 00075 static Bitu call_mouse_bd = 0; 00076 static Bitu call_int33 = 0; 00077 static Bitu call_int74 = 0; 00078 static Bitu call_ps2, call_uir = 0; 00079 00080 void MOUSE_Unsetup_DOS(void) { 00081 if (call_mouse_bd != 0) { 00082 CALLBACK_DeAllocate(call_mouse_bd); 00083 call_mouse_bd = 0; 00084 } 00085 if (call_int33 != 0) { 00086 CALLBACK_DeAllocate(call_int33); 00087 call_int33 = 0; 00088 } 00089 } 00090 00091 void MOUSE_Unsetup_BIOS(void) { 00092 if (int74_ret_callback != 0) { 00093 CALLBACK_DeAllocate(int74_ret_callback); 00094 int74_ret_callback = 0; 00095 } 00096 if (call_int74 != 0) { 00097 CALLBACK_DeAllocate(call_int74); 00098 call_int74 = 0; 00099 } 00100 if (call_ps2 != 0) { 00101 CALLBACK_DeAllocate(call_ps2); 00102 call_ps2 = 0; 00103 } 00104 } 00105 00106 static Bit16u ps2cbseg,ps2cbofs; 00107 static bool useps2callback,ps2callbackinit; 00108 static RealPt ps2_callback,uir_callback; 00109 static Bit16s oldmouseX, oldmouseY; 00110 00111 // serial mouse emulation 00112 void on_mouse_event_for_serial(int delta_x,int delta_y,Bit8u buttonstate); 00113 00114 struct button_event { 00115 Bit8u type; 00116 Bit8u buttons; 00117 }; 00118 00119 extern bool enable_slave_pic; 00120 extern uint8_t p7fd8_8255_mouse_int_enable; 00121 00122 uint8_t MOUSE_IRQ = 12; // IBM PC/AT default 00123 00124 #define QUEUE_SIZE 32 00125 #define MOUSE_BUTTONS 3 00126 #define POS_X (static_cast<Bit16s>(mouse.x) & mouse.gran_x) 00127 #define POS_Y (static_cast<Bit16s>(mouse.y) & mouse.gran_y) 00128 00129 #define CURSORX 16 00130 #define CURSORY 16 00131 #define HIGHESTBIT (1<<(CURSORX-1)) 00132 00133 static Bit16u defaultTextAndMask = 0x77FF; 00134 static Bit16u defaultTextXorMask = 0x7700; 00135 00136 static Bit16u defaultScreenMask[CURSORY] = { 00137 0x3FFF, 0x1FFF, 0x0FFF, 0x07FF, 00138 0x03FF, 0x01FF, 0x00FF, 0x007F, 00139 0x003F, 0x001F, 0x01FF, 0x00FF, 00140 0x30FF, 0xF87F, 0xF87F, 0xFCFF 00141 }; 00142 00143 static Bit16u defaultCursorMask[CURSORY] = { 00144 0x0000, 0x4000, 0x6000, 0x7000, 00145 0x7800, 0x7C00, 0x7E00, 0x7F00, 00146 0x7F80, 0x7C00, 0x6C00, 0x4600, 00147 0x0600, 0x0300, 0x0300, 0x0000 00148 }; 00149 00150 static Bit16u userdefScreenMask[CURSORY]; 00151 static Bit16u userdefCursorMask[CURSORY]; 00152 00153 static struct { 00154 Bit8u buttons; 00155 Bit16u times_pressed[MOUSE_BUTTONS]; 00156 Bit16u times_released[MOUSE_BUTTONS]; 00157 Bit16u last_released_x[MOUSE_BUTTONS]; 00158 Bit16u last_released_y[MOUSE_BUTTONS]; 00159 Bit16u last_pressed_x[MOUSE_BUTTONS]; 00160 Bit16u last_pressed_y[MOUSE_BUTTONS]; 00161 pic_tickindex_t hidden_at; 00162 Bit16u hidden; 00163 float add_x,add_y; 00164 Bit16s min_x,max_x,min_y,max_y; 00165 Bit16s max_screen_x,max_screen_y; 00166 float mickey_x,mickey_y; 00167 float x,y; 00168 float ps2x,ps2y; 00169 button_event event_queue[QUEUE_SIZE]; 00170 Bit8u events;//Increase if QUEUE_SIZE >255 (currently 32) 00171 Bit16u sub_seg,sub_ofs; 00172 Bit16u sub_mask; 00173 00174 bool background; 00175 Bit16s backposx, backposy; 00176 Bit8u backData[CURSORX*CURSORY]; 00177 Bit16u* screenMask; 00178 Bit16u* cursorMask; 00179 Bit16s clipx,clipy; 00180 Bit16s hotx,hoty; 00181 Bit16u textAndMask, textXorMask; 00182 00183 float mickeysPerPixel_x; 00184 float mickeysPerPixel_y; 00185 float pixelPerMickey_x; 00186 float pixelPerMickey_y; 00187 Bit16u senv_x_val; 00188 Bit16u senv_y_val; 00189 Bit16u dspeed_val; 00190 float senv_x; 00191 float senv_y; 00192 Bit16s updateRegion_x[2]; 00193 Bit16s updateRegion_y[2]; 00194 Bit16u doubleSpeedThreshold; 00195 Bit16u language; 00196 Bit16u cursorType; 00197 Bit16u oldhidden; 00198 Bit8u page; 00199 bool enabled; 00200 bool inhibit_draw; 00201 bool timer_in_progress; 00202 bool first_range_setx; 00203 bool first_range_sety; 00204 bool in_UIR; 00205 Bit8u mode; 00206 Bit16s gran_x,gran_y; 00207 int scrollwheel; 00208 } mouse; 00209 00210 bool Mouse_SetPS2State(bool use) { 00211 if (use && (!ps2callbackinit)) { 00212 useps2callback = false; 00213 00214 if (MOUSE_IRQ != 0) 00215 PIC_SetIRQMask(MOUSE_IRQ,true); 00216 00217 return false; 00218 } 00219 useps2callback = use; 00220 Mouse_AutoLock(useps2callback); 00221 00222 if (MOUSE_IRQ != 0) 00223 PIC_SetIRQMask(MOUSE_IRQ,!useps2callback); 00224 00225 return true; 00226 } 00227 00228 void Mouse_ChangePS2Callback(Bit16u pseg, Bit16u pofs) { 00229 if ((pseg==0) && (pofs==0)) { 00230 ps2callbackinit = false; 00231 Mouse_AutoLock(false); 00232 } else { 00233 ps2callbackinit = true; 00234 ps2cbseg = pseg; 00235 ps2cbofs = pofs; 00236 } 00237 Mouse_AutoLock(ps2callbackinit); 00238 } 00239 00240 /* set to true in case of shitty INT 15h device callbacks that fail to preserve CPU registers */ 00241 bool ps2_callback_save_regs = false; 00242 00243 void DoPS2Callback(Bit16u data, Bit16s mouseX, Bit16s mouseY) { 00244 if (useps2callback && ps2cbseg != 0 && ps2cbofs != 0) { 00245 Bit16u mdat = (data & 0x03) | 0x08; 00246 Bit16s xdiff = mouseX-oldmouseX; 00247 Bit16s ydiff = oldmouseY-mouseY; 00248 oldmouseX = mouseX; 00249 oldmouseY = mouseY; 00250 if ((xdiff>0xff) || (xdiff<-0xff)) mdat |= 0x40; // x overflow 00251 if ((ydiff>0xff) || (ydiff<-0xff)) mdat |= 0x80; // y overflow 00252 xdiff %= 256; 00253 ydiff %= 256; 00254 if (xdiff<0) { 00255 xdiff = (0x100+xdiff); 00256 mdat |= 0x10; 00257 } 00258 if (ydiff<0) { 00259 ydiff = (0x100+ydiff); 00260 mdat |= 0x20; 00261 } 00262 if (ps2_callback_save_regs) { 00263 CPU_Push16(reg_ax);CPU_Push16(reg_cx);CPU_Push16(reg_dx);CPU_Push16(reg_bx); 00264 CPU_Push16(reg_bp);CPU_Push16(reg_si);CPU_Push16(reg_di); 00265 CPU_Push16(SegValue(ds)); CPU_Push16(SegValue(es)); 00266 } 00267 CPU_Push16((Bit16u)mdat); 00268 CPU_Push16((Bit16u)(xdiff % 256)); 00269 CPU_Push16((Bit16u)(ydiff % 256)); 00270 CPU_Push16((Bit16u)0); 00271 CPU_Push16(RealSeg(ps2_callback)); 00272 CPU_Push16(RealOff(ps2_callback)); 00273 SegSet16(cs, ps2cbseg); 00274 reg_ip = ps2cbofs; 00275 } 00276 } 00277 00278 Bitu PS2_Handler(void) { 00279 CPU_Pop16();CPU_Pop16();CPU_Pop16();CPU_Pop16();// remove the 4 words 00280 if (ps2_callback_save_regs) { 00281 SegSet16(es,CPU_Pop16()); SegSet16(ds,CPU_Pop16()); 00282 reg_di=CPU_Pop16();reg_si=CPU_Pop16();reg_bp=CPU_Pop16(); 00283 reg_bx=CPU_Pop16();reg_dx=CPU_Pop16();reg_cx=CPU_Pop16();reg_ax=CPU_Pop16(); 00284 } 00285 return CBRET_NONE; 00286 } 00287 00288 00289 #define X_MICKEY 8 00290 #define Y_MICKEY 8 00291 00292 #define MOUSE_HAS_MOVED 1 00293 #define MOUSE_LEFT_PRESSED 2 00294 #define MOUSE_LEFT_RELEASED 4 00295 #define MOUSE_RIGHT_PRESSED 8 00296 #define MOUSE_RIGHT_RELEASED 16 00297 #define MOUSE_MIDDLE_PRESSED 32 00298 #define MOUSE_MIDDLE_RELEASED 64 00299 #define MOUSE_DUMMY 128 00300 #define MOUSE_DELAY 5.0 00301 00302 void MOUSE_Limit_Events(Bitu /*val*/) { 00303 mouse.timer_in_progress = false; 00304 00305 if (IS_PC98_ARCH) { 00306 if (mouse.events>0) { 00307 mouse.events--; 00308 } 00309 } 00310 00311 if (mouse.events) { 00312 mouse.timer_in_progress = true; 00313 PIC_AddEvent(MOUSE_Limit_Events,MOUSE_DELAY); 00314 00315 if (MOUSE_IRQ != 0) { 00316 if (!IS_PC98_ARCH) 00317 PIC_ActivateIRQ(MOUSE_IRQ); 00318 } 00319 } 00320 } 00321 00322 INLINE void Mouse_AddEvent(Bit8u type) { 00323 if (mouse.events<QUEUE_SIZE) { 00324 if (mouse.events>0) { 00325 /* Skip duplicate events */ 00326 if (type==MOUSE_HAS_MOVED) return; 00327 /* Always put the newest element in the front as that the events are 00328 * handled backwards (prevents doubleclicks while moving) 00329 */ 00330 for(Bitu i = mouse.events ; i ; i--) 00331 mouse.event_queue[i] = mouse.event_queue[i-1]; 00332 } 00333 mouse.event_queue[0].type=type; 00334 mouse.event_queue[0].buttons=mouse.buttons; 00335 mouse.events++; 00336 } 00337 if (!mouse.timer_in_progress) { 00338 mouse.timer_in_progress = true; 00339 PIC_AddEvent(MOUSE_Limit_Events,MOUSE_DELAY); 00340 00341 if (MOUSE_IRQ != 0) { 00342 if (!IS_PC98_ARCH) 00343 PIC_ActivateIRQ(MOUSE_IRQ); 00344 } 00345 } 00346 } 00347 00348 void MOUSE_DummyEvent(void) { 00349 Mouse_AddEvent(MOUSE_DUMMY); 00350 } 00351 00352 // *************************************************************************** 00353 // Mouse cursor - text mode 00354 // *************************************************************************** 00355 /* Write and read directly to the screen. Do no use int_setcursorpos (LOTUS123) */ 00356 extern void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit16u chr,Bit8u attr,bool useattr); 00357 extern void ReadCharAttr(Bit16u col,Bit16u row,Bit8u page,Bit16u * result); 00358 00359 void RestoreCursorBackgroundText() { 00360 if (mouse.hidden || mouse.inhibit_draw) return; 00361 00362 if (mouse.background) { 00363 WriteChar((Bit16u)mouse.backposx,(Bit16u)mouse.backposy,real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE),mouse.backData[0],mouse.backData[1],true); 00364 mouse.background = false; 00365 } 00366 } 00367 00368 void DrawCursorText() { 00369 // Restore Background 00370 RestoreCursorBackgroundText(); 00371 00372 // Check if cursor in update region 00373 if ((POS_Y <= mouse.updateRegion_y[1]) && (POS_Y >= mouse.updateRegion_y[0]) && 00374 (POS_X <= mouse.updateRegion_x[1]) && (POS_X >= mouse.updateRegion_x[0])) { 00375 return; 00376 } 00377 00378 // Save Background 00379 mouse.backposx = POS_X>>3; 00380 mouse.backposy = POS_Y>>3; 00381 if (mouse.mode < 2) mouse.backposx >>= 1; 00382 00383 //use current page (CV program) 00384 Bit8u page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00385 00386 if (mouse.cursorType == 0) { 00387 Bit16u result; 00388 ReadCharAttr((Bit16u)mouse.backposx,(Bit16u)mouse.backposy,page,&result); 00389 mouse.backData[0] = (Bit8u)(result & 0xFF); 00390 mouse.backData[1] = (Bit8u)(result>>8); 00391 mouse.background = true; 00392 // Write Cursor 00393 result = (result & mouse.textAndMask) ^ mouse.textXorMask; 00394 WriteChar((Bit16u)mouse.backposx,(Bit16u)mouse.backposy,page,(Bit8u)(result&0xFF),(Bit8u)(result>>8),true); 00395 } else { 00396 Bit16u address=page * real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE); 00397 address += (mouse.backposy * real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS) + mouse.backposx) * 2; 00398 address /= 2; 00399 Bit16u cr = real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); 00400 IO_Write(cr , 0xe); 00401 IO_Write((Bitu)cr + 1u, (address >> 8) & 0xff); 00402 IO_Write(cr , 0xf); 00403 IO_Write((Bitu)cr + 1u, address & 0xff); 00404 } 00405 } 00406 00407 // *************************************************************************** 00408 // Mouse cursor - graphic mode 00409 // *************************************************************************** 00410 00411 static Bit8u gfxReg3CE[9]; 00412 static Bit8u index3C4,gfxReg3C5; 00413 void SaveVgaRegisters() { 00414 if (IS_VGA_ARCH) { 00415 for (Bit8u i=0; i<9; i++) { 00416 IO_Write (0x3CE,i); 00417 gfxReg3CE[i] = IO_Read(0x3CF); 00418 } 00419 /* Setup some default values in GFX regs that should work */ 00420 IO_Write(0x3CE,3); IO_Write(0x3Cf,0); //disable rotate and operation 00421 IO_Write(0x3CE,5); IO_Write(0x3Cf,gfxReg3CE[5]&0xf0); //Force read/write mode 0 00422 00423 //Set Map to all planes. Celtic Tales 00424 index3C4 = IO_Read(0x3c4); IO_Write(0x3C4,2); 00425 gfxReg3C5 = IO_Read(0x3C5); IO_Write(0x3C5,0xF); 00426 } else if (machine==MCH_EGA) { 00427 //Set Map to all planes. 00428 IO_Write(0x3C4,2); 00429 IO_Write(0x3C5,0xF); 00430 } 00431 } 00432 00433 void RestoreVgaRegisters() { 00434 if (IS_VGA_ARCH) { 00435 for (Bit8u i=0; i<9; i++) { 00436 IO_Write(0x3CE,i); 00437 IO_Write(0x3CF,gfxReg3CE[i]); 00438 } 00439 00440 IO_Write(0x3C4,2); 00441 IO_Write(0x3C5,gfxReg3C5); 00442 IO_Write(0x3C4,index3C4); 00443 } 00444 } 00445 00446 void ClipCursorArea(Bit16s& x1, Bit16s& x2, Bit16s& y1, Bit16s& y2, 00447 Bit16u& addx1, Bit16u& addx2, Bit16u& addy) { 00448 addx1 = addx2 = addy = 0; 00449 // Clip up 00450 if (y1<0) { 00451 addy += (-y1); 00452 y1 = 0; 00453 } 00454 // Clip down 00455 if (y2>mouse.clipy) { 00456 y2 = mouse.clipy; 00457 } 00458 // Clip left 00459 if (x1<0) { 00460 addx1 += (-x1); 00461 x1 = 0; 00462 } 00463 // Clip right 00464 if (x2>mouse.clipx) { 00465 addx2 = x2 - mouse.clipx; 00466 x2 = mouse.clipx; 00467 } 00468 } 00469 00470 void RestoreCursorBackground() { 00471 if (mouse.hidden || mouse.inhibit_draw) return; 00472 00473 SaveVgaRegisters(); 00474 if (mouse.background) { 00475 // Restore background 00476 Bit16s x,y; 00477 Bit16u addx1,addx2,addy; 00478 Bit16u dataPos = 0; 00479 Bit16s x1 = mouse.backposx; 00480 Bit16s y1 = mouse.backposy; 00481 Bit16s x2 = x1 + CURSORX - 1; 00482 Bit16s y2 = y1 + CURSORY - 1; 00483 00484 ClipCursorArea(x1, x2, y1, y2, addx1, addx2, addy); 00485 00486 dataPos = addy * CURSORX; 00487 for (y=y1; y<=y2; y++) { 00488 dataPos += addx1; 00489 for (x=x1; x<=x2; x++) { 00490 INT10_PutPixel((Bit16u)x,(Bit16u)y,mouse.page,mouse.backData[dataPos++]); 00491 } 00492 dataPos += addx2; 00493 } 00494 mouse.background = false; 00495 } 00496 RestoreVgaRegisters(); 00497 } 00498 00499 void DrawCursor() { 00500 if (mouse.hidden || mouse.inhibit_draw) return; 00501 INT10_SetCurMode(); 00502 // In Textmode ? 00503 if (CurMode->type==M_TEXT) { 00504 DrawCursorText(); 00505 return; 00506 } 00507 00508 // Check video page. Seems to be ignored for text mode. 00509 // hence the text mode handled above this 00510 if (real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)!=mouse.page) return; 00511 // Check if cursor in update region 00512 /* if ((POS_X >= mouse.updateRegion_x[0]) && (POS_X <= mouse.updateRegion_x[1]) && 00513 (POS_Y >= mouse.updateRegion_y[0]) && (POS_Y <= mouse.updateRegion_y[1])) { 00514 if (CurMode->type==M_TEXT16) 00515 RestoreCursorBackgroundText(); 00516 else 00517 RestoreCursorBackground(); 00518 mouse.shown--; 00519 return; 00520 } 00521 */ /*Not sure yet what to do update region should be set to ??? */ 00522 00523 // Get Clipping ranges 00524 00525 00526 mouse.clipx = (Bit16s)((Bits)CurMode->swidth-1); /* Get from bios ? */ 00527 mouse.clipy = (Bit16s)((Bits)CurMode->sheight-1); 00528 00529 /* might be vidmode == 0x13?2:1 */ 00530 Bit16s xratio = 640; 00531 if (CurMode->swidth>0) xratio/=(Bit16u)CurMode->swidth; 00532 if (xratio==0) xratio = 1; 00533 00534 RestoreCursorBackground(); 00535 00536 SaveVgaRegisters(); 00537 00538 // Save Background 00539 Bit16s x,y; 00540 Bit16u addx1,addx2,addy; 00541 Bit16u dataPos = 0; 00542 Bit16s x1 = POS_X / xratio - mouse.hotx; 00543 Bit16s y1 = POS_Y - mouse.hoty; 00544 Bit16s x2 = x1 + CURSORX - 1; 00545 Bit16s y2 = y1 + CURSORY - 1; 00546 00547 ClipCursorArea(x1,x2,y1,y2, addx1, addx2, addy); 00548 00549 dataPos = addy * CURSORX; 00550 for (y=y1; y<=y2; y++) { 00551 dataPos += addx1; 00552 for (x=x1; x<=x2; x++) { 00553 INT10_GetPixel((Bit16u)x,(Bit16u)y,mouse.page,&mouse.backData[dataPos++]); 00554 } 00555 dataPos += addx2; 00556 } 00557 mouse.background= true; 00558 mouse.backposx = POS_X / xratio - mouse.hotx; 00559 mouse.backposy = POS_Y - mouse.hoty; 00560 00561 // Draw Mousecursor 00562 dataPos = addy * CURSORX; 00563 for (y=y1; y<=y2; y++) { 00564 Bit16u scMask = mouse.screenMask[addy+y-y1]; 00565 Bit16u cuMask = mouse.cursorMask[addy+y-y1]; 00566 if (addx1>0) { scMask<<=addx1; cuMask<<=addx1; dataPos += addx1; } 00567 for (x=x1; x<=x2; x++) { 00568 Bit8u pixel = 0; 00569 // ScreenMask 00570 if (scMask & HIGHESTBIT) pixel = mouse.backData[dataPos]; 00571 scMask<<=1; 00572 // CursorMask 00573 if (cuMask & HIGHESTBIT) pixel = pixel ^ 0x0F; 00574 cuMask<<=1; 00575 // Set Pixel 00576 INT10_PutPixel((Bit16u)x,(Bit16u)y,mouse.page,pixel); 00577 dataPos++; 00578 } 00579 dataPos += addx2; 00580 } 00581 RestoreVgaRegisters(); 00582 } 00583 00584 void pc98_mouse_movement_apply(int x,int y); 00585 00586 #if !defined(C_SDL2) 00587 bool GFX_IsFullscreen(void); 00588 #else 00589 static inline bool GFX_IsFullscreen(void) { 00590 return false; 00591 } 00592 #endif 00593 00594 extern int user_cursor_x, user_cursor_y; 00595 extern int user_cursor_sw, user_cursor_sh; 00596 extern bool user_cursor_locked; 00597 00598 /* FIXME: Re-test this code */ 00599 void Mouse_CursorMoved(float xrel,float yrel,float x,float y,bool emulate) { 00600 extern bool Mouse_Vertical; 00601 float dx = xrel * mouse.pixelPerMickey_x; 00602 float dy = (Mouse_Vertical?-yrel:yrel) * mouse.pixelPerMickey_y; 00603 00604 if (!IS_PC98_ARCH && KEYBOARD_AUX_Active()) { 00605 KEYBOARD_AUX_Event(xrel,yrel,mouse.buttons,mouse.scrollwheel); 00606 mouse.scrollwheel = 0; 00607 return; 00608 } 00609 00610 if((fabs(xrel) > 1.0) || (mouse.senv_x < 1.0)) dx *= mouse.senv_x; 00611 if((fabs(yrel) > 1.0) || (mouse.senv_y < 1.0)) dy *= mouse.senv_y; 00612 if (useps2callback) dy *= 2; 00613 00614 if (user_cursor_locked) { 00615 /* either device reports relative motion ONLY, and therefore requires that the user 00616 * has captured the mouse */ 00617 00618 /* serial mouse */ 00619 on_mouse_event_for_serial((int)(dx),(int)(dy*2),mouse.buttons); 00620 00621 /* PC-98 mouse */ 00622 if (IS_PC98_ARCH) pc98_mouse_movement_apply(xrel,yrel); 00623 00624 mouse.mickey_x += (dx * mouse.mickeysPerPixel_x); 00625 mouse.mickey_y += (dy * mouse.mickeysPerPixel_y); 00626 if (mouse.mickey_x >= 32768.0) mouse.mickey_x -= 65536.0; 00627 else if (mouse.mickey_x <= -32769.0) mouse.mickey_x += 65536.0; 00628 if (mouse.mickey_y >= 32768.0) mouse.mickey_y -= 65536.0; 00629 else if (mouse.mickey_y <= -32769.0) mouse.mickey_y += 65536.0; 00630 } 00631 00632 if (emulate) { 00633 mouse.x += dx; 00634 mouse.y += dy; 00635 } else if (CurMode != NULL) { 00636 if (CurMode->type == M_TEXT) { 00637 mouse.x = x*real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)*8; 00638 mouse.y = y*(real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1)*8; 00639 /* NTS: DeluxePaint II enhanced sets a large range (5112x3832) for VGA mode 0x12 640x480 16-color */ 00640 } else { 00641 if ((mouse.max_x > 0) && (mouse.max_y > 0)) { 00642 mouse.x = x*mouse.max_x; 00643 mouse.y = y*mouse.max_y; 00644 } else { 00645 mouse.x += xrel; 00646 mouse.y += yrel; 00647 } 00648 } 00649 } 00650 00651 /* ignore constraints if using PS2 mouse callback in the bios */ 00652 00653 if (mouse.x > mouse.max_x) mouse.x = mouse.max_x; 00654 if (mouse.x < mouse.min_x) mouse.x = mouse.min_x; 00655 if (mouse.y > mouse.max_y) mouse.y = mouse.max_y; 00656 if (mouse.y < mouse.min_y) mouse.y = mouse.min_y; 00657 00658 /*make mouse emulated, eventually*/ 00659 extern MOUSE_EMULATION user_cursor_emulation; 00660 bool emu; 00661 switch (user_cursor_emulation) 00662 { 00663 case MOUSE_EMULATION_ALWAYS: 00664 emu = true; 00665 break; 00666 case MOUSE_EMULATION_INTEGRATION: 00667 emu = !user_cursor_locked && !GFX_IsFullscreen(); 00668 break; 00669 case MOUSE_EMULATION_LOCKED: 00670 emu = user_cursor_locked && !GFX_IsFullscreen(); 00671 break; 00672 case MOUSE_EMULATION_NEVER: 00673 default: 00674 emu = false; 00675 } 00676 if (!emu) 00677 { 00678 auto x1 = (double)user_cursor_x / ((double)user_cursor_sw - 1); 00679 auto y1 = (double)user_cursor_y / ((double)user_cursor_sh - 1); 00680 mouse.x = x1 * mouse.max_screen_x; 00681 mouse.y = y1 * mouse.max_screen_y; 00682 00683 if (mouse.x < mouse.min_x) 00684 mouse.x = mouse.min_x; 00685 if (mouse.y < mouse.min_y) 00686 mouse.y = mouse.min_y; 00687 if (mouse.x > mouse.max_x) 00688 mouse.x = mouse.max_x; 00689 if (mouse.y > mouse.max_y) 00690 mouse.y = mouse.max_y; 00691 } 00692 00693 if (user_cursor_locked) { 00694 /* send relative PS/2 mouse motion only if the cursor is captured */ 00695 mouse.ps2x += xrel; 00696 mouse.ps2y += yrel; 00697 if (mouse.ps2x >= 32768.0) mouse.ps2x -= 65536.0; 00698 else if (mouse.ps2x <= -32769.0) mouse.ps2x += 65536.0; 00699 if (mouse.ps2y >= 32768.0) mouse.ps2y -= 65536.0; 00700 else if (mouse.ps2y <= -32769.0) mouse.ps2y += 65536.0; 00701 } 00702 00703 Mouse_AddEvent(MOUSE_HAS_MOVED); 00704 } 00705 00706 uint8_t Mouse_GetButtonState(void) { 00707 return mouse.buttons; 00708 } 00709 00710 #if defined(WIN32) 00711 char text[5000]; 00712 const char* Mouse_GetSelected(int x1, int y1, int x2, int y2, int w, int h, Bit16u *textlen) { 00713 Bit8u page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00714 Bit16u c=0, r=0; 00715 if (IS_PC98_ARCH) { 00716 c=80; 00717 r=real_readb(0x60,0x113) & 0x01 ? 25 : 20; 00718 } else { 00719 c=real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 00720 r=(Bit16u)real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; 00721 } 00722 int c1=c*x1/w, r1=r*y1/h, c2=c*x2/w, r2=r*y2/h, t; 00723 if (c1>c2) { 00724 t=c1; 00725 c1=c2; 00726 c2=t; 00727 } 00728 if (r1>r2) { 00729 t=r1; 00730 r1=r2; 00731 r2=t; 00732 } 00733 Bit16u result=0, len=0; 00734 text[0]=0; 00735 for (int i=r1; i<=r2; i++) { 00736 for (int j=c1; j<=c2; j++) { 00737 if (IS_PC98_ARCH) { 00738 Bit16u address=((i*80)+j)*2; 00739 PhysPt where = CurMode->pstart+address; 00740 result=mem_readw(where); 00741 if ((result & 0xFF00u) != 0u && (result & 0xFCu) != 0x08u && result==mem_readw(where+2) && ++j<c) { 00742 result&=0x7F7F; 00743 Bit8u j1=(result%0x100)+0x20, j2=result/0x100; 00744 if (j1>32&&j1<127&&j2>32&&j2<127) { 00745 text[len++]=(j1+1)/2+(j1<95?112:176); 00746 text[len++]=j2+(j1%2?31+(j2/96):126); 00747 } 00748 } else 00749 text[len++]=result; 00750 } else { 00751 ReadCharAttr(j,i,page,&result); 00752 text[len++]=result; 00753 } 00754 } 00755 while (len>0&&text[len-1]==32) text[--len]=0; 00756 if (i<r2) { 00757 text[len++]='\r'; 00758 text[len++]='\n'; 00759 } 00760 } 00761 text[len]=0; 00762 *textlen=len; 00763 return text; 00764 } 00765 00766 void Mouse_Select(int x1, int y1, int x2, int y2, int w, int h) { 00767 Bit8u page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00768 Bit16u c=0, r=0; 00769 if (IS_PC98_ARCH) { 00770 c=80; 00771 r=real_readb(0x60,0x113) & 0x01 ? 25 : 20; 00772 } else { 00773 c=real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 00774 r=(Bit16u)real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; 00775 } 00776 int c1=c*x1/w, r1=r*y1/h, c2=c*x2/w, r2=r*y2/h, t; 00777 if (c1>c2) { 00778 t=c1; 00779 c1=c2; 00780 c2=t; 00781 } 00782 if (r1>r2) { 00783 t=r1; 00784 r1=r2; 00785 r2=t; 00786 } 00787 for (int i=r1; i<=r2; i++) 00788 for (int j=c1; j<=c2; j++) { 00789 if (IS_PC98_ARCH) { 00790 Bit16u address=((i*80)+j)*2; 00791 PhysPt where = CurMode->pstart+address; 00792 mem_writeb(where+0x2000,mem_readb(where+0x2000)^16); 00793 } else 00794 real_writeb(0xb800,(i*c+j)*2+1,real_readb(0xb800,(i*c+j)*2+1)^119); 00795 } 00796 } 00797 00798 void Restore_Text(int x1, int y1, int x2, int y2, int w, int h) { 00799 Bit8u page = real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); 00800 Bit16u c=0, r=0; 00801 if (IS_PC98_ARCH) { 00802 c=80; 00803 r=real_readb(0x60,0x113) & 0x01 ? 25 : 20; 00804 } else { 00805 c=real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); 00806 r=(Bit16u)real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1; 00807 } 00808 int c1=c*x1/w, r1=r*y1/h, c2=c*x2/w, r2=r*y2/h, t; 00809 if (c1>c2) { 00810 t=c1; 00811 c1=c2; 00812 c2=t; 00813 } 00814 if (r1>r2) { 00815 t=r1; 00816 r1=r2; 00817 r2=t; 00818 } 00819 for (int i=r1; i<=r2; i++) 00820 for (int j=c1; j<=c2; j++) { 00821 if (IS_PC98_ARCH) { 00822 Bit16u address=((i*80)+j)*2; 00823 PhysPt where = CurMode->pstart+address; 00824 mem_writeb(where+0x2000,mem_readb(where+0x2000)^16); 00825 } else 00826 real_writeb(0xb800,(i*c+j)*2+1,real_readb(0xb800,(i*c+j)*2+1)^119); 00827 } 00828 } 00829 #endif 00830 00831 void Mouse_ButtonPressed(Bit8u button) { 00832 if (!IS_PC98_ARCH && KEYBOARD_AUX_Active()) { 00833 switch (button) { 00834 case 0: 00835 mouse.buttons|=1; 00836 break; 00837 case 1: 00838 mouse.buttons|=2; 00839 break; 00840 case 2: 00841 mouse.buttons|=4; 00842 break; 00843 default: 00844 return; 00845 } 00846 00847 KEYBOARD_AUX_Event(0,0,mouse.buttons,mouse.scrollwheel); 00848 mouse.scrollwheel = 0; 00849 return; 00850 } 00851 00852 if (button > 2) 00853 return; 00854 00855 switch (button) { 00856 #if (MOUSE_BUTTONS >= 1) 00857 case 0: 00858 if (mouse.buttons&1) return; 00859 mouse.buttons|=1; 00860 Mouse_AddEvent(MOUSE_LEFT_PRESSED); 00861 break; 00862 #endif 00863 #if (MOUSE_BUTTONS >= 2) 00864 case 1: 00865 if (mouse.buttons&2) return; 00866 mouse.buttons|=2; 00867 Mouse_AddEvent(MOUSE_RIGHT_PRESSED); 00868 break; 00869 #endif 00870 #if (MOUSE_BUTTONS >= 3) 00871 case 2: 00872 if (mouse.buttons&4) return; 00873 mouse.buttons|=4; 00874 Mouse_AddEvent(MOUSE_MIDDLE_PRESSED); 00875 break; 00876 #endif 00877 default: 00878 return; 00879 } 00880 mouse.times_pressed[button]++; 00881 mouse.last_pressed_x[button]=(Bit16u)POS_X; 00882 mouse.last_pressed_y[button]=(Bit16u)POS_Y; 00883 00884 /* serial mouse, if connected, also wants to know about it */ 00885 on_mouse_event_for_serial(0,0,mouse.buttons); 00886 } 00887 00888 void Mouse_ButtonReleased(Bit8u button) { 00889 if (!IS_PC98_ARCH && KEYBOARD_AUX_Active()) { 00890 switch (button) { 00891 case 0: 00892 mouse.buttons&=~1; 00893 break; 00894 case 1: 00895 mouse.buttons&=~2; 00896 break; 00897 case 2: 00898 mouse.buttons&=~4; 00899 break; 00900 case (100-1): /* scrollwheel up */ 00901 mouse.scrollwheel -= 8; 00902 break; 00903 case (100+1): /* scrollwheel down */ 00904 mouse.scrollwheel += 8; 00905 break; 00906 default: 00907 return; 00908 } 00909 00910 KEYBOARD_AUX_Event(0,0,mouse.buttons,mouse.scrollwheel); 00911 mouse.scrollwheel = 0; 00912 return; 00913 } 00914 00915 if (button > 2) 00916 return; 00917 00918 switch (button) { 00919 #if (MOUSE_BUTTONS >= 1) 00920 case 0: 00921 if (!(mouse.buttons&1)) return; 00922 mouse.buttons&=~1; 00923 Mouse_AddEvent(MOUSE_LEFT_RELEASED); 00924 break; 00925 #endif 00926 #if (MOUSE_BUTTONS >= 2) 00927 case 1: 00928 if (!(mouse.buttons&2)) return; 00929 mouse.buttons&=~2; 00930 Mouse_AddEvent(MOUSE_RIGHT_RELEASED); 00931 break; 00932 #endif 00933 #if (MOUSE_BUTTONS >= 3) 00934 case 2: 00935 if (!(mouse.buttons&4)) return; 00936 mouse.buttons&=~4; 00937 Mouse_AddEvent(MOUSE_MIDDLE_RELEASED); 00938 break; 00939 #endif 00940 default: 00941 return; 00942 } 00943 mouse.times_released[button]++; 00944 mouse.last_released_x[button]=(Bit16u)POS_X; 00945 mouse.last_released_y[button]=(Bit16u)POS_Y; 00946 00947 /* serial mouse, if connected, also wants to know about it */ 00948 on_mouse_event_for_serial(0,0,mouse.buttons); 00949 } 00950 00951 static void Mouse_SetMickeyPixelRate(Bit16s px, Bit16s py){ 00952 if ((px!=0) && (py!=0)) { 00953 mouse.mickeysPerPixel_x = (float)px/X_MICKEY; 00954 mouse.mickeysPerPixel_y = (float)py/Y_MICKEY; 00955 mouse.pixelPerMickey_x = X_MICKEY/(float)px; 00956 mouse.pixelPerMickey_y = Y_MICKEY/(float)py; 00957 } 00958 } 00959 00960 static void Mouse_SetSensitivity(Bit16u px, Bit16u py, Bit16u dspeed){ 00961 if(px>100) px=100; 00962 if(py>100) py=100; 00963 if(dspeed>100) dspeed=100; 00964 // save values 00965 mouse.senv_x_val=px; 00966 mouse.senv_y_val=py; 00967 mouse.dspeed_val=dspeed; 00968 if ((px!=0) && (py!=0)) { 00969 px--; //Inspired by cutemouse 00970 py--; //Although their cursor update routine is far more complex then ours 00971 mouse.senv_x=(static_cast<float>(px)*px)/3600.0f +1.0f/3.0f; 00972 mouse.senv_y=(static_cast<float>(py)*py)/3600.0f +1.0f/3.0f; 00973 } 00974 } 00975 00976 00977 static void Mouse_ResetHardware(void){ 00978 if (MOUSE_IRQ != 0) 00979 PIC_SetIRQMask(MOUSE_IRQ,false); 00980 00981 if (IS_PC98_ARCH) { 00982 IO_WriteB(0x7FDD,IO_ReadB(0x7FDD) & (~0x10)); // remove interrupt inhibit 00983 00984 // NEC MOUSE.COM behavior: Driver startup and INT 33h AX=0 automatically show the graphics layer. 00985 // Some games by "Orange House" depend on this behavior, without which the graphics are invisible. 00986 if (en_int33_pc98_show_graphics) { 00987 reg_eax = 0x40u << 8u; // AH=40h show graphics layer 00988 CALLBACK_RunRealInt(0x18); 00989 } 00990 } 00991 } 00992 00993 void Mouse_BeforeNewVideoMode(bool setmode) { 00994 (void)setmode;//unused 00995 00996 if (CurMode->type!=M_TEXT) RestoreCursorBackground(); 00997 else RestoreCursorBackgroundText(); 00998 if (!mouse.hidden) { 00999 mouse.hidden = 1; 01000 mouse.hidden_at = PIC_FullIndex(); 01001 } 01002 mouse.oldhidden = 1; 01003 mouse.background = false; 01004 } 01005 01006 //Does way to much. Many things should be moved to mouse reset one day 01007 void Mouse_AfterNewVideoMode(bool setmode) { 01008 mouse.inhibit_draw = false; 01009 /* Get the correct resolution from the current video mode */ 01010 Bit8u mode = mem_readb(BIOS_VIDEO_MODE); 01011 if (setmode && mode == mouse.mode) LOG(LOG_MOUSE,LOG_NORMAL)("New video mode is the same as the old"); 01012 mouse.first_range_setx = false; 01013 mouse.first_range_sety = false; 01014 mouse.gran_x = (Bit16s)0xffff; 01015 mouse.gran_y = (Bit16s)0xffff; 01016 01017 /* If new video mode is SVGA and this is NOT a mouse driver reset, then do not reset min/max. 01018 * This is needed for "down-by-the-laituri-peli" (some sort of Finnish band tour simulation?) 01019 * which sets the min/max range and THEN sets up 640x480 256-color mode through the VESA BIOS. 01020 * Without this fix, the cursor is constrained to the upper left hand quadrant of the screen. */ 01021 if (!setmode || mode <= 0x13/*non-SVGA*/) { 01022 mouse.min_x = 0; 01023 mouse.max_x = 639; 01024 mouse.min_y = 0; 01025 mouse.max_y = 479; 01026 } 01027 01028 if (machine == MCH_HERC) { 01029 // DeluxePaint II again... 01030 mouse.first_range_setx = true; 01031 mouse.first_range_sety = true; 01032 } 01033 01034 switch (mode) { 01035 case 0x00: 01036 case 0x01: 01037 case 0x02: 01038 case 0x03: 01039 case 0x07: { 01040 mouse.gran_x = (mode<2)?0xfff0:0xfff8; 01041 mouse.gran_y = (Bit16s)0xfff8; 01042 if (IS_PC98_ARCH) { 01043 mouse.max_y = 400 - 1; 01044 } 01045 else { 01046 Bitu rows = real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS); 01047 if ((rows == 0) || (rows > 250)) rows = 25 - 1; 01048 mouse.max_y = 8*(rows+1) - 1; 01049 } 01050 break; 01051 } 01052 case 0x04: 01053 case 0x05: 01054 case 0x06: 01055 case 0x08: 01056 case 0x09: 01057 case 0x0a: 01058 case 0x0d: 01059 case 0x0e: 01060 case 0x13: 01061 if (mode == 0x0d || mode == 0x13) mouse.gran_x = (Bit16s)0xfffe; 01062 mouse.max_y = 199; 01063 // some games redefine the mouse range for this mode 01064 mouse.first_range_setx = true; 01065 mouse.first_range_sety = true; 01066 break; 01067 case 0x0f: 01068 case 0x10: 01069 mouse.max_y = 349; 01070 // Deluxepaint II enhanced will redefine the range for 640x480 mode 01071 mouse.first_range_setx = true; 01072 mouse.first_range_sety = true; 01073 break; 01074 case 0x11: 01075 case 0x12: 01076 mouse.max_y = 479; 01077 // Deluxepaint II enhanced will redefine the range for 640x480 mode 01078 mouse.first_range_setx = true; 01079 mouse.first_range_sety = true; 01080 break; 01081 default: 01082 LOG(LOG_MOUSE,LOG_ERROR)("Unhandled videomode %X on reset",mode); 01083 mouse.inhibit_draw = true; 01084 /* If new video mode is SVGA and this is NOT a mouse driver reset, then do not reset min/max. 01085 * This is needed for "down-by-the-laituri-peli" (some sort of Finnish band tour simulation?) 01086 * which sets the min/max range and THEN sets up 640x480 256-color mode through the VESA BIOS. 01087 * Without this fix, the cursor is constrained to the upper left hand quadrant of the screen. */ 01088 if (!setmode) { 01089 if (CurMode != NULL) { 01090 mouse.first_range_setx = true; 01091 mouse.first_range_sety = true; 01092 mouse.max_x = CurMode->swidth - 1; 01093 mouse.max_y = CurMode->sheight - 1; 01094 } 01095 else { 01096 mouse.max_x = 639; 01097 mouse.max_y = 479; 01098 } 01099 } 01100 break; 01101 } 01102 mouse.mode = mode; 01103 01104 if (cell_granularity_disable) { 01105 mouse.gran_x = (Bit16s)0xffff; 01106 mouse.gran_y = (Bit16s)0xffff; 01107 } 01108 01109 mouse.events = 0; 01110 mouse.timer_in_progress = false; 01111 PIC_RemoveEvents(MOUSE_Limit_Events); 01112 01113 mouse.hotx = 0; 01114 mouse.hoty = 0; 01115 mouse.background = false; 01116 mouse.screenMask = defaultScreenMask; 01117 mouse.cursorMask = defaultCursorMask; 01118 mouse.textAndMask= defaultTextAndMask; 01119 mouse.textXorMask= defaultTextXorMask; 01120 mouse.language = 0; 01121 mouse.page = 0; 01122 mouse.doubleSpeedThreshold = 64; 01123 mouse.updateRegion_y[1] = -1; //offscreen 01124 mouse.cursorType = 0; 01125 mouse.enabled=true; 01126 01127 mouse.max_screen_x = mouse.max_x; 01128 mouse.max_screen_y = mouse.max_y; 01129 } 01130 01131 //Much too empty, Mouse_NewVideoMode contains stuff that should be in here 01132 static void Mouse_Reset(void) { 01133 Mouse_BeforeNewVideoMode(false); 01134 Mouse_AfterNewVideoMode(false); 01135 Mouse_SetMickeyPixelRate(8,16); 01136 01137 mouse.mickey_x = 0; 01138 mouse.mickey_y = 0; 01139 01140 mouse.buttons = 0; 01141 01142 for (Bit16u but=0; but<MOUSE_BUTTONS; but++) { 01143 mouse.times_pressed[but] = 0; 01144 mouse.times_released[but] = 0; 01145 mouse.last_pressed_x[but] = 0; 01146 mouse.last_pressed_y[but] = 0; 01147 mouse.last_released_x[but] = 0; 01148 mouse.last_released_y[but] = 0; 01149 } 01150 01151 // Dont set max coordinates here. it is done by SetResolution! 01152 mouse.x = static_cast<float>((mouse.max_x + 1)/ 2); 01153 mouse.y = static_cast<float>((mouse.max_y + 1)/ 2); 01154 mouse.sub_mask = 0; 01155 mouse.in_UIR = false; 01156 } 01157 01158 static Bitu INT33_Handler(void) { 01159 // LOG(LOG_MOUSE,LOG_NORMAL)("MOUSE: %04X %X %X %d %d",reg_ax,reg_bx,reg_cx,POS_X,POS_Y); 01160 switch (reg_ax) { 01161 case 0x00: /* Reset Driver and Read Status */ 01162 Mouse_ResetHardware(); 01163 goto software_reset; 01164 case 0x01: /* Show Mouse */ 01165 if (mouse.hidden) mouse.hidden--; 01166 mouse.updateRegion_y[1] = -1; //offscreen 01167 Mouse_AutoLock(true); 01168 DrawCursor(); 01169 break; 01170 case 0x02: /* Hide Mouse */ 01171 { 01172 if (CurMode->type != M_TEXT) RestoreCursorBackground(); 01173 else RestoreCursorBackgroundText(); 01174 if (mouse.hidden == 0) mouse.hidden_at = PIC_FullIndex(); 01175 mouse.hidden++; 01176 } 01177 break; 01178 case 0x03: /* Return position and Button Status */ 01179 reg_bx = mouse.buttons; 01180 reg_cx = (Bit16u)POS_X; 01181 reg_dx = (Bit16u)POS_Y; 01182 mouse.first_range_setx = false; 01183 mouse.first_range_sety = false; 01184 if (en_int33_hide_if_polling) int33_last_poll = PIC_FullIndex(); 01185 break; 01186 case 0x04: /* Position Mouse */ 01187 /* If position isn't different from current position 01188 * don't change it then. (as position is rounded so numbers get 01189 * lost when the rounded number is set) (arena/simulation Wolf) */ 01190 if ((Bit16s)reg_cx >= mouse.max_x) mouse.x = static_cast<float>(mouse.max_x); 01191 else if (mouse.min_x >= (Bit16s)reg_cx) mouse.x = static_cast<float>(mouse.min_x); 01192 else if ((Bit16s)reg_cx != POS_X) mouse.x = static_cast<float>(reg_cx); 01193 01194 if ((Bit16s)reg_dx >= mouse.max_y) mouse.y = static_cast<float>(mouse.max_y); 01195 else if (mouse.min_y >= (Bit16s)reg_dx) mouse.y = static_cast<float>(mouse.min_y); 01196 else if ((Bit16s)reg_dx != POS_Y) mouse.y = static_cast<float>(reg_dx); 01197 DrawCursor(); 01198 if (en_int33_hide_if_polling) int33_last_poll = PIC_FullIndex(); 01199 break; 01200 case 0x05: /* Return Button Press Data */ 01201 { 01202 Bit16u but = reg_bx; 01203 reg_ax = mouse.buttons; 01204 if (but >= MOUSE_BUTTONS) but = MOUSE_BUTTONS - 1; 01205 reg_cx = mouse.last_pressed_x[but]; 01206 reg_dx = mouse.last_pressed_y[but]; 01207 reg_bx = mouse.times_pressed[but]; 01208 mouse.times_pressed[but] = 0; 01209 if (en_int33_hide_if_polling) int33_last_poll = PIC_FullIndex(); 01210 break; 01211 } 01212 case 0x06: /* Return Button Release Data */ 01213 { 01214 Bit16u but = reg_bx; 01215 reg_ax = mouse.buttons; 01216 if (but >= MOUSE_BUTTONS) but = MOUSE_BUTTONS - 1; 01217 reg_cx = mouse.last_released_x[but]; 01218 reg_dx = mouse.last_released_y[but]; 01219 reg_bx = mouse.times_released[but]; 01220 mouse.times_released[but] = 0; 01221 if (en_int33_hide_if_polling) int33_last_poll = PIC_FullIndex(); 01222 break; 01223 } 01224 case 0x07: /* Define horizontal cursor range */ 01225 { 01226 //Lemmings sets 1-640 and wants that. Ironseed sets 0-640 but doesn't like 640 01227 //Ironseed works if newvideo mode with mode 13 sets 0-639 01228 //Larry 6 actually wants newvideo mode with mode 13 to set it to 0-319 01229 Bit16s max, min; 01230 if ((Bit16s)reg_cx < (Bit16s)reg_dx) { min = (Bit16s)reg_cx; max = (Bit16s)reg_dx; } 01231 else { min = (Bit16s)reg_dx; max = (Bit16s)reg_cx; } 01232 mouse.min_x = min; 01233 mouse.max_x = max; 01234 /* Battle Chess wants this */ 01235 if (mouse.x > mouse.max_x) mouse.x = mouse.max_x; 01236 if (mouse.x < mouse.min_x) mouse.x = mouse.min_x; 01237 /* Or alternatively this: 01238 mouse.x = (mouse.max_x - mouse.min_x + 1)/2;*/ 01239 LOG(LOG_MOUSE, LOG_NORMAL)("Define Horizontal range min:%d max:%d", min, max); 01240 01241 /* NTS: The mouse in VESA BIOS modes would ideally start with the x and y ranges 01242 * that fit the screen, but I'm not so sure mouse drivers even pay attention 01243 * to VESA BIOS modes so it's not certain what comes out. However some 01244 * demoscene productions like "Aqua" will set their own mouse range and draw 01245 * their own cursor. The menu in "Aqua" will set up 640x480 256-color mode 01246 * and then set a mouse range of x=0-1279 and y=0-479. Using the FIRST range 01247 * set after mode set is the only way to make sure mouse pointer integration 01248 * tracks the guest pointer properly. */ 01249 if (mouse.first_range_setx || mouse.buttons == 0) { 01250 if (mouse.min_x == 0 && mouse.max_x > 0) { 01251 // most games redefine the range so they can use a saner range matching the screen 01252 Bit16s nval = mouse.max_x; 01253 01254 if (CurMode->type == M_TEXT) { 01255 // Text is reported as if each row is 8 lines high (CGA compat) even if EGA 14-line 01256 // or VGA 16-line, and 8 pixels wide even if EGA/VGA 9-pixels/char is enabled. 01257 // 01258 // Apply sanity rounding. 01259 // 01260 // FreeDOS EDIT: The max is set to just under 640x400, so that the cursor only has 01261 // room for ONE PIXEL in the last row and column. 01262 if (nval >= ((Bit16s)(CurMode->twidth*8) - 32) && nval <= ((Bit16s)(CurMode->twidth*8) + 32)) 01263 nval = (Bit16s)CurMode->twidth*8; 01264 } 01265 else { 01266 // Apply sanity rounding. 01267 // 01268 // Daggerfall: Sets max to 310 instead of 320, probably to prevent drawing the cursor 01269 // partially offscreen. */ 01270 if (nval >= ((Bit16s)CurMode->swidth - 32) && nval <= ((Bit16s)CurMode->swidth + 32)) 01271 nval = (Bit16s)CurMode->swidth; 01272 else if (nval >= (((Bit16s)CurMode->swidth - 32) * 2) && nval <= (((Bit16s)CurMode->swidth + 32) * 2)) 01273 nval = (Bit16s)CurMode->swidth * 2; 01274 } 01275 01276 if (mouse.max_screen_x != nval) { 01277 mouse.max_screen_x = nval; 01278 LOG(LOG_MOUSE, LOG_NORMAL)("Define Horizontal range min:%d max:%d defines the bounds of the screen", min, max); 01279 } 01280 } 01281 mouse.first_range_setx = false; 01282 } 01283 } 01284 break; 01285 case 0x08: /* Define vertical cursor range */ 01286 { 01287 // Not sure what to take instead of the CurMode (see case 0x07 as well) 01288 // especially the cases where sheight= 400 and we set it with the mouse_reset to 200 01289 // disabled it at the moment. Seems to break Syndicate which wants 400 in mode 13 01290 Bit16s max, min; 01291 if ((Bit16s)reg_cx < (Bit16s)reg_dx) { min = (Bit16s)reg_cx; max = (Bit16s)reg_dx; } 01292 else { min = (Bit16s)reg_dx; max = (Bit16s)reg_cx; } 01293 mouse.min_y = min; 01294 mouse.max_y = max; 01295 /* Battle Chess wants this */ 01296 if (mouse.y > mouse.max_y) mouse.y = mouse.max_y; 01297 if (mouse.y < mouse.min_y) mouse.y = mouse.min_y; 01298 /* Or alternatively this: 01299 mouse.y = (mouse.max_y - mouse.min_y + 1)/2;*/ 01300 LOG(LOG_MOUSE, LOG_NORMAL)("Define Vertical range min:%d max:%d", min, max); 01301 01302 /* NTS: The mouse in VESA BIOS modes would ideally start with the x and y ranges 01303 * that fit the screen, but I'm not so sure mouse drivers even pay attention 01304 * to VESA BIOS modes so it's not certain what comes out. However some 01305 * demoscene productions like "Aqua" will set their own mouse range and draw 01306 * their own cursor. The menu in "Aqua" will set up 640x480 256-color mode 01307 * and then set a mouse range of x=0-1279 and y=0-479. Using the FIRST range 01308 * set after mode set is the only way to make sure mouse pointer integration 01309 * tracks the guest pointer properly. */ 01310 if (mouse.first_range_sety || mouse.buttons == 0) { 01311 if (mouse.min_y == 0 && mouse.max_y > 0) { 01312 // most games redefine the range so they can use a saner range matching the screen 01313 Bit16s nval = mouse.max_y; 01314 01315 if (CurMode->type == M_TEXT) { 01316 // Text is reported as if each row is 8 lines high (CGA compat) even if EGA 14-line 01317 // or VGA 16-line, and 8 pixels wide even if EGA/VGA 9-pixels/char is enabled. 01318 // 01319 // Apply sanity rounding. 01320 // 01321 // FreeDOS EDIT: The max is set to just under 640x400, so that the cursor only has 01322 // room for ONE PIXEL in the last row and column. 01323 if (nval >= ((Bit16s)(CurMode->theight*8) - 32) && nval <= ((Bit16s)(CurMode->theight*8) + 32)) 01324 nval = (Bit16s)CurMode->theight*8; 01325 } 01326 else { 01327 // Apply sanity rounding. 01328 // 01329 // Daggerfall: Sets max to 310 instead of 320, probably to prevent drawing the cursor 01330 // partially offscreen. */ 01331 if (nval >= ((Bit16s)CurMode->sheight - 32) && nval <= ((Bit16s)CurMode->sheight + 32)) 01332 nval = (Bit16s)CurMode->sheight; 01333 else if (nval >= (((Bit16s)CurMode->sheight - 32) * 2) && nval <= (((Bit16s)CurMode->sheight + 32) * 2)) 01334 nval = (Bit16s)CurMode->sheight * 2; 01335 } 01336 01337 if (mouse.max_screen_y != nval) { 01338 mouse.max_screen_y = nval; 01339 LOG(LOG_MOUSE, LOG_NORMAL)("Define Vertical range min:%d max:%d defines the bounds of the screen", min, max); 01340 } 01341 } 01342 mouse.first_range_sety = false; 01343 } 01344 } 01345 break; 01346 case 0x09: /* Define GFX Cursor */ 01347 { 01348 PhysPt src = SegPhys(es) + reg_dx; 01349 MEM_BlockRead(src, userdefScreenMask, CURSORY * 2); 01350 MEM_BlockRead(src + CURSORY * 2, userdefCursorMask, CURSORY * 2); 01351 mouse.screenMask = userdefScreenMask; 01352 mouse.cursorMask = userdefCursorMask; 01353 mouse.hotx = (Bit16s)reg_bx; 01354 mouse.hoty = (Bit16s)reg_cx; 01355 mouse.cursorType = 2; 01356 DrawCursor(); 01357 break; 01358 } 01359 case 0x0a: /* Define Text Cursor */ 01360 mouse.cursorType = (reg_bx ? 1 : 0); 01361 mouse.textAndMask = reg_cx; 01362 mouse.textXorMask = reg_dx; 01363 if (reg_bx) { 01364 INT10_SetCursorShape(reg_cl, reg_dl); 01365 LOG(LOG_MOUSE, LOG_NORMAL)("Hardware Text cursor selected"); 01366 } 01367 DrawCursor(); 01368 break; 01369 case 0x0b: /* Read Motion Data */ 01370 { 01371 extern bool MOUSE_IsLocked(); 01372 const auto locked = MOUSE_IsLocked(); 01373 reg_cx = (Bit16u)static_cast<Bit16s>(locked ? mouse.mickey_x : 0); 01374 reg_dx = (Bit16u)static_cast<Bit16s>(locked ? mouse.mickey_y : 0); 01375 mouse.mickey_x = 0; 01376 mouse.mickey_y = 0; 01377 break; 01378 } 01379 case 0x0c: /* Define interrupt subroutine parameters */ 01380 mouse.sub_mask = reg_cx; 01381 mouse.sub_seg = SegValue(es); 01382 mouse.sub_ofs = reg_dx; 01383 Mouse_AutoLock(true); //Some games don't seem to reset the mouse before using 01384 break; 01385 case 0x0d: /* Mouse light pen emulation on */ 01386 LOG(LOG_MOUSE, LOG_ERROR)("Mouse light pen emulation on not implemented"); 01387 break; 01388 case 0x0e: /* Mouse light pen emulation off */ 01389 LOG(LOG_MOUSE, LOG_ERROR)("Mouse light pen emulation off not implemented"); 01390 break; 01391 case 0x0f: /* Define mickey/pixel rate */ 01392 Mouse_SetMickeyPixelRate((Bit16s)reg_cx, (Bit16s)reg_dx); 01393 break; 01394 case 0x10: /* Define screen region for updating */ 01395 mouse.updateRegion_x[0] = (Bit16s)reg_cx; 01396 mouse.updateRegion_y[0] = (Bit16s)reg_dx; 01397 mouse.updateRegion_x[1] = (Bit16s)reg_si; 01398 mouse.updateRegion_y[1] = (Bit16s)reg_di; 01399 DrawCursor(); 01400 break; 01401 case 0x11: /* Get number of buttons */ 01402 reg_ax = 0xffff; 01403 reg_bx = MOUSE_BUTTONS; 01404 break; 01405 case 0x13: /* Set double-speed threshold */ 01406 mouse.doubleSpeedThreshold = (reg_bx ? reg_bx : 64); 01407 break; 01408 case 0x14: /* Exchange event-handler */ 01409 { 01410 Bit16u oldSeg = mouse.sub_seg; 01411 Bit16u oldOfs = mouse.sub_ofs; 01412 Bit16u oldMask = mouse.sub_mask; 01413 // Set new values 01414 mouse.sub_mask = reg_cx; 01415 mouse.sub_seg = SegValue(es); 01416 mouse.sub_ofs = reg_dx; 01417 // Return old values 01418 reg_cx = (Bit16u)oldMask; 01419 reg_dx = (Bit16u)oldOfs; 01420 SegSet16(es, oldSeg); 01421 } 01422 break; 01423 case 0x15: /* Get Driver storage space requirements */ 01424 reg_bx = sizeof(mouse); 01425 break; 01426 case 0x16: /* Save driver state */ 01427 { 01428 LOG(LOG_MOUSE, LOG_NORMAL)("Saving driver state..."); 01429 PhysPt dest = SegPhys(es) + reg_dx; 01430 MEM_BlockWrite(dest, &mouse, sizeof(mouse)); 01431 } 01432 break; 01433 case 0x17: /* load driver state */ 01434 { 01435 LOG(LOG_MOUSE, LOG_NORMAL)("Loading driver state..."); 01436 PhysPt src = SegPhys(es) + reg_dx; 01437 MEM_BlockRead(src, &mouse, sizeof(mouse)); 01438 break; 01439 } 01440 case 0x18: /* Set alternate subroutine call mask and address */ 01441 LOG(LOG_MOUSE, LOG_ERROR)("Set alternate subroutine call mask and address not implemented"); 01442 break; 01443 case 0x19: /* Get user alternate interrupt address*/ 01444 LOG(LOG_MOUSE, LOG_ERROR)("Get user alternate interrupt address not implemented"); 01445 break; 01446 case 0x1a: /* Set mouse sensitivity */ 01447 // ToDo : double mouse speed value 01448 Mouse_SetSensitivity(reg_bx, reg_cx, reg_dx); 01449 LOG(LOG_MOUSE, LOG_NORMAL)("Set sensitivity used with %d %d (%d)", reg_bx, reg_cx, reg_dx); 01450 break; 01451 case 0x1b: /* Get mouse sensitivity */ 01452 reg_bx = mouse.senv_x_val; 01453 reg_cx = mouse.senv_y_val; 01454 reg_dx = mouse.dspeed_val; 01455 01456 LOG(LOG_MOUSE, LOG_NORMAL)("Get sensitivity %d %d", reg_bx, reg_cx); 01457 break; 01458 case 0x1c: /* Set interrupt rate */ 01459 /* Can't really set a rate this is host determined */ 01460 break; 01461 case 0x1d: /* Set display page number */ 01462 mouse.page = reg_bl; 01463 break; 01464 case 0x1e: /* Get display page number */ 01465 reg_bx = mouse.page; 01466 break; 01467 case 0x1f: /* Disable Mousedriver */ 01468 /* ES:BX old mouse driver Zero at the moment TODO */ 01469 reg_bx = 0; 01470 SegSet16(es, 0); 01471 mouse.enabled = false; /* Just for reporting not doing a thing with it */ 01472 mouse.oldhidden = mouse.hidden; 01473 if (!mouse.hidden) { 01474 mouse.hidden = 1; 01475 mouse.hidden_at = PIC_FullIndex(); 01476 } 01477 break; 01478 case 0x20: /* Enable Mousedriver */ 01479 mouse.enabled = true; 01480 mouse.hidden = mouse.oldhidden; 01481 break; 01482 case 0x21: /* Software Reset */ 01483 software_reset: 01484 extern bool Mouse_Drv; 01485 if (Mouse_Drv) { 01486 reg_ax = 0xffff; 01487 reg_bx = MOUSE_BUTTONS; 01488 Mouse_Reset(); 01489 Mouse_AutoLock(true); 01490 AUX_INT33_Takeover(); 01491 LOG(LOG_MOUSE, LOG_NORMAL)("INT 33h reset"); 01492 } 01493 break; 01494 case 0x22: /* Set language for messages */ 01495 /* 01496 * Values for mouse driver language: 01497 * 01498 * 00h English 01499 * 01h French 01500 * 02h Dutch 01501 * 03h German 01502 * 04h Swedish 01503 * 05h Finnish 01504 * 06h Spanish 01505 * 07h Portugese 01506 * 08h Italian 01507 * 01508 */ 01509 mouse.language = reg_bx; 01510 break; 01511 case 0x23: /* Get language for messages */ 01512 reg_bx = mouse.language; 01513 break; 01514 case 0x24: /* Get Software version and mouse type */ 01515 reg_bx = 0x805; //Version 8.05 woohoo 01516 reg_ch = 0x04; /* PS/2 type */ 01517 reg_cl = 0; /* PS/2 (unused) */ 01518 break; 01519 case 0x26: /* Get Maximum virtual coordinates */ 01520 reg_bx = (mouse.enabled ? 0x0000 : 0xffff); 01521 reg_cx = (Bit16u)mouse.max_x; 01522 reg_dx = (Bit16u)mouse.max_y; 01523 break; 01524 case 0x2a: /* Get cursor hot spot */ 01525 reg_al = (Bit8u)-mouse.hidden; // Microsoft uses a negative byte counter for cursor visibility 01526 reg_bx = (Bit16u)mouse.hotx; 01527 reg_cx = (Bit16u)mouse.hoty; 01528 reg_dx = 0x04; // PS/2 mouse type 01529 break; 01530 case 0x31: /* Get Current Minimum/Maximum virtual coordinates */ 01531 reg_ax = (Bit16u)mouse.min_x; 01532 reg_bx = (Bit16u)mouse.min_y; 01533 reg_cx = (Bit16u)mouse.max_x; 01534 reg_dx = (Bit16u)mouse.max_y; 01535 break; 01536 case 0x53C1: /* Logitech CyberMan */ 01537 LOG(LOG_MOUSE, LOG_NORMAL)("Mouse function 53C1 for Logitech CyberMan called. Ignored by regular mouse driver."); 01538 break; 01539 default: 01540 LOG(LOG_MOUSE, LOG_ERROR)("Mouse Function %04X not implemented!", reg_ax); 01541 break; 01542 } 01543 return CBRET_NONE; 01544 } 01545 01546 static Bitu MOUSE_BD_Handler(void) { 01547 // the stack contains offsets to register values 01548 Bit16u raxpt=real_readw(SegValue(ss),reg_sp+0x0a); 01549 Bit16u rbxpt=real_readw(SegValue(ss),reg_sp+0x08); 01550 Bit16u rcxpt=real_readw(SegValue(ss),reg_sp+0x06); 01551 Bit16u rdxpt=real_readw(SegValue(ss),reg_sp+0x04); 01552 01553 // read out the actual values, registers ARE overwritten 01554 Bit16u rax=real_readw(SegValue(ds),raxpt); 01555 reg_ax=rax; 01556 reg_bx=real_readw(SegValue(ds),rbxpt); 01557 reg_cx=real_readw(SegValue(ds),rcxpt); 01558 reg_dx=real_readw(SegValue(ds),rdxpt); 01559 // LOG_MSG("MOUSE BD: %04X %X %X %X %d %d",reg_ax,reg_bx,reg_cx,reg_dx,POS_X,POS_Y); 01560 01561 // some functions are treated in a special way (additional registers) 01562 switch (rax) { 01563 case 0x09: /* Define GFX Cursor */ 01564 case 0x16: /* Save driver state */ 01565 case 0x17: /* load driver state */ 01566 SegSet16(es,SegValue(ds)); 01567 break; 01568 case 0x0c: /* Define interrupt subroutine parameters */ 01569 case 0x14: /* Exchange event-handler */ 01570 if (reg_bx!=0) SegSet16(es,reg_bx); 01571 else SegSet16(es,SegValue(ds)); 01572 break; 01573 case 0x10: /* Define screen region for updating */ 01574 reg_cx=real_readw(SegValue(ds),rdxpt); 01575 reg_dx=real_readw(SegValue(ds),rdxpt+2); 01576 reg_si=real_readw(SegValue(ds),rdxpt+4); 01577 reg_di=real_readw(SegValue(ds),rdxpt+6); 01578 break; 01579 default: 01580 break; 01581 } 01582 01583 INT33_Handler(); 01584 01585 // save back the registers, too 01586 real_writew(SegValue(ds),raxpt,reg_ax); 01587 real_writew(SegValue(ds),rbxpt,reg_bx); 01588 real_writew(SegValue(ds),rcxpt,reg_cx); 01589 real_writew(SegValue(ds),rdxpt,reg_dx); 01590 switch (rax) { 01591 case 0x1f: /* Disable Mousedriver */ 01592 real_writew(SegValue(ds),rbxpt,SegValue(es)); 01593 break; 01594 case 0x14: /* Exchange event-handler */ 01595 real_writew(SegValue(ds),rcxpt,SegValue(es)); 01596 break; 01597 default: 01598 break; 01599 } 01600 01601 reg_ax=rax; 01602 return CBRET_NONE; 01603 } 01604 01605 static Bitu INT74_Handler(void) { 01606 if (mouse.events>0 && !mouse.in_UIR) { 01607 mouse.events--; 01608 01609 /* INT 33h emulation: HERE within the IRQ 12 handler is the appropriate place to 01610 * redraw the cursor. OSes like Windows 3.1 expect real-mode code to do it in 01611 * response to IRQ 12, not "out of the blue" from the SDL event handler like 01612 * the original DOSBox code did it. Doing this allows the INT 33h emulation 01613 * to draw the cursor while not causing Windows 3.1 to crash or behave 01614 * erratically. */ 01615 if (en_int33) DrawCursor(); 01616 01617 /* Check for an active Interrupt Handler that will get called */ 01618 if (mouse.sub_mask & mouse.event_queue[mouse.events].type) { 01619 reg_ax=mouse.event_queue[mouse.events].type; 01620 reg_bx=mouse.event_queue[mouse.events].buttons; 01621 reg_cx=(Bit16u)POS_X; 01622 reg_dx=(Bit16u)POS_Y; 01623 reg_si=(Bit16u)static_cast<Bit16s>(mouse.mickey_x); 01624 reg_di=(Bit16u)static_cast<Bit16s>(mouse.mickey_y); 01625 CPU_Push16(RealSeg(CALLBACK_RealPointer(int74_ret_callback))); 01626 CPU_Push16(RealOff(CALLBACK_RealPointer(int74_ret_callback))+7); 01627 CPU_Push16(RealSeg(uir_callback)); 01628 CPU_Push16(RealOff(uir_callback)); 01629 CPU_Push16(mouse.sub_seg); 01630 CPU_Push16(mouse.sub_ofs); 01631 mouse.in_UIR = true; 01632 } else if (useps2callback) { 01633 CPU_Push16(RealSeg(CALLBACK_RealPointer(int74_ret_callback))); 01634 CPU_Push16(RealOff(CALLBACK_RealPointer(int74_ret_callback))); 01635 DoPS2Callback(mouse.event_queue[mouse.events].buttons, static_cast<Bit16s>(mouse.ps2x), static_cast<Bit16s>(mouse.ps2y)); 01636 } else { 01637 SegSet16(cs, RealSeg(CALLBACK_RealPointer(int74_ret_callback))); 01638 reg_ip = RealOff(CALLBACK_RealPointer(int74_ret_callback)); 01639 } 01640 } else { 01641 SegSet16(cs, RealSeg(CALLBACK_RealPointer(int74_ret_callback))); 01642 reg_ip = RealOff(CALLBACK_RealPointer(int74_ret_callback)); 01643 } 01644 return CBRET_NONE; 01645 } 01646 01647 Bitu INT74_Ret_Handler(void) { 01648 if (mouse.events) { 01649 if (!mouse.timer_in_progress) { 01650 mouse.timer_in_progress = true; 01651 PIC_AddEvent(MOUSE_Limit_Events,MOUSE_DELAY); 01652 } 01653 } 01654 return CBRET_NONE; 01655 } 01656 01657 Bitu UIR_Handler(void) { 01658 mouse.in_UIR = false; 01659 return CBRET_NONE; 01660 } 01661 01662 bool MouseTypeNone(); 01663 01664 void MOUSE_OnReset(Section *sec) { 01665 (void)sec;//UNUSED 01666 if (IS_PC98_ARCH) 01667 MOUSE_IRQ = 13; // PC-98 standard 01668 else if (!enable_slave_pic) 01669 MOUSE_IRQ = 0; 01670 else 01671 MOUSE_IRQ = 12; // IBM PC/AT standard 01672 01673 if (MOUSE_IRQ != 0) 01674 PIC_SetIRQMask(MOUSE_IRQ,true); 01675 } 01676 01677 void MOUSE_ShutDown(Section *sec) { 01678 (void)sec;//UNUSED 01679 } 01680 01681 void BIOS_PS2MOUSE_ShutDown(Section *sec) { 01682 (void)sec;//UNUSED 01683 } 01684 01685 void BIOS_PS2Mouse_Startup(Section *sec) { 01686 (void)sec;//UNUSED 01687 Section_prop *section=static_cast<Section_prop *>(control->GetSection("dos")); 01688 01689 /* NTS: This assumes MOUSE_Init() is called after KEYBOARD_Init() */ 01690 en_bios_ps2mouse = section->Get_bool("biosps2"); 01691 01692 if (!enable_slave_pic || machine == MCH_PCJR) return; 01693 01694 if (!en_bios_ps2mouse) return; 01695 01696 if (MouseTypeNone()) { 01697 LOG(LOG_MOUSE, LOG_WARN)("INT 15H PS/2 emulation NOT enabled. biosps2=1 but mouse type=none"); 01698 } 01699 else { 01700 LOG(LOG_MOUSE, LOG_NORMAL)("INT 15H PS/2 emulation enabled"); 01701 bios_enable_ps2(); 01702 } 01703 01704 ps2_callback_save_regs = section->Get_bool("int15 mouse callback does not preserve registers"); 01705 01706 // Callback for ps2 irq 01707 call_int74=CALLBACK_Allocate(); 01708 CALLBACK_Setup(call_int74,&INT74_Handler,CB_IRQ12,"int 74"); 01709 // pseudocode for CB_IRQ12: 01710 // sti 01711 // push ds 01712 // push es 01713 // pushad 01714 // sti 01715 // callback INT74_Handler 01716 // ps2 or user callback if requested 01717 // otherwise jumps to CB_IRQ12_RET 01718 // push ax 01719 // mov al, 0x20 01720 // out 0xa0, al 01721 // out 0x20, al 01722 // pop ax 01723 // cld 01724 // retf 01725 01726 int74_ret_callback=CALLBACK_Allocate(); 01727 CALLBACK_Setup(int74_ret_callback,&INT74_Ret_Handler,CB_IRQ12_RET,"int 74 ret"); 01728 // pseudocode for CB_IRQ12_RET: 01729 // cli 01730 // mov al, 0x20 01731 // out 0xa0, al 01732 // out 0x20, al 01733 // callback INT74_Ret_Handler 01734 // popad 01735 // pop es 01736 // pop ds 01737 // iret 01738 01739 if (MOUSE_IRQ != 0) { 01740 Bit8u hwvec=(MOUSE_IRQ>7)?(0x70+MOUSE_IRQ-8):(0x8+MOUSE_IRQ); 01741 RealSetVec(hwvec,CALLBACK_RealPointer(call_int74)); 01742 } 01743 01744 // Callback for ps2 user callback handling 01745 useps2callback = false; ps2callbackinit = false; 01746 if (call_ps2 == 0) 01747 call_ps2 = CALLBACK_Allocate(); 01748 CALLBACK_Setup(call_ps2,&PS2_Handler,CB_RETF,"ps2 bios callback"); 01749 ps2_callback=CALLBACK_RealPointer(call_ps2); 01750 01751 // Callback for mouse user routine return 01752 if (call_uir == 0) 01753 call_uir = CALLBACK_Allocate(); 01754 CALLBACK_Setup(call_uir,&UIR_Handler,CB_RETF_CLI,"mouse uir ret"); 01755 uir_callback=CALLBACK_RealPointer(call_uir); 01756 } 01757 01758 void MOUSE_Startup(Section *sec) { 01759 (void)sec;//UNUSED 01760 Section_prop *section=static_cast<Section_prop *>(control->GetSection("dos")); 01761 Section_prop * pc98_section=static_cast<Section_prop *>(control->GetSection("pc98")); 01762 RealPt i33loc=0; 01763 01764 /* TODO: Needs to check for mouse, and fail to do anything if neither PS/2 nor serial mouse emulation enabled */ 01765 01766 en_int33_hide_if_intsub=section->Get_bool("int33 hide host cursor if interrupt subroutine"); 01767 01768 en_int33_hide_if_polling=section->Get_bool("int33 hide host cursor when polling"); 01769 01770 en_int33_pc98_show_graphics=pc98_section->Get_bool("pc-98 show graphics layer on initialize"); 01771 01772 en_int33=section->Get_bool("int33"); 01773 if (!en_int33) { 01774 Mouse_Reset(); 01775 Mouse_SetSensitivity(50,50,50); 01776 return; 01777 } 01778 01779 cell_granularity_disable=section->Get_bool("int33 disable cell granularity"); 01780 01781 LOG(LOG_MOUSE, LOG_NORMAL)("INT 33H emulation enabled"); 01782 if (en_int33_hide_if_polling) 01783 LOG(LOG_MOUSE, LOG_NORMAL)("INT 33H emulation will hide host cursor if polling"); 01784 01785 // Callback for mouse interrupt 0x33 01786 call_int33=CALLBACK_Allocate(); 01787 01788 // i33loc=RealMake(CB_SEG+1,(call_int33*CB_SIZE)-0x10); 01789 i33loc=RealMake(DOS_GetMemory(0x1,"i33loc")-1,0x10); 01790 CALLBACK_Setup(call_int33,&INT33_Handler,CB_MOUSE,Real2Phys(i33loc),"Mouse"); 01791 01792 // Wasteland needs low(seg(int33))!=0 and low(ofs(int33))!=0 01793 real_writed(0,0x33<<2,i33loc); 01794 01795 call_mouse_bd=CALLBACK_Allocate(); 01796 CALLBACK_Setup(call_mouse_bd,&MOUSE_BD_Handler,CB_RETF8, 01797 PhysMake(RealSeg(i33loc),RealOff(i33loc)+2),"MouseBD"); 01798 // pseudocode for CB_MOUSE (including the special backdoor entry point): 01799 // jump near i33hd 01800 // callback MOUSE_BD_Handler 01801 // retf 8 01802 // label i33hd: 01803 // callback INT33_Handler 01804 // iret 01805 01806 memset(&mouse,0,sizeof(mouse)); 01807 01808 if (!mouse.hidden) { 01809 mouse.hidden = 1; 01810 mouse.hidden_at = PIC_FullIndex(); 01811 } 01812 01813 mouse.timer_in_progress = false; 01814 mouse.mode = 0xFF; //Non existing mode 01815 mouse.scrollwheel = 0; 01816 01817 mouse.sub_mask=0; 01818 mouse.sub_seg=0x6362; // magic value 01819 mouse.sub_ofs=0; 01820 01821 oldmouseX = oldmouseY = 0; 01822 mouse.ps2x = mouse.ps2y = 0; 01823 01824 Mouse_ResetHardware(); 01825 Mouse_Reset(); 01826 Mouse_SetSensitivity(50,50,50); 01827 } 01828 01829 void MOUSE_Init() { 01830 LOG(LOG_MOUSE, LOG_DEBUG)("Initializing mouse interface emulation"); 01831 01832 // TODO: We need a DOSBox shutdown callback, and we need a shutdown callback for when the DOS kernel begins to unload and on system reset 01833 AddVMEventFunction(VM_EVENT_RESET,AddVMEventFunctionFuncPair(MOUSE_OnReset)); 01834 } 01835 01836 bool MOUSE_IsHidden() 01837 { 01838 /* mouse is returned hidden IF hidden for more than 100ms. 01839 * rapidly hiding/showing should not signal hidden (FreeDOS EDIT.COM) */ 01840 return static_cast<bool>(mouse.hidden) && (PIC_FullIndex() >= (mouse.hidden_at + 100)); 01841 } 01842 01843 bool MOUSE_IsBeingPolled() 01844 { 01845 if (!en_int33_hide_if_polling) 01846 return false; 01847 01848 return (PIC_FullIndex() < (int33_last_poll + 1000)); 01849 } 01850 01851 bool MOUSE_HasInterruptSub() 01852 { 01853 if (!en_int33_hide_if_intsub) 01854 return false; 01855 01856 return (mouse.sub_mask != 0); 01857 } 01858 01859 //save state support 01860 void *MOUSE_Limit_Events_PIC_Event = (void*)((uintptr_t)MOUSE_Limit_Events); 01861 01862 01863 namespace 01864 { 01865 class SerializeMouse : public SerializeGlobalPOD 01866 { 01867 public: 01868 SerializeMouse() : SerializeGlobalPOD("Mouse") 01869 {} 01870 01871 private: 01872 virtual void getBytes(std::ostream& stream) 01873 { 01874 Bit8u screenMask_idx, cursorMask_idx; 01875 01876 01877 if( mouse.screenMask == defaultScreenMask ) screenMask_idx = 0x00; 01878 else if( mouse.screenMask == userdefScreenMask ) screenMask_idx = 0x01; 01879 01880 if( mouse.cursorMask == defaultCursorMask ) cursorMask_idx = 0x00; 01881 else if( mouse.cursorMask == userdefCursorMask ) cursorMask_idx = 0x01; 01882 01883 //******************************************* 01884 //******************************************* 01885 //******************************************* 01886 01887 SerializeGlobalPOD::getBytes(stream); 01888 01889 01890 // - pure data 01891 WRITE_POD( &ps2cbseg, ps2cbseg ); 01892 WRITE_POD( &ps2cbofs, ps2cbofs ); 01893 WRITE_POD( &useps2callback, useps2callback ); 01894 WRITE_POD( &ps2callbackinit, ps2callbackinit ); 01895 01896 WRITE_POD( &userdefScreenMask, userdefScreenMask ); 01897 WRITE_POD( &userdefCursorMask, userdefCursorMask ); 01898 01899 01900 // - near-pure data 01901 WRITE_POD( &mouse, mouse ); 01902 01903 // - pure data 01904 WRITE_POD( &gfxReg3CE, gfxReg3CE ); 01905 WRITE_POD( &index3C4, index3C4 ); 01906 WRITE_POD( &gfxReg3C5, gfxReg3C5 ); 01907 01908 //******************************************* 01909 //******************************************* 01910 //******************************************* 01911 01912 // - reloc ptr 01913 WRITE_POD( &screenMask_idx, screenMask_idx ); 01914 WRITE_POD( &cursorMask_idx, cursorMask_idx ); 01915 } 01916 01917 virtual void setBytes(std::istream& stream) 01918 { 01919 Bit8u screenMask_idx, cursorMask_idx; 01920 01921 //******************************************* 01922 //******************************************* 01923 //******************************************* 01924 01925 SerializeGlobalPOD::setBytes(stream); 01926 01927 // - pure data 01928 READ_POD( &ps2cbseg, ps2cbseg ); 01929 READ_POD( &ps2cbofs, ps2cbofs ); 01930 READ_POD( &useps2callback, useps2callback ); 01931 READ_POD( &ps2callbackinit, ps2callbackinit ); 01932 01933 READ_POD( &userdefScreenMask, userdefScreenMask ); 01934 READ_POD( &userdefCursorMask, userdefCursorMask ); 01935 01936 01937 // - near-pure data 01938 READ_POD( &mouse, mouse ); 01939 01940 01941 // - pure data 01942 READ_POD( &gfxReg3CE, gfxReg3CE ); 01943 READ_POD( &index3C4, index3C4 ); 01944 READ_POD( &gfxReg3C5, gfxReg3C5 ); 01945 01946 //******************************************* 01947 //******************************************* 01948 //******************************************* 01949 01950 // - reloc ptr 01951 READ_POD( &screenMask_idx, screenMask_idx ); 01952 READ_POD( &cursorMask_idx, cursorMask_idx ); 01953 01954 01955 if( screenMask_idx == 0x00 ) mouse.screenMask = defaultScreenMask; 01956 else if( screenMask_idx == 0x01 ) mouse.screenMask = userdefScreenMask; 01957 01958 if( cursorMask_idx == 0x00 ) mouse.cursorMask = defaultCursorMask; 01959 else if( cursorMask_idx == 0x01 ) mouse.cursorMask = userdefCursorMask; 01960 01961 //******************************************* 01962 //******************************************* 01963 //******************************************* 01964 01965 // reset 01966 oldmouseX = static_cast<Bit16s>(mouse.x); 01967 oldmouseY = static_cast<Bit16s>(mouse.y); 01968 } 01969 } dummy; 01970 }