1 /*
2 * Copyright (C) 2002-2010 The DOSBox Team
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /* $Id: joystick.cpp,v 1.21 2009-05-27 09:15:41 qbix79 Exp $ */
20
21 #include <string.h>
22 #include "dosbox.h"
23 #include "inout.h"
24 #include "setup.h"
25 #include "joystick.h"
26 #include "pic.h"
27 #include "support.h"
28
29 #define RANGE 64
30 #define TIMEOUT 10
31
32 #define OHMS 120000/2
33 #define JOY_S_CONSTANT 0.0000242
34 #define S_PER_OHM 0.000000011
35
36 struct JoyStick {
37 bool enabled;
38 float xpos,ypos;
39 double xtick,ytick;
40 Bitu xcount,ycount;
41 bool button[2];
42 };
43
44 JoystickType joytype;
45 static JoyStick stick[2];
46
47 static Bit32u last_write = 0;
48 static bool write_active = false;
49 static bool swap34 = false;
50 bool button_wrapping_enabled = true;
51
52 extern bool autofire; //sdl_mapper.cpp
53
read_p201(Bitu port,Bitu iolen)54 static Bitu read_p201(Bitu port,Bitu iolen) {
55 /* Reset Joystick to 0 after TIMEOUT ms */
56 if(write_active && ((PIC_Ticks - last_write) > TIMEOUT)) {
57 write_active = false;
58 stick[0].xcount = 0;
59 stick[1].xcount = 0;
60 stick[0].ycount = 0;
61 stick[1].ycount = 0;
62 // LOG_MSG("reset by time %d %d",PIC_Ticks,last_write);
63 }
64
65 /** Format of the byte to be returned:
66 ** | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
67 ** +-------------------------------+
68 ** | | | | | | | |
69 ** Joystick B, Button 2 ---+ | | | | | | +--- Joystick A, X Axis
70 ** Joystick B, Button 1 -------+ | | | | +------- Joystick A, Y Axis
71 ** Joystick A, Button 2 -----------+ | | +----------- Joystick B, X Axis
72 ** Joystick A, Button 1 ---------------+ +--------------- Joystick B, Y Axis
73 **/
74 Bit8u ret=0xff;
75 if (stick[0].enabled) {
76 if (stick[0].xcount) stick[0].xcount--; else ret&=~1;
77 if (stick[0].ycount) stick[0].ycount--; else ret&=~2;
78 if (stick[0].button[0]) ret&=~16;
79 if (stick[0].button[1]) ret&=~32;
80 }
81 if (stick[1].enabled) {
82 if (stick[1].xcount) stick[1].xcount--; else ret&=~4;
83 if (stick[1].ycount) stick[1].ycount--; else ret&=~8;
84 if (stick[1].button[0]) ret&=~64;
85 if (stick[1].button[1]) ret&=~128;
86 }
87 return ret;
88 }
89
read_p201_timed(Bitu port,Bitu iolen)90 static Bitu read_p201_timed(Bitu port,Bitu iolen) {
91 Bit8u ret=0xff;
92 double currentTick = PIC_FullIndex();
93 if( stick[0].enabled ){
94 if( stick[0].xtick < currentTick ) ret &=~1;
95 if( stick[0].ytick < currentTick ) ret &=~2;
96 }
97 if( stick[1].enabled ){
98 if( stick[1].xtick < currentTick ) ret &=~4;
99 if( stick[1].ytick < currentTick ) ret &=~8;
100 }
101
102 if (stick[0].enabled) {
103 if (stick[0].button[0]) ret&=~16;
104 if (stick[0].button[1]) ret&=~32;
105 }
106 if (stick[1].enabled) {
107 if (stick[1].button[0]) ret&=~64;
108 if (stick[1].button[1]) ret&=~128;
109 }
110 return ret;
111 }
112
write_p201(Bitu port,Bitu val,Bitu iolen)113 static void write_p201(Bitu port,Bitu val,Bitu iolen) {
114 /* Store writetime index */
115 write_active = true;
116 last_write = PIC_Ticks;
117 if (stick[0].enabled) {
118 stick[0].xcount=(Bitu)((stick[0].xpos*RANGE)+RANGE);
119 stick[0].ycount=(Bitu)((stick[0].ypos*RANGE)+RANGE);
120 }
121 if (stick[1].enabled) {
122 stick[1].xcount=(Bitu)(((swap34? stick[1].ypos : stick[1].xpos)*RANGE)+RANGE);
123 stick[1].ycount=(Bitu)(((swap34? stick[1].xpos : stick[1].ypos)*RANGE)+RANGE);
124 }
125
126 }
write_p201_timed(Bitu port,Bitu val,Bitu iolen)127 static void write_p201_timed(Bitu port,Bitu val,Bitu iolen) {
128 // Store writetime index
129 // Axes take time = 24.2 microseconds + ( 0.011 microsecons/ohm * resistance )
130 // to reset to 0
131 // Precalculate the time at which each axis hits 0 here
132 double currentTick = PIC_FullIndex();
133 if (stick[0].enabled) {
134 stick[0].xtick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM *
135 (double)(((stick[0].xpos+1.0)* OHMS)) );
136 stick[0].ytick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM *
137 (double)(((stick[0].ypos+1.0)* OHMS)) );
138 }
139 if (stick[1].enabled) {
140 stick[1].xtick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM *
141 (double)((swap34? stick[1].ypos : stick[1].xpos)+1.0) * OHMS);
142 stick[1].ytick = currentTick + 1000.0*( JOY_S_CONSTANT + S_PER_OHM *
143 (double)((swap34? stick[1].xpos : stick[1].ypos)+1.0) * OHMS);
144 }
145 }
146
JOYSTICK_Enable(Bitu which,bool enabled)147 void JOYSTICK_Enable(Bitu which,bool enabled) {
148 if (which<2) stick[which].enabled=enabled;
149 }
150
JOYSTICK_Button(Bitu which,Bitu num,bool pressed)151 void JOYSTICK_Button(Bitu which,Bitu num,bool pressed) {
152 if ((which<2) && (num<2)) stick[which].button[num]=pressed;
153 }
154
JOYSTICK_Move_X(Bitu which,float x)155 void JOYSTICK_Move_X(Bitu which,float x) {
156 if (which<2) {
157 stick[which].xpos=x;
158 }
159 }
160
JOYSTICK_Move_Y(Bitu which,float y)161 void JOYSTICK_Move_Y(Bitu which,float y) {
162 if (which<2) {
163 stick[which].ypos=y;
164 }
165 }
166
JOYSTICK_IsEnabled(Bitu which)167 bool JOYSTICK_IsEnabled(Bitu which) {
168 if (which<2) return stick[which].enabled;
169 return false;
170 }
171
JOYSTICK_GetButton(Bitu which,Bitu num)172 bool JOYSTICK_GetButton(Bitu which, Bitu num) {
173 if ((which<2) && (num<2)) return stick[which].button[num];
174 return false;
175 }
176
JOYSTICK_GetMove_X(Bitu which)177 float JOYSTICK_GetMove_X(Bitu which) {
178 if (which<2) return stick[which].xpos;
179 return 0.0f;
180 }
181
JOYSTICK_GetMove_Y(Bitu which)182 float JOYSTICK_GetMove_Y(Bitu which) {
183 if (which<2) return stick[which].ypos;
184 return 0.0f;
185 }
186
187 class JOYSTICK:public Module_base{
188 private:
189 IO_ReadHandleObject ReadHandler;
190 IO_WriteHandleObject WriteHandler;
191 public:
JOYSTICK(Section * configuration)192 JOYSTICK(Section* configuration):Module_base(configuration){
193 Section_prop * section=static_cast<Section_prop *>(configuration);
194 const char * type=section->Get_string("joysticktype");
195 if (!strcasecmp(type,"none")) joytype = JOY_NONE;
196 else if (!strcasecmp(type,"false")) joytype = JOY_NONE;
197 else if (!strcasecmp(type,"auto")) joytype = JOY_AUTO;
198 else if (!strcasecmp(type,"2axis")) joytype = JOY_2AXIS;
199 else if (!strcasecmp(type,"4axis")) joytype = JOY_4AXIS;
200 else if (!strcasecmp(type,"4axis_2")) joytype = JOY_4AXIS_2;
201 else if (!strcasecmp(type,"fcs")) joytype = JOY_FCS;
202 else if (!strcasecmp(type,"ch")) joytype = JOY_CH;
203 else joytype = JOY_AUTO;
204
205 bool timed = section->Get_bool("timed");
206 if(timed) {
207 ReadHandler.Install(0x201,read_p201_timed,IO_MB);
208 WriteHandler.Install(0x201,write_p201_timed,IO_MB);
209 } else {
210 ReadHandler.Install(0x201,read_p201,IO_MB);
211 WriteHandler.Install(0x201,write_p201,IO_MB);
212 }
213 autofire = section->Get_bool("autofire");
214 swap34 = section->Get_bool("swap34");
215 button_wrapping_enabled = section->Get_bool("buttonwrap");
216 stick[0].enabled = false;
217 stick[1].enabled = false;
218 stick[0].xtick = stick[0].ytick = stick[1].xtick =
219 stick[1].ytick = PIC_FullIndex();
220 }
221 };
222 static JOYSTICK* test;
223
JOYSTICK_Destroy(Section * sec)224 void JOYSTICK_Destroy(Section* sec) {
225 delete test;
226 }
227
JOYSTICK_Init(Section * sec)228 void JOYSTICK_Init(Section* sec) {
229 test = new JOYSTICK(sec);
230 sec->AddDestroyFunction(&JOYSTICK_Destroy,true);
231 }
232