mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-02 21:30:40 +00:00
Add AppleJack controller support, based on AdbMouse
All AppleJack controllers start in mouse emulation mode, behaving exactly like ADB mice. Only upon receiving a Listen command on register 3 with handler ID 0x46 does the AppleJack switch protocols, albeit such a change consisting merely of expanding register 0's buffer size to 4 bytes. In this state, the first 2 bytes remain defined as they are for an ADB mouse; the additional 16 bits carry the respective states of each of the AppleJack controller's remaining 11 buttons out of a possible supported 16. For backward compatibility, honor both mouse clicks and shoulder button presses on the host when considering the state of the emulated trigger buttons.
This commit is contained in:
parent
d23f21b391
commit
34e0ba84f1
100
devices/common/adb/adbapplejack.cpp
Normal file
100
devices/common/adb/adbapplejack.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-24 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file Apple Desktop Bus AppleJack controller emulation. */
|
||||
|
||||
#include <devices/common/adb/adbapplejack.h>
|
||||
#include <devices/common/adb/adbbus.h>
|
||||
#include <devices/deviceregistry.h>
|
||||
#include <core/hostevents.h>
|
||||
#include <loguru.hpp>
|
||||
|
||||
AdbAppleJack::AdbAppleJack(std::string name) : AdbMouse(name, AdbMouse::TRACKBALL, 2, 7, 300) {
|
||||
EventManager::get_instance()->add_gamepad_handler(this, &AdbAppleJack::event_handler);
|
||||
}
|
||||
|
||||
void AdbAppleJack::event_handler(const GamepadEvent& event) {
|
||||
uint32_t button_bit = 1 << event.button;
|
||||
|
||||
if (event.flags & GAMEPAD_EVENT_DOWN)
|
||||
this->buttons_state |= button_bit;
|
||||
else if (event.flags & GAMEPAD_EVENT_UP)
|
||||
this->buttons_state &= ~button_bit;
|
||||
|
||||
if (button_bit & ((1 << GamepadButton::LeftTrigger) | (1 << GamepadButton::RightTrigger)))
|
||||
this->triggers_changed = true;
|
||||
else
|
||||
this->buttons_changed = true;
|
||||
}
|
||||
|
||||
void AdbAppleJack::reset() {
|
||||
this->AdbMouse::reset();
|
||||
this->buttons_state = 0;
|
||||
this->triggers_changed = false;
|
||||
this->buttons_changed = false;
|
||||
LOG_F(INFO, "%s: reset; in mouse emulation mode", this->name.c_str());
|
||||
}
|
||||
|
||||
bool AdbAppleJack::get_register_0() {
|
||||
bool changed = this->triggers_changed || this->buttons_changed;
|
||||
|
||||
uint8_t mouse_buttons = this->AdbMouse::get_buttons_state();
|
||||
// AppleJack triggers always affect the mouse button bits.
|
||||
mouse_buttons |= (this->buttons_state >> (GamepadButton::LeftTrigger - 0)) & 1;
|
||||
mouse_buttons |= (this->buttons_state >> (GamepadButton::RightTrigger - 1)) & 2;
|
||||
changed |= this->AdbMouse::get_register_0(mouse_buttons, changed);
|
||||
this->triggers_changed = false;
|
||||
|
||||
if (this->dev_handler_id == APPLEJACK_HANDLER_ID && this->buttons_changed) {
|
||||
uint8_t* out_buf = this->host_obj->get_output_buf();
|
||||
|
||||
out_buf[2] = ~this->buttons_state >> 8;
|
||||
out_buf[3] = ~this->buttons_state & 0xFF;
|
||||
|
||||
this->host_obj->set_output_count(4);
|
||||
this->buttons_changed = false;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void AdbAppleJack::set_register_3() {
|
||||
if (this->host_obj->get_input_count() < 2) // ensure we got enough data
|
||||
return;
|
||||
|
||||
const uint8_t* in_data = this->host_obj->get_input_buf();
|
||||
|
||||
switch (in_data[1]) {
|
||||
case APPLEJACK_HANDLER_ID: // switch over to AppleJack protocol
|
||||
this->dev_handler_id = in_data[1];
|
||||
LOG_F(INFO, "%s: switched to AppleJack mode", this->name.c_str());
|
||||
break;
|
||||
default:
|
||||
this->AdbMouse::set_register_3();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const DeviceDescription AdbAppleJack_Descriptor = {
|
||||
AdbAppleJack::create, {}, {}
|
||||
};
|
||||
|
||||
REGISTER_DEVICE(AdbAppleJack, AdbAppleJack_Descriptor);
|
60
devices/common/adb/adbapplejack.h
Normal file
60
devices/common/adb/adbapplejack.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
DingusPPC - The Experimental PowerPC Macintosh emulator
|
||||
Copyright (C) 2018-24 divingkatae and maximum
|
||||
(theweirdo) spatium
|
||||
|
||||
(Contact divingkatae#1017 or powermax#2286 on Discord for more info)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file Apple Desktop Bus AppleJack controller definitions. */
|
||||
|
||||
#ifndef ADB_APPLEJACK_H
|
||||
#define ADB_APPLEJACK_H
|
||||
|
||||
#include <devices/common/adb/adbmouse.h>
|
||||
#include <devices/common/hwcomponent.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
enum : uint8_t {
|
||||
APPLEJACK_HANDLER_ID = 0x46,
|
||||
};
|
||||
|
||||
class GamepadEvent;
|
||||
|
||||
class AdbAppleJack : public AdbMouse {
|
||||
public:
|
||||
AdbAppleJack(std::string name);
|
||||
~AdbAppleJack() = default;
|
||||
|
||||
static std::unique_ptr<HWComponent> create() {
|
||||
return std::unique_ptr<AdbAppleJack>(new AdbAppleJack("ADB-APPLEJACK"));
|
||||
}
|
||||
|
||||
void reset() override;
|
||||
void event_handler(const GamepadEvent& event);
|
||||
|
||||
bool get_register_0() override;
|
||||
void set_register_3() override;
|
||||
|
||||
private:
|
||||
uint32_t buttons_state = 0;
|
||||
bool triggers_changed = false;
|
||||
bool buttons_changed = false;
|
||||
};
|
||||
|
||||
#endif // ADB_APPLEJACK_H
|
@ -28,7 +28,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include <memaccess.h>
|
||||
#include <loguru.hpp>
|
||||
|
||||
AdbMouse::AdbMouse(std::string name) : AdbDevice(name) {
|
||||
AdbMouse::AdbMouse(
|
||||
std::string name, uint8_t device_class, int num_buttons, int num_bits, uint16_t resolution) : AdbDevice(name), device_class(device_class), num_buttons(num_buttons), num_bits(num_bits), resolution(resolution) {
|
||||
EventManager::get_instance()->add_mouse_handler(this, &AdbMouse::event_handler);
|
||||
|
||||
this->reset();
|
||||
@ -63,8 +64,10 @@ void AdbMouse::reset() {
|
||||
this->changed = false;
|
||||
}
|
||||
|
||||
bool AdbMouse::get_register_0() {
|
||||
if (this->x_rel || this->y_rel || this->changed) {
|
||||
bool AdbMouse::get_register_0(uint8_t buttons_state, bool force) {
|
||||
bool should_update = this->x_rel || this->y_rel || this->changed || force;
|
||||
|
||||
if (should_update) {
|
||||
uint8_t* p;
|
||||
uint8_t* out_buf = this->host_obj->get_output_buf();
|
||||
|
||||
@ -86,7 +89,7 @@ bool AdbMouse::get_register_0() {
|
||||
bits = 7;
|
||||
|
||||
while (bits_remaining > 0) {
|
||||
*p = (val & ((1 << bits) - 1)) | (((this->buttons_state >> button) ^ 1) << bits) | (*p << (bits + 1));
|
||||
*p = (val & ((1 << bits) - 1)) | (((buttons_state >> button) ^ 1) << bits) | (*p << (bits + 1));
|
||||
val >>= bits;
|
||||
bits_remaining -= bits;
|
||||
p = bits == 7 ? &out_buf[2] : p + 1;
|
||||
@ -109,12 +112,16 @@ bool AdbMouse::get_register_0() {
|
||||
if (this->device_class == MOUSE && this->dev_handler_id == 1)
|
||||
count = 2;
|
||||
this->host_obj->set_output_count(count);
|
||||
return true;
|
||||
return should_update;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AdbMouse::get_register_0() {
|
||||
return get_register_0(this->buttons_state, false);
|
||||
}
|
||||
|
||||
bool AdbMouse::get_register_1() {
|
||||
uint8_t* out_buf = this->host_obj->get_output_buf();
|
||||
// Identifier
|
||||
@ -156,6 +163,10 @@ void AdbMouse::set_register_3() {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t AdbMouse::get_buttons_state() const {
|
||||
return this->buttons_state;
|
||||
}
|
||||
|
||||
static const DeviceDescription AdbMouse_Descriptor = {
|
||||
AdbMouse::create, {}, {}
|
||||
};
|
||||
|
@ -35,19 +35,31 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
class MouseEvent;
|
||||
|
||||
class AdbMouse : public AdbDevice {
|
||||
|
||||
public:
|
||||
enum DeviceClass {
|
||||
TABLET = 0,
|
||||
MOUSE = 1,
|
||||
TRACKBALL = 2,
|
||||
};
|
||||
|
||||
public:
|
||||
AdbMouse(std::string name);
|
||||
AdbMouse(
|
||||
std::string name, uint8_t device_class, int num_buttons, int num_bits, uint16_t resolution);
|
||||
~AdbMouse() = default;
|
||||
|
||||
static std::unique_ptr<HWComponent> create() {
|
||||
return std::unique_ptr<AdbMouse>(new AdbMouse("ADB-MOUSE"));
|
||||
#ifdef ABSOLUTE
|
||||
uint8_t device_class = TABLET;
|
||||
int num_buttons = 3;
|
||||
int num_bits = 16;
|
||||
uint16_t resolution = 72;
|
||||
#else
|
||||
uint8_t device_class = MOUSE;
|
||||
int num_buttons = 3;
|
||||
int num_bits = 10;
|
||||
uint16_t resolution = 300;
|
||||
#endif
|
||||
return std::unique_ptr<AdbMouse>(
|
||||
new AdbMouse("ADB-MOUSE", device_class, num_buttons, num_bits, resolution));
|
||||
}
|
||||
|
||||
void reset() override;
|
||||
@ -57,6 +69,10 @@ public:
|
||||
bool get_register_1() override;
|
||||
void set_register_3() override;
|
||||
|
||||
protected:
|
||||
bool get_register_0(uint8_t buttons_state, bool force);
|
||||
uint8_t get_buttons_state() const;
|
||||
|
||||
private:
|
||||
int32_t x_rel = 0;
|
||||
int32_t y_rel = 0;
|
||||
@ -64,17 +80,10 @@ private:
|
||||
int32_t y_abs = 0;
|
||||
uint8_t buttons_state = 0;
|
||||
bool changed = false;
|
||||
#ifdef ABSOLUTE
|
||||
uint8_t device_class = TABLET;
|
||||
int num_buttons = 3;
|
||||
int num_bits = 16;
|
||||
uint16_t resolution = 72;
|
||||
#else
|
||||
uint8_t device_class = MOUSE;
|
||||
int num_buttons = 3;
|
||||
int num_bits = 10;
|
||||
uint16_t resolution = 300;
|
||||
#endif
|
||||
uint8_t device_class;
|
||||
int num_buttons;
|
||||
int num_bits;
|
||||
uint16_t resolution;
|
||||
};
|
||||
|
||||
#endif // ADB_MOUSE_H
|
||||
|
Loading…
Reference in New Issue
Block a user