1 //============================================================================
2 //
3 // SSSS tt lll lll
4 // SS SS tt ll ll
5 // SS tttttt eeee ll ll aaaa
6 // SSSS tt ee ee ll ll aa
7 // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8 // SS SS tt ee ll ll aa aa
9 // SSSS ttt eeeee llll llll aaaaa
10 //
11 // Copyright (c) 1995-2014 by Bradford W. Mott, Stephen Anthony
12 // and the Stella Team
13 //
14 // See the file "License.txt" for information on usage and redistribution of
15 // this file, and for a DISCLAIMER OF ALL WARRANTIES.
16 //
17 // $Id: TrackBall.cxx 2838 2014-01-17 23:34:03Z stephena $
18 //============================================================================
19
20 #include <cstdlib>
21
22 #include "Event.hxx"
23 #include "System.hxx"
24 #include "TIA.hxx"
25 #include "TrackBall.hxx"
26
27 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TrackBall(Jack jack,const Event & event,const System & system,Type type)28 TrackBall::TrackBall(Jack jack, const Event& event, const System& system,
29 Type type)
30 : Controller(jack, event, system, type),
31 myHCounter(0),
32 myVCounter(0),
33 myMouseEnabled(false)
34 {
35 // This code in ::read() is set up to always return IOPortA values in
36 // the lower 4 bits data value
37 // As such, the jack type (left or right) isn't necessary here
38
39 myTrakBallCountH = myTrakBallCountV = 0;
40 myTrakBallLinesH = myTrakBallLinesV = 1;
41
42 myTrakBallLeft = myTrakBallDown = myScanCountV = myScanCountH =
43 myCountV = myCountH = 0;
44
45 // Analog pins are never used by the trackball controller
46 myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance;
47 }
48
49 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
~TrackBall()50 TrackBall::~TrackBall()
51 {
52 }
53
54 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
read()55 uInt8 TrackBall::read()
56 {
57 int scanline = ((System&)mySystem).tia().scanlines();
58
59 if(myScanCountV > scanline) myScanCountV = 0;
60 if(myScanCountH > scanline) myScanCountH = 0;
61 while((myScanCountV + myTrakBallLinesV) < scanline)
62 {
63 if(myTrakBallCountV)
64 {
65 if(myTrakBallDown) myCountV--;
66 else myCountV++;
67 myTrakBallCountV--;
68 }
69 myScanCountV += myTrakBallLinesV;
70 }
71
72 while((myScanCountH + myTrakBallLinesH) < scanline)
73 {
74 if(myTrakBallCountH)
75 {
76 if(myTrakBallLeft) myCountH--;
77 else myCountH++;
78 myTrakBallCountH--;
79 }
80 myScanCountH += myTrakBallLinesH;
81 }
82
83 myCountV &= 0x03;
84 myCountH &= 0x03;
85
86 uInt8 IOPortA = 0x00;
87 switch(myType)
88 {
89 case Controller::TrackBall80:
90 IOPortA = IOPortA
91 | ourTrakBallTableST_V[myCountV]
92 | ourTrakBallTableST_H[myCountH];
93 break;
94 case Controller::TrackBall22:
95 IOPortA = IOPortA
96 | ourTrakBallTableTB_V[myCountV & 0x01][myTrakBallDown]
97 | ourTrakBallTableTB_H[myCountH & 0x01][myTrakBallLeft];
98 break;
99 case Controller::AmigaMouse:
100 IOPortA = IOPortA
101 | ourTrakBallTableAM_V[myCountV]
102 | ourTrakBallTableAM_H[myCountH];
103 break;
104 default:
105 break;
106 }
107
108 myDigitalPinState[One] = IOPortA & 0x10;
109 myDigitalPinState[Two] = IOPortA & 0x20;
110 myDigitalPinState[Three] = IOPortA & 0x40;
111 myDigitalPinState[Four] = IOPortA & 0x80;
112
113 return (IOPortA >> 4);
114 }
115
116 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
update()117 void TrackBall::update()
118 {
119 if(!myMouseEnabled)
120 return;
121
122 // Get the current mouse position
123 myHCounter = myEvent.get(Event::MouseAxisXValue);
124 myVCounter = myEvent.get(Event::MouseAxisYValue);
125
126 if(myVCounter < 0) myTrakBallLeft = 1;
127 else myTrakBallLeft = 0;
128 if(myHCounter < 0) myTrakBallDown = 0;
129 else myTrakBallDown = 1;
130 myTrakBallCountH = abs(myVCounter >> 1);
131 myTrakBallCountV = abs(myHCounter >> 1);
132 myTrakBallLinesH = 200 /*LinesInFrame*/ / (myTrakBallCountH + 1);
133 if(myTrakBallLinesH == 0) myTrakBallLinesH = 1;
134 myTrakBallLinesV = 200 /*LinesInFrame*/ / (myTrakBallCountV + 1);
135 if(myTrakBallLinesV == 0) myTrakBallLinesV = 1;
136
137 // Get mouse button state
138 myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) &&
139 (myEvent.get(Event::MouseButtonRightValue) == 0);
140 }
141
142 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setMouseControl(Controller::Type xtype,int xid,Controller::Type ytype,int yid)143 bool TrackBall::setMouseControl(
144 Controller::Type xtype, int xid, Controller::Type ytype, int yid)
145 {
146 // Currently, the various trackball controllers take full control of the
147 // mouse, and use both mouse buttons for the single fire button
148 // As well, there's no separate setting for x and y axis, so any
149 // combination of Controller and id is valid
150 myMouseEnabled = (xtype == myType || ytype == myType) &&
151 (xid != -1 || yid != -1);
152 return true;
153 }
154
155 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
156 const uInt32 TrackBall::ourTrakBallTableTB_H[2][2] = {
157 { 0x40, 0x00 }, { 0xc0, 0x80 }
158 };
159
160 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
161 const uInt32 TrackBall::ourTrakBallTableTB_V[2][2] = {
162 { 0x00, 0x10 }, { 0x20, 0x30 }
163 };
164
165 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
166 const uInt32 TrackBall::ourTrakBallTableST_H[4] = {
167 0x00, 0x80, 0xc0, 0x40
168 };
169
170 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
171 const uInt32 TrackBall::ourTrakBallTableST_V[4] = {
172 0x00, 0x10, 0x30, 0x20
173 };
174
175 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
176 const uInt32 TrackBall::ourTrakBallTableAM_H[4] = {
177 0x00, 0x10, 0x50, 0x40
178 };
179
180 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
181 const uInt32 TrackBall::ourTrakBallTableAM_V[4] = {
182 0x00, 0x80, 0xa0, 0x20
183 };
184