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 /* Microsoft Serial Mouse compatible emulation. 00020 * Written by Jonathan Campbell */ 00021 00022 #include "dosbox.h" 00023 00024 #include "mouse.h" 00025 #include "setup.h" 00026 #include "serialdummy.h" 00027 #include "serialmouse.h" 00028 #include "serialport.h" 00029 00030 static CSerialMouse *serial_mice[4] = {NULL}; 00031 00032 /* this function is the method the GUI and mouse emulation notifies us of movement/button events. 00033 * if the serial mouse is not installed, it is ignored */ 00034 void on_mouse_event_for_serial(int delta_x,int delta_y,Bit8u buttonstate) { 00035 int i; 00036 00037 for (i=0;i < 4;i++) { 00038 if (serial_mice[i] != NULL) 00039 serial_mice[i]->on_mouse_event(delta_x,delta_y,buttonstate); 00040 } 00041 } 00042 00043 void CSerialMouse::start_packet() { 00044 xmit_another_packet = false; 00045 00046 /* FIX: Default mapping deltas as-is in previous versions of this code 00047 * resulted in serial mouse input that was way too sensitive */ 00048 mouse_delta_x /= 4; 00049 mouse_delta_y /= 4; 00050 00051 if (mouse_delta_x < -128) mouse_delta_x = -128; 00052 else if (mouse_delta_x > 127) mouse_delta_x = 127; 00053 mouse_delta_x &= 0xFF; 00054 00055 if (mouse_delta_y < -128) mouse_delta_y = -128; 00056 else if (mouse_delta_y > 127) mouse_delta_y = 127; 00057 mouse_delta_y &= 0xFF; 00058 00059 /* NOTE TO SELF: Do NOT set bit 7. It confuses CTMOUSE.EXE (CuteMouse) serial support. 00060 * Leaving it clear is the only way to make mouse movement possible. 00061 * Microsoft Windows on the other hand doesn't care if bit 7 is set. */ 00062 packet_xmit = 0; 00063 /* Byte 0: X 1 LB RB Y7 Y6 X7 X6 */ 00064 packet[0] = 0x40 | (mouse_buttons << 4) | (((mouse_delta_y >> 6) & 3) << 2) | ((mouse_delta_x >> 6) & 3); 00065 /* Byte 1: X 0 X5-X0 */ 00066 packet[1] = 0x00 | (mouse_delta_x & 0x3F); 00067 /* Byte 2: X 0 Y5-Y0 */ 00068 packet[2] = 0x00 | (mouse_delta_y & 0x3F); 00069 00070 /* clear counters */ 00071 mouse_delta_x = mouse_delta_y = 0; 00072 00073 setEvent(SERIAL_RX_EVENT, bytetime); 00074 } 00075 00076 void CSerialMouse::on_mouse_event(int delta_x,int delta_y,Bit8u buttonstate) { 00077 mouse_buttons = ((buttonstate & 1) ? 2 : 0) | ((buttonstate & 2) ? 1 : 0); 00078 mouse_delta_x += delta_x; 00079 mouse_delta_y += delta_y; 00080 00081 /* initiate data transfer and form the packet to transmit. if another packet 00082 * is already transmitting now then wait for it to finish before transmitting ours, 00083 * and let the mouse motion accumulate in the meantime */ 00084 if (packet_xmit >= 3) start_packet(); 00085 else xmit_another_packet = true; 00086 } 00087 00088 CSerialMouse::CSerialMouse(Bitu id, CommandLine* cmd):CSerial(id, cmd) { 00089 CSerial::Init_Registers(); 00090 setRI(false); 00091 setDSR(false); 00092 setCD(false); 00093 setCTS(false); 00094 InstallationSuccessful=true; 00095 send_ack=true; 00096 packet_xmit=0xFF; 00097 mouse_buttons=0; 00098 serial_mice[id] = this; /* <- NTS: 'id' is just the index of the serial mouse 0..3 for COM1...COM4 */ 00099 xmit_another_packet=false; 00100 mouse_delta_x=mouse_delta_y=0; 00101 } 00102 00103 CSerialMouse::~CSerialMouse() { 00104 // clear events 00105 removeEvent(SERIAL_TX_EVENT); 00106 } 00107 00108 void CSerialMouse::handleUpperEvent(Bit16u type) { 00109 if(type==SERIAL_TX_EVENT) { 00110 //LOG_MSG("SERIAL_TX_EVENT"); 00111 ByteTransmitted(); // tx timeout 00112 } 00113 else if(type==SERIAL_THR_EVENT){ 00114 //LOG_MSG("SERIAL_THR_EVENT"); 00115 ByteTransmitting(); 00116 setEvent(SERIAL_TX_EVENT,bytetime); 00117 } 00118 else if (type==SERIAL_RX_EVENT) { 00119 // check for bytes to be sent to port 00120 if(CSerial::CanReceiveByte()) { 00121 if (send_ack) { 00122 send_ack = 0; 00123 CSerial::receiveByte('M'); 00124 setEvent(SERIAL_RX_EVENT, bytetime); 00125 } 00126 else if (packet_xmit < 3) { 00127 CSerial::receiveByte(packet[packet_xmit++]); 00128 if (packet_xmit >= 3 && xmit_another_packet) 00129 start_packet(); 00130 else 00131 setEvent(SERIAL_RX_EVENT, bytetime); 00132 } 00133 } 00134 else { 00135 setEvent(SERIAL_RX_EVENT, bytetime); 00136 } 00137 } 00138 } 00139 00140 /*****************************************************************************/ 00141 /* updatePortConfig is called when emulated app changes the serial port **/ 00142 /* parameters baudrate, stopbits, number of databits, parity. **/ 00143 /*****************************************************************************/ 00144 void CSerialMouse::updatePortConfig(Bit16u divider, Bit8u lcr) { 00145 (void)divider;//UNUSED 00146 (void)lcr;//UNUSED 00147 //LOG_MSG("Serial port at 0x%x: Port params changed: %d Baud", base,dcb.BaudRate); 00148 } 00149 00150 void CSerialMouse::updateMSR() { 00151 } 00152 void CSerialMouse::transmitByte(Bit8u val, bool first) { 00153 (void)val;//UNUSED 00154 if(first) setEvent(SERIAL_THR_EVENT, bytetime/10); 00155 else setEvent(SERIAL_TX_EVENT, bytetime); 00156 } 00157 00158 /*****************************************************************************/ 00159 /* setBreak(val) switches break on or off **/ 00160 /*****************************************************************************/ 00161 00162 void CSerialMouse::setBreak(bool value) { 00163 (void)value;//UNUSED 00164 //LOG_MSG("UART 0x%x: Break toggeled: %d", base, value); 00165 } 00166 00167 void CSerialMouse::onMouseReset() { 00168 send_ack = 1; 00169 packet_xmit=0xFF; 00170 mouse_buttons=0; 00171 xmit_another_packet=false; 00172 mouse_delta_x=mouse_delta_y=0; 00173 setEvent(SERIAL_RX_EVENT, bytetime); 00174 Mouse_AutoLock(true); 00175 } 00176 00177 /*****************************************************************************/ 00178 /* setRTSDTR sets the modem control lines **/ 00179 /*****************************************************************************/ 00180 void CSerialMouse::setRTSDTR(bool rts, bool dtr) { 00181 if (rts && dtr && !getRTS() && !getDTR()) { 00182 /* The serial mouse driver turns on the mouse by bringing up 00183 * RTS and DTR. Not just for show, but to give the serial mouse 00184 * a power source to work from. Likewise, drivers "reset" the 00185 * mouse by bringing down the lines, then bringing them back 00186 * up. And most drivers turn off the mouse when not in use by 00187 * bringing them back down and leaving them that way. 00188 * 00189 * We're expected to transmit ASCII character 'M' when first 00190 * initialized, so that the driver knows we're a Microsoft 00191 * compatible serial mouse attached to a COM port. */ 00192 onMouseReset(); 00193 } 00194 00195 setRTS(rts); 00196 setDTR(dtr); 00197 } 00198 void CSerialMouse::setRTS(bool val) { 00199 if (val && !getRTS() && getDTR()) { 00200 onMouseReset(); 00201 } 00202 00203 setCTS(val); 00204 } 00205 void CSerialMouse::setDTR(bool val) { 00206 if (val && !getDTR() && getRTS()) { 00207 onMouseReset(); 00208 } 00209 00210 setDSR(val); 00211 setRI(val); 00212 setCD(val); 00213 }