Skip to content

Commit 1f05865

Browse files
authored
Merge pull request #117 from kkaisershot/applejack
AppleJack (Pippin) controller support
2 parents 02c8c8c + 6df1c7d commit 1f05865

File tree

13 files changed

+338
-25
lines changed

13 files changed

+338
-25
lines changed

core/hostevents.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ enum : uint32_t {
4040
MOUSE_EVENT_BUTTON = 1 << 1,
4141
KEYBOARD_EVENT_DOWN = 1 << 0,
4242
KEYBOARD_EVENT_UP = 1 << 1,
43+
GAMEPAD_EVENT_DOWN = 1 << 0,
44+
GAMEPAD_EVENT_UP = 1 << 1,
4345
};
4446

4547
class MouseEvent {
@@ -65,6 +67,36 @@ class KeyboardEvent {
6567
uint16_t keys_state;
6668
};
6769

70+
/* AppleJack bits 3-7 are supported but unused */
71+
enum GamepadButton : uint8_t {
72+
Red = 14,
73+
Green = 15,
74+
Yellow = 9,
75+
Blue = 8,
76+
77+
FrontLeft = 0,
78+
FrontMiddle = 1,
79+
FrontRight = 2,
80+
81+
LeftTrigger = 17,
82+
RightTrigger = 16,
83+
84+
Up = 10,
85+
Down = 13,
86+
Left = 11,
87+
Right = 12,
88+
};
89+
90+
class GamepadEvent {
91+
public:
92+
GamepadEvent() = default;
93+
~GamepadEvent() = default;
94+
95+
uint32_t gamepad_id;
96+
uint32_t flags;
97+
uint8_t button;
98+
};
99+
68100
class EventManager {
69101
public:
70102
static EventManager* get_instance() {
@@ -91,6 +123,11 @@ class EventManager {
91123
_keyboard_signal.connect_method(inst, func);
92124
}
93125

126+
template <typename T>
127+
void add_gamepad_handler(T* inst, void (T::*func)(const GamepadEvent&)) {
128+
_gamepad_signal.connect_method(inst, func);
129+
}
130+
94131
template <typename T>
95132
void add_post_handler(T *inst, void (T::*func)()) {
96133
_post_signal.connect_method(inst, func);
@@ -110,6 +147,7 @@ class EventManager {
110147
CoreSignal<const WindowEvent&> _window_signal;
111148
CoreSignal<const MouseEvent&> _mouse_signal;
112149
CoreSignal<const KeyboardEvent&> _keyboard_signal;
150+
CoreSignal<const GamepadEvent&> _gamepad_signal;
113151
CoreSignal<> _post_signal;
114152

115153
uint64_t events_captured = 0;

core/hostevents_sdl.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,52 @@ void EventManager::poll_events()
130130
}
131131
break;
132132

133+
case SDL_CONTROLLERBUTTONDOWN: {
134+
GamepadEvent ge;
135+
switch (event.cbutton.button) {
136+
case SDL_CONTROLLER_BUTTON_BACK: ge.button = GamepadButton::FrontLeft; break;
137+
case SDL_CONTROLLER_BUTTON_GUIDE: ge.button = GamepadButton::FrontMiddle; break;
138+
case SDL_CONTROLLER_BUTTON_START: ge.button = GamepadButton::FrontRight; break;
139+
case SDL_CONTROLLER_BUTTON_Y: ge.button = GamepadButton::Blue; break;
140+
case SDL_CONTROLLER_BUTTON_X: ge.button = GamepadButton::Yellow; break;
141+
case SDL_CONTROLLER_BUTTON_DPAD_UP: ge.button = GamepadButton::Up; break;
142+
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: ge.button = GamepadButton::Left; break;
143+
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: ge.button = GamepadButton::Right; break;
144+
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: ge.button = GamepadButton::Down; break;
145+
case SDL_CONTROLLER_BUTTON_A: ge.button = GamepadButton::Red; break;
146+
case SDL_CONTROLLER_BUTTON_B: ge.button = GamepadButton::Green; break;
147+
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: ge.button = GamepadButton::RightTrigger; break;
148+
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: ge.button = GamepadButton::LeftTrigger; break;
149+
}
150+
ge.gamepad_id = event.cbutton.which;
151+
ge.flags = GAMEPAD_EVENT_DOWN;
152+
this->_gamepad_signal.emit(ge);
153+
}
154+
break;
155+
156+
case SDL_CONTROLLERBUTTONUP: {
157+
GamepadEvent ge;
158+
switch (event.cbutton.button) {
159+
case SDL_CONTROLLER_BUTTON_BACK: ge.button = GamepadButton::FrontLeft; break;
160+
case SDL_CONTROLLER_BUTTON_GUIDE: ge.button = GamepadButton::FrontMiddle; break;
161+
case SDL_CONTROLLER_BUTTON_START: ge.button = GamepadButton::FrontRight; break;
162+
case SDL_CONTROLLER_BUTTON_Y: ge.button = GamepadButton::Blue; break;
163+
case SDL_CONTROLLER_BUTTON_X: ge.button = GamepadButton::Yellow; break;
164+
case SDL_CONTROLLER_BUTTON_DPAD_UP: ge.button = GamepadButton::Up; break;
165+
case SDL_CONTROLLER_BUTTON_DPAD_LEFT: ge.button = GamepadButton::Left; break;
166+
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: ge.button = GamepadButton::Right; break;
167+
case SDL_CONTROLLER_BUTTON_DPAD_DOWN: ge.button = GamepadButton::Down; break;
168+
case SDL_CONTROLLER_BUTTON_A: ge.button = GamepadButton::Red; break;
169+
case SDL_CONTROLLER_BUTTON_B: ge.button = GamepadButton::Green; break;
170+
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: ge.button = GamepadButton::RightTrigger; break;
171+
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: ge.button = GamepadButton::LeftTrigger; break;
172+
}
173+
ge.gamepad_id = event.cbutton.which;
174+
ge.flags = GAMEPAD_EVENT_UP;
175+
this->_gamepad_signal.emit(ge);
176+
}
177+
break;
178+
133179
default:
134180
unhandled_events++;
135181
}

devices/common/adb/adbapplejack.cpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
DingusPPC - The Experimental PowerPC Macintosh emulator
3+
Copyright (C) 2018-24 divingkatae and maximum
4+
(theweirdo) spatium
5+
6+
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
7+
8+
This program is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation, either version 3 of the License, or
11+
(at your option) any later version.
12+
13+
This program is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
*/
21+
22+
/** @file Apple Desktop Bus AppleJack controller emulation. */
23+
24+
#include <devices/common/adb/adbapplejack.h>
25+
#include <devices/common/adb/adbbus.h>
26+
#include <devices/deviceregistry.h>
27+
#include <core/hostevents.h>
28+
#include <loguru.hpp>
29+
30+
AdbAppleJack::AdbAppleJack(std::string name) : AdbMouse(name, AdbMouse::TRACKBALL, 2, 7, 300) {
31+
EventManager::get_instance()->add_gamepad_handler(this, &AdbAppleJack::event_handler);
32+
}
33+
34+
void AdbAppleJack::event_handler(const GamepadEvent& event) {
35+
uint32_t button_bit = 1 << event.button;
36+
37+
if (event.flags & GAMEPAD_EVENT_DOWN)
38+
this->buttons_state |= button_bit;
39+
else if (event.flags & GAMEPAD_EVENT_UP)
40+
this->buttons_state &= ~button_bit;
41+
42+
if (button_bit & ((1 << GamepadButton::LeftTrigger) | (1 << GamepadButton::RightTrigger)))
43+
this->triggers_changed = true;
44+
else
45+
this->buttons_changed = true;
46+
}
47+
48+
void AdbAppleJack::reset() {
49+
this->AdbMouse::reset();
50+
this->buttons_state = 0;
51+
this->triggers_changed = false;
52+
this->buttons_changed = false;
53+
LOG_F(INFO, "%s: reset; in mouse emulation mode", this->name.c_str());
54+
}
55+
56+
bool AdbAppleJack::get_register_0() {
57+
bool changed = this->triggers_changed || this->buttons_changed;
58+
59+
uint8_t mouse_buttons = this->AdbMouse::get_buttons_state();
60+
// AppleJack triggers always affect the mouse button bits.
61+
mouse_buttons |= (this->buttons_state >> (GamepadButton::LeftTrigger - 0)) & 1;
62+
mouse_buttons |= (this->buttons_state >> (GamepadButton::RightTrigger - 1)) & 2;
63+
changed |= this->AdbMouse::get_register_0(mouse_buttons, changed);
64+
this->triggers_changed = false;
65+
66+
if (this->dev_handler_id == APPLEJACK_HANDLER_ID && this->buttons_changed) {
67+
uint8_t* out_buf = this->host_obj->get_output_buf();
68+
69+
out_buf[2] = ~this->buttons_state >> 8;
70+
out_buf[3] = ~this->buttons_state & 0xFF;
71+
72+
this->host_obj->set_output_count(4);
73+
this->buttons_changed = false;
74+
}
75+
76+
return changed;
77+
}
78+
79+
void AdbAppleJack::set_register_3() {
80+
if (this->host_obj->get_input_count() < 2) // ensure we got enough data
81+
return;
82+
83+
const uint8_t* in_data = this->host_obj->get_input_buf();
84+
85+
switch (in_data[1]) {
86+
case APPLEJACK_HANDLER_ID: // switch over to AppleJack protocol
87+
this->dev_handler_id = in_data[1];
88+
LOG_F(INFO, "%s: switched to AppleJack mode", this->name.c_str());
89+
break;
90+
default:
91+
this->AdbMouse::set_register_3();
92+
break;
93+
}
94+
}
95+
96+
static const DeviceDescription AdbAppleJack_Descriptor = {
97+
AdbAppleJack::create, {}, {}
98+
};
99+
100+
REGISTER_DEVICE(AdbAppleJack, AdbAppleJack_Descriptor);

devices/common/adb/adbapplejack.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
DingusPPC - The Experimental PowerPC Macintosh emulator
3+
Copyright (C) 2018-24 divingkatae and maximum
4+
(theweirdo) spatium
5+
6+
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
7+
8+
This program is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation, either version 3 of the License, or
11+
(at your option) any later version.
12+
13+
This program is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
*/
21+
22+
/** @file Apple Desktop Bus AppleJack controller definitions. */
23+
24+
#ifndef ADB_APPLEJACK_H
25+
#define ADB_APPLEJACK_H
26+
27+
#include <devices/common/adb/adbmouse.h>
28+
#include <devices/common/hwcomponent.h>
29+
30+
#include <memory>
31+
#include <string>
32+
33+
enum : uint8_t {
34+
APPLEJACK_HANDLER_ID = 0x46,
35+
};
36+
37+
class GamepadEvent;
38+
39+
class AdbAppleJack : public AdbMouse {
40+
public:
41+
AdbAppleJack(std::string name);
42+
~AdbAppleJack() = default;
43+
44+
static std::unique_ptr<HWComponent> create() {
45+
return std::unique_ptr<AdbAppleJack>(new AdbAppleJack("ADB-APPLEJACK"));
46+
}
47+
48+
void reset() override;
49+
void event_handler(const GamepadEvent& event);
50+
51+
bool get_register_0() override;
52+
void set_register_3() override;
53+
54+
private:
55+
uint32_t buttons_state = 0;
56+
bool triggers_changed = false;
57+
bool buttons_changed = false;
58+
};
59+
60+
#endif // ADB_APPLEJACK_H

devices/common/adb/adbbus.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,39 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
2525
#include <devices/common/adb/adbdevice.h>
2626
#include <devices/deviceregistry.h>
2727
#include <loguru.hpp>
28+
#include <machines/machinebase.h>
29+
#include <sstream>
2830

2931
AdbBus::AdbBus(std::string name) {
3032
this->set_name(name);
3133
supports_types(HWCompType::ADB_HOST);
3234
this->devices.clear();
3335
}
3436

37+
int AdbBus::device_postinit() {
38+
std::string adb_device_list = GET_STR_PROP("adb_devices");
39+
if (adb_device_list.empty())
40+
return 0;
41+
42+
std::string adb_device;
43+
std::istringstream adb_device_stream(adb_device_list);
44+
45+
while (getline(adb_device_stream, adb_device, ',')) {
46+
string dev_name = "Adb" + adb_device;
47+
48+
if (dev_name == this->name)
49+
continue; // don't register a second ADB bus
50+
51+
if (DeviceRegistry::device_registered(dev_name)) {
52+
gMachineObj->add_device(dev_name, DeviceRegistry::get_descriptor(dev_name).m_create_func());
53+
} else {
54+
LOG_F(WARNING, "Unknown specified ADB device \"%s\"", adb_device.c_str());
55+
}
56+
}
57+
58+
return 0;
59+
}
60+
3561
void AdbBus::register_device(AdbDevice* dev_obj) {
3662
this->devices.push_back(dev_obj);
3763
}
@@ -102,8 +128,12 @@ uint8_t AdbBus::process_command(const uint8_t* in_data, int data_size) {
102128
return ADB_STAT_OK;
103129
}
104130

131+
static const PropMap AdbBus_Properties = {
132+
{"adb_devices", new StrProperty("Mouse,Keyboard")},
133+
};
134+
105135
static const DeviceDescription AdbBus_Descriptor = {
106-
AdbBus::create, {}, {}
136+
AdbBus::create, {}, AdbBus_Properties
107137
};
108138

109139
REGISTER_DEVICE(AdbBus, AdbBus_Descriptor);

devices/common/adb/adbbus.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class AdbBus : public HWComponent {
5151
return std::unique_ptr<AdbBus>(new AdbBus("ADB-BUS"));
5252
}
5353

54+
int device_postinit() override;
55+
5456
void register_device(AdbDevice* dev_obj);
5557
uint8_t process_command(const uint8_t* in_data, int data_size);
5658
uint8_t get_output_count() { return this->output_count; };

0 commit comments

Comments
 (0)