1 #ifdef SYSTEM_CPP
2
3 Input input;
4
port_read(bool portnumber)5 uint8 Input::port_read(bool portnumber) {
6 port_t &p = port[portnumber];
7
8 switch(p.device) {
9 case DeviceJoypad: {
10 if(p.counter0 >= 16) return 1;
11 return system.interface->input_poll(portnumber, p.device, 0, p.counter0++);
12 } //case DeviceJoypad
13
14 case DeviceMultitap: {
15 if(cpu.joylatch()) return 2; //when latch is high -- data2 = 1, data1 = 0
16
17 unsigned deviceidx, deviceindex0, deviceindex1;
18 uint8 mask = (portnumber == 0 ? 0x40 : 0x80);
19
20 if(cpu.pio() & mask) {
21 deviceidx = p.counter0;
22 if(deviceidx >= 16) return 3;
23 p.counter0++;
24
25 deviceindex0 = 0; //controller 1
26 deviceindex1 = 1; //controller 2
27 } else {
28 deviceidx = p.counter1;
29 if(deviceidx >= 16) return 3;
30 p.counter1++;
31
32 deviceindex0 = 2; //controller 3
33 deviceindex1 = 3; //controller 4
34 }
35
36 return (system.interface->input_poll(portnumber, p.device, deviceindex0, deviceidx) << 0)
37 | (system.interface->input_poll(portnumber, p.device, deviceindex1, deviceidx) << 1);
38 } //case DeviceMultitap
39
40 case DeviceMouse: {
41 if(p.counter0 >= 32) return 1;
42
43 int position_x = system.interface->input_poll(portnumber, p.device, 0, MouseX); //-n = left, 0 = center, +n = right
44 int position_y = system.interface->input_poll(portnumber, p.device, 0, MouseY); //-n = up, 0 = center, +n = right
45
46 bool direction_x = position_x < 0; //0 = right, 1 = left
47 bool direction_y = position_y < 0; //0 = down, 1 = up
48
49 if(position_x < 0) position_x = -position_x; //abs(position_x)
50 if(position_y < 0) position_y = -position_y; //abs(position_x)
51
52 position_x = min(127, position_x); //range = 0 - 127
53 position_y = min(127, position_y); //range = 0 - 127
54
55 switch(p.counter0++) { default:
56 case 0: return 0;
57 case 1: return 0;
58 case 2: return 0;
59 case 3: return 0;
60 case 4: return 0;
61 case 5: return 0;
62 case 6: return 0;
63 case 7: return 0;
64
65 case 8: return system.interface->input_poll(portnumber, p.device, 0, MouseRight);
66 case 9: return system.interface->input_poll(portnumber, p.device, 0, MouseLeft);
67 case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
68 case 11: return 0; // ||
69
70 case 12: return 0; //signature
71 case 13: return 0; // ||
72 case 14: return 0; // ||
73 case 15: return 1; // ||
74
75 case 16: return (direction_y) & 1;
76 case 17: return (position_y >> 6) & 1;
77 case 18: return (position_y >> 5) & 1;
78 case 19: return (position_y >> 4) & 1;
79 case 20: return (position_y >> 3) & 1;
80 case 21: return (position_y >> 2) & 1;
81 case 22: return (position_y >> 1) & 1;
82 case 23: return (position_y >> 0) & 1;
83
84 case 24: return (direction_x) & 1;
85 case 25: return (position_x >> 6) & 1;
86 case 26: return (position_x >> 5) & 1;
87 case 27: return (position_x >> 4) & 1;
88 case 28: return (position_x >> 3) & 1;
89 case 29: return (position_x >> 2) & 1;
90 case 30: return (position_x >> 1) & 1;
91 case 31: return (position_x >> 0) & 1;
92 }
93 } //case DeviceMouse
94
95 case DeviceSuperScope: {
96 if(portnumber == 0) break; //Super Scope in port 1 not supported ...
97 if(p.counter0 >= 8) return 1;
98
99 if(p.counter0 == 0) {
100 //turbo is a switch; toggle is edge sensitive
101 bool turbo = system.interface->input_poll(portnumber, p.device, 0, SuperScopeTurbo);
102 if(turbo && !p.superscope.turbolock) {
103 p.superscope.turbo = !p.superscope.turbo; //toggle state
104 p.superscope.turbolock = true;
105 } else if(!turbo) {
106 p.superscope.turbolock = false;
107 }
108
109 //trigger is a button
110 //if turbo is active, trigger is level sensitive; otherwise it is edge sensitive
111 p.superscope.trigger = false;
112 bool trigger = system.interface->input_poll(portnumber, p.device, 0, SuperScopeTrigger);
113 if(trigger && (p.superscope.turbo || !p.superscope.triggerlock)) {
114 p.superscope.trigger = true;
115 p.superscope.triggerlock = true;
116 } else if(!trigger) {
117 p.superscope.triggerlock = false;
118 }
119
120 //cursor is a button; it is always level sensitive
121 p.superscope.cursor = system.interface->input_poll(portnumber, p.device, 0, SuperScopeCursor);
122
123 //pause is a button; it is always edge sensitive
124 p.superscope.pause = false;
125 bool pause = system.interface->input_poll(portnumber, p.device, 0, SuperScopePause);
126 if(pause && !p.superscope.pauselock) {
127 p.superscope.pause = true;
128 p.superscope.pauselock = true;
129 } else if(!pause) {
130 p.superscope.pauselock = false;
131 }
132
133 p.superscope.offscreen =
134 p.superscope.x < 0 || p.superscope.x >= 256
135 || p.superscope.y < 0 || p.superscope.y >= (ppu.overscan() ? 240 : 225);
136 }
137
138 switch(p.counter0++) {
139 case 0: return p.superscope.trigger;
140 case 1: return p.superscope.cursor;
141 case 2: return p.superscope.turbo;
142 case 3: return p.superscope.pause;
143 case 4: return 0;
144 case 5: return 0;
145 case 6: return p.superscope.offscreen;
146 case 7: return 0; //noise (1 = yes)
147 }
148 } //case DeviceSuperScope
149
150 case DeviceJustifier:
151 case DeviceJustifiers: {
152 if(portnumber == 0) break; //Justifier in port 1 not supported ...
153 if(p.counter0 >= 32) return 1;
154
155 if(p.counter0 == 0) {
156 p.justifier.trigger1 = system.interface->input_poll(portnumber, p.device, 0, JustifierTrigger);
157 p.justifier.start1 = system.interface->input_poll(portnumber, p.device, 0, JustifierStart);
158
159 if(p.device == DeviceJustifiers) {
160 p.justifier.trigger2 = system.interface->input_poll(portnumber, p.device, 1, JustifierTrigger);
161 p.justifier.start2 = system.interface->input_poll(portnumber, p.device, 1, JustifierStart);
162 } else {
163 p.justifier.x2 = -1;
164 p.justifier.y2 = -1;
165
166 p.justifier.trigger2 = false;
167 p.justifier.start2 = false;
168 }
169 }
170
171 switch(p.counter0++) {
172 case 0: return 0;
173 case 1: return 0;
174 case 2: return 0;
175 case 3: return 0;
176 case 4: return 0;
177 case 5: return 0;
178 case 6: return 0;
179 case 7: return 0;
180 case 8: return 0;
181 case 9: return 0;
182 case 10: return 0;
183 case 11: return 0;
184
185 case 12: return 1; //signature
186 case 13: return 1; // ||
187 case 14: return 1; // ||
188 case 15: return 0; // ||
189
190 case 16: return 0;
191 case 17: return 1;
192 case 18: return 0;
193 case 19: return 1;
194 case 20: return 0;
195 case 21: return 1;
196 case 22: return 0;
197 case 23: return 1;
198
199 case 24: return p.justifier.trigger1;
200 case 25: return p.justifier.trigger2;
201 case 26: return p.justifier.start1;
202 case 27: return p.justifier.start2;
203 case 28: return p.justifier.active;
204
205 case 29: return 0;
206 case 30: return 0;
207 case 31: return 0;
208 }
209 } //case DeviceJustifier(s)
210 } //switch(p.device)
211
212 //no device connected
213 return 0;
214 }
215
216 //scan all input; update cursor positions if needed
update()217 void Input::update() {
218 system.interface->input_poll();
219 port_t &p = port[1];
220
221 switch(p.device) {
222 case DeviceSuperScope: {
223 int x = system.interface->input_poll(1, p.device, 0, SuperScopeX);
224 int y = system.interface->input_poll(1, p.device, 0, SuperScopeY);
225 x += p.superscope.x;
226 y += p.superscope.y;
227 p.superscope.x = max(-16, min(256 + 16, x));
228 p.superscope.y = max(-16, min(240 + 16, y));
229
230 latchx = p.superscope.x;
231 latchy = p.superscope.y;
232 } break;
233
234 case DeviceJustifier:
235 case DeviceJustifiers: {
236 int x1 = system.interface->input_poll(1, p.device, 0, JustifierX);
237 int y1 = system.interface->input_poll(1, p.device, 0, JustifierY);
238 x1 += p.justifier.x1;
239 y1 += p.justifier.y1;
240 p.justifier.x1 = max(-16, min(256 + 16, x1));
241 p.justifier.y1 = max(-16, min(240 + 16, y1));
242
243 int x2 = system.interface->input_poll(1, p.device, 1, JustifierX);
244 int y2 = system.interface->input_poll(1, p.device, 1, JustifierY);
245 x2 += p.justifier.x2;
246 y2 += p.justifier.y2;
247 p.justifier.x2 = max(-16, min(256 + 16, x2));
248 p.justifier.y2 = max(-16, min(240 + 16, y2));
249
250 if(p.justifier.active == 0) {
251 latchx = p.justifier.x1;
252 latchy = p.justifier.y1;
253 } else {
254 latchx = (p.device == DeviceJustifiers ? p.justifier.x2 : -1);
255 latchy = (p.device == DeviceJustifiers ? p.justifier.y2 : -1);
256 }
257 } break;
258 }
259
260 if(latchy < 0 || latchy >= (ppu.overscan() ? 240 : 225) || latchx < 0 || latchx >= 256) {
261 //cursor is offscreen, set to invalid position so counters are not latched
262 latchx = ~0;
263 latchy = ~0;
264 } else {
265 //cursor is onscreen
266 latchx += 40; //offset trigger position to simulate hardware latching delay
267 latchx <<= 2; //dot -> clock conversion
268 latchx += 2; //align trigger on half-dot ala interrupts (speed optimization for sCPU::add_clocks)
269 }
270 }
271
port_set_device(bool portnumber,unsigned device)272 void Input::port_set_device(bool portnumber, unsigned device) {
273 port_t &p = port[portnumber];
274
275 p.device = device;
276 p.counter0 = 0;
277 p.counter1 = 0;
278
279 //set iobit to true if device is capable of latching PPU counters
280 iobit = port[1].device == DeviceSuperScope
281 || port[1].device == DeviceJustifier
282 || port[1].device == DeviceJustifiers;
283 latchx = -1;
284 latchy = -1;
285
286 if(device == DeviceSuperScope) {
287 p.superscope.x = 256 / 2;
288 p.superscope.y = 240 / 2;
289
290 p.superscope.trigger = false;
291 p.superscope.cursor = false;
292 p.superscope.turbo = false;
293 p.superscope.pause = false;
294 p.superscope.offscreen = false;
295
296 p.superscope.turbolock = false;
297 p.superscope.triggerlock = false;
298 p.superscope.pauselock = false;
299 } else if(device == DeviceJustifier) {
300 p.justifier.active = 0;
301 p.justifier.x1 = 256 / 2;
302 p.justifier.y1 = 240 / 2;
303 p.justifier.x2 = -1;
304 p.justifier.y2 = -1;
305
306 p.justifier.trigger1 = false;
307 p.justifier.trigger2 = false;
308 p.justifier.start1 = false;
309 p.justifier.start2 = false;
310 } else if(device == DeviceJustifiers) {
311 p.justifier.active = 0;
312 p.justifier.x1 = 256 / 2 - 16;
313 p.justifier.y1 = 240 / 2;
314 p.justifier.x2 = 256 / 2 + 16;
315 p.justifier.y2 = 240 / 2;
316
317 p.justifier.trigger1 = false;
318 p.justifier.trigger2 = false;
319 p.justifier.start1 = false;
320 p.justifier.start2 = false;
321 }
322 }
323
poll()324 void Input::poll() {
325 port[0].counter0 = 0;
326 port[0].counter1 = 0;
327 port[1].counter0 = 0;
328 port[1].counter1 = 0;
329
330 port[1].justifier.active = !port[1].justifier.active;
331 }
332
init()333 void Input::init() {
334 }
335
336 #endif
337