| 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-2019 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 |  | 
|---|
| 18 | #include "Event.hxx" | 
|---|
| 19 | #include "System.hxx" | 
|---|
| 20 |  | 
|---|
| 21 | #include "Driving.hxx" | 
|---|
| 22 |  | 
|---|
| 23 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 24 | Driving::Driving(Jack jack, const Event& event, const System& system) | 
|---|
| 25 | : Controller(jack, event, system, Controller::Type::Driving), | 
|---|
| 26 | myCounter(0), | 
|---|
| 27 | myGrayIndex(0), | 
|---|
| 28 | myLastYaxis(0), | 
|---|
| 29 | myControlID(-1), | 
|---|
| 30 | myControlIDX(-1), | 
|---|
| 31 | myControlIDY(-1) | 
|---|
| 32 | { | 
|---|
| 33 | if(myJack == Jack::Left) | 
|---|
| 34 | { | 
|---|
| 35 | myCCWEvent   = Event::JoystickZeroLeft; | 
|---|
| 36 | myCWEvent    = Event::JoystickZeroRight; | 
|---|
| 37 | myFireEvent  = Event::JoystickZeroFire; | 
|---|
| 38 | myXAxisValue = Event::PaddleZeroAnalog; | 
|---|
| 39 | myYAxisValue = Event::PaddleOneAnalog; | 
|---|
| 40 | } | 
|---|
| 41 | else | 
|---|
| 42 | { | 
|---|
| 43 | myCCWEvent   = Event::JoystickOneLeft; | 
|---|
| 44 | myCWEvent    = Event::JoystickOneRight; | 
|---|
| 45 | myFireEvent  = Event::JoystickOneFire; | 
|---|
| 46 | myXAxisValue = Event::PaddleTwoAnalog; | 
|---|
| 47 | myYAxisValue = Event::PaddleThreeAnalog; | 
|---|
| 48 | } | 
|---|
| 49 |  | 
|---|
| 50 | // Digital pins 3 and 4 are not connected | 
|---|
| 51 | setPin(DigitalPin::Three, true); | 
|---|
| 52 | setPin(DigitalPin::Four, true); | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 56 | void Driving::update() | 
|---|
| 57 | { | 
|---|
| 58 | // Make sure direct gray codes from Stelladaptor stay in sync with | 
|---|
| 59 | // simulated gray codes generated by PC keyboard or PC joystick | 
|---|
| 60 | myCounter = (myGrayIndex << 2) | (myCounter & 3); | 
|---|
| 61 |  | 
|---|
| 62 | // Digital events (from keyboard or joystick hats & buttons) | 
|---|
| 63 | setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0); | 
|---|
| 64 | int d_axis = myEvent.get(myXAxisValue); | 
|---|
| 65 | if(myEvent.get(myCCWEvent) != 0 || d_axis < -16384)     --myCounter; | 
|---|
| 66 | else if(myEvent.get(myCWEvent) != 0 || d_axis > 16384)  ++myCounter; | 
|---|
| 67 |  | 
|---|
| 68 | // Mouse motion and button events | 
|---|
| 69 | if(myControlID > -1) | 
|---|
| 70 | { | 
|---|
| 71 | int m_axis = myEvent.get(Event::MouseAxisXValue); | 
|---|
| 72 | if(m_axis < -2)     --myCounter; | 
|---|
| 73 | else if(m_axis > 2) ++myCounter; | 
|---|
| 74 | if(myEvent.get(Event::MouseButtonLeftValue) || | 
|---|
| 75 | myEvent.get(Event::MouseButtonRightValue)) | 
|---|
| 76 | setPin(DigitalPin::Six, false); | 
|---|
| 77 | } | 
|---|
| 78 | else | 
|---|
| 79 | { | 
|---|
| 80 | // Test for 'untied' mouse axis mode, where each axis is potentially | 
|---|
| 81 | // mapped to a separate driving controller | 
|---|
| 82 | if(myControlIDX > -1) | 
|---|
| 83 | { | 
|---|
| 84 | int m_axis = myEvent.get(Event::MouseAxisXValue); | 
|---|
| 85 | if(m_axis < -2)     --myCounter; | 
|---|
| 86 | else if(m_axis > 2) ++myCounter; | 
|---|
| 87 | if(myEvent.get(Event::MouseButtonLeftValue)) | 
|---|
| 88 | setPin(DigitalPin::Six, false); | 
|---|
| 89 | } | 
|---|
| 90 | if(myControlIDY > -1) | 
|---|
| 91 | { | 
|---|
| 92 | int m_axis = myEvent.get(Event::MouseAxisYValue); | 
|---|
| 93 | if(m_axis < -2)     --myCounter; | 
|---|
| 94 | else if(m_axis > 2) ++myCounter; | 
|---|
| 95 | if(myEvent.get(Event::MouseButtonRightValue)) | 
|---|
| 96 | setPin(DigitalPin::Six, false); | 
|---|
| 97 | } | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|
| 100 | // Only consider the lower-most bits (corresponding to pins 1 & 2) | 
|---|
| 101 | myCounter &= 0x0f; | 
|---|
| 102 | myGrayIndex = myCounter >> 2; | 
|---|
| 103 |  | 
|---|
| 104 | // Stelladaptor is the only controller that should set this | 
|---|
| 105 | int yaxis = myEvent.get(myYAxisValue); | 
|---|
| 106 |  | 
|---|
| 107 | // Only overwrite gray code when Stelladaptor input has changed | 
|---|
| 108 | // (that means real changes, not just analog signal jitter) | 
|---|
| 109 | if((yaxis < (myLastYaxis - 1024)) || (yaxis > (myLastYaxis + 1024))) | 
|---|
| 110 | { | 
|---|
| 111 | myLastYaxis = yaxis; | 
|---|
| 112 | if(yaxis <= -16384-4096) | 
|---|
| 113 | myGrayIndex = 3; // up | 
|---|
| 114 | else if(yaxis > 16384+4096) | 
|---|
| 115 | myGrayIndex = 1; // down | 
|---|
| 116 | else if(yaxis >= 16384-4096) | 
|---|
| 117 | myGrayIndex = 2; // up + down | 
|---|
| 118 | else /* if(yaxis < 16384-4096) */ | 
|---|
| 119 | myGrayIndex = 0; // no movement | 
|---|
| 120 | } | 
|---|
| 121 |  | 
|---|
| 122 | // Gray codes for rotation | 
|---|
| 123 | static constexpr uInt8 graytable[] = { 0x03, 0x01, 0x00, 0x02 }; | 
|---|
| 124 |  | 
|---|
| 125 | // Determine which bits are set | 
|---|
| 126 | uInt8 gray = graytable[myGrayIndex]; | 
|---|
| 127 | setPin(DigitalPin::One, (gray & 0x1) != 0); | 
|---|
| 128 | setPin(DigitalPin::Two, (gray & 0x2) != 0); | 
|---|
| 129 | } | 
|---|
| 130 |  | 
|---|
| 131 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | 
|---|
| 132 | bool Driving::setMouseControl( | 
|---|
| 133 | Controller::Type xtype, int xid, Controller::Type ytype, int yid) | 
|---|
| 134 | { | 
|---|
| 135 | // When the mouse emulates a single driving controller, only the X-axis is | 
|---|
| 136 | // used, and both mouse buttons map to the same 'fire' event | 
|---|
| 137 | if(xtype == Controller::Type::Driving && ytype == Controller::Type::Driving && xid == yid) | 
|---|
| 138 | { | 
|---|
| 139 | myControlID = ((myJack == Jack::Left && xid == 0) || | 
|---|
| 140 | (myJack == Jack::Right && xid == 1) | 
|---|
| 141 | ) ? xid : -1; | 
|---|
| 142 | myControlIDX = myControlIDY = -1; | 
|---|
| 143 | } | 
|---|
| 144 | else | 
|---|
| 145 | { | 
|---|
| 146 | // Otherwise, each axis can be mapped to a separate driving controller, | 
|---|
| 147 | // and the buttons map to separate (corresponding) controllers | 
|---|
| 148 | myControlID = -1; | 
|---|
| 149 | if(myJack == Jack::Left) | 
|---|
| 150 | { | 
|---|
| 151 | myControlIDX = (xtype == Controller::Type::Driving && xid == 0) ? 0 : -1; | 
|---|
| 152 | myControlIDY = (ytype == Controller::Type::Driving && yid == 0) ? 0 : -1; | 
|---|
| 153 | } | 
|---|
| 154 | else  // myJack == Right | 
|---|
| 155 | { | 
|---|
| 156 | myControlIDX = (xtype == Controller::Type::Driving && xid == 1) ? 1 : -1; | 
|---|
| 157 | myControlIDY = (ytype == Controller::Type::Driving && yid == 1) ? 1 : -1; | 
|---|
| 158 | } | 
|---|
| 159 | } | 
|---|
| 160 |  | 
|---|
| 161 | return true; | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|