mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-08 14:30:55 +00:00
59fba285b5
Add absolute coordinates for tablets. Absolute coordinates is relative to window so it can't work for multiple displays? Doesn't work for single display without mouse driver modification. Add arbitrary number of buttons. Previously, only one mouse button was supported. Add arbitrary number of bits. Previously, only 7 bits per axis was supported which is good enough for relative movement but not absolute movement.
156 lines
5.0 KiB
C++
156 lines
5.0 KiB
C++
/*
|
|
DingusPPC - The Experimental PowerPC Macintosh emulator
|
|
Copyright (C) 2018-23 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 Mouse emulation. */
|
|
|
|
#include <devices/common/adb/adbmouse.h>
|
|
#include <devices/common/adb/adbbus.h>
|
|
#include <devices/deviceregistry.h>
|
|
#include <core/hostevents.h>
|
|
#include <memaccess.h>
|
|
#include <loguru.hpp>
|
|
|
|
AdbMouse::AdbMouse(std::string name) : AdbDevice(name) {
|
|
EventManager::get_instance()->add_mouse_handler(this, &AdbMouse::event_handler);
|
|
|
|
this->reset();
|
|
}
|
|
|
|
void AdbMouse::event_handler(const MouseEvent& event) {
|
|
if (event.flags & MOUSE_EVENT_MOTION) {
|
|
this->x_rel += event.xrel;
|
|
this->y_rel += event.yrel;
|
|
this->x_abs = event.xabs;
|
|
this->y_abs = event.yabs;
|
|
if (this->device_class == TABLET)
|
|
this->changed = true;
|
|
} else if (event.flags & MOUSE_EVENT_BUTTON) {
|
|
this->buttons_state = event.buttons_state & ((1 << this->num_buttons) - 1);
|
|
this->x_abs = event.xabs;
|
|
this->y_abs = event.yabs;
|
|
this->changed = true;
|
|
}
|
|
}
|
|
|
|
void AdbMouse::reset() {
|
|
this->my_addr = ADB_ADDR_RELPOS;
|
|
this->dev_handler_id = 1;
|
|
this->exc_event_flag = 1;
|
|
this->srq_flag = 1; // enable service requests
|
|
this->x_rel = 0;
|
|
this->y_rel = 0;
|
|
this->x_abs = 0;
|
|
this->y_abs = 0;
|
|
this->buttons_state = 0;
|
|
this->changed = false;
|
|
}
|
|
|
|
bool AdbMouse::get_register_0() {
|
|
if (this->x_rel || this->y_rel || this->changed) {
|
|
uint8_t* p;
|
|
uint8_t* out_buf = this->host_obj->get_output_buf();
|
|
|
|
static const uint8_t buttons_to_bits[] = {0, 7, 7, 10, 10, 13, 13, 16, 16};
|
|
static const uint8_t bits_to_bits[] = {0, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 13, 13, 13, 16, 16, 16};
|
|
int total_bits = std::max(buttons_to_bits[this->num_buttons], bits_to_bits[this->num_bits]);
|
|
|
|
for (int axis = 0; axis < 2; axis++) {
|
|
int bits = this->num_bits;
|
|
int32_t val = axis ? this->device_class == TABLET ? this->x_abs : this->x_rel
|
|
: this->device_class == TABLET ? this->y_abs : this->y_rel;
|
|
if (val < (-1 << (bits - 1)))
|
|
val = -1 << (bits - 1);
|
|
else if (val >= (1 << (bits - 1)))
|
|
val = (1 << (bits - 1)) - 1;
|
|
int bits_remaining = total_bits;
|
|
p = &out_buf[axis];
|
|
int button = axis;
|
|
bits = 7;
|
|
|
|
while (bits_remaining > 0) {
|
|
*p = (val & ((1 << bits) - 1)) | (((this->buttons_state >> button) ^ 1) << bits) | (*p << (bits + 1));
|
|
val >>= bits;
|
|
bits_remaining -= bits;
|
|
p = bits == 7 ? &out_buf[2] : p + 1;
|
|
button += 2;
|
|
bits = 3;
|
|
}
|
|
}
|
|
|
|
// reset accumulated motion data and button change flag
|
|
this->x_rel = 0;
|
|
this->y_rel = 0;
|
|
this->changed = false;
|
|
|
|
this->host_obj->set_output_count(p - out_buf);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool AdbMouse::get_register_1() {
|
|
uint8_t* out_buf = this->host_obj->get_output_buf();
|
|
// Identifier
|
|
out_buf[0] = 'a';
|
|
out_buf[1] = 'p';
|
|
out_buf[2] = 'p';
|
|
out_buf[3] = 'l';
|
|
// Slightly higher resolution of 300 units per inch
|
|
WRITE_WORD_BE_A(&out_buf[4], resolution);
|
|
out_buf[6] = device_class;
|
|
out_buf[7] = num_buttons;
|
|
this->host_obj->set_output_count(8);
|
|
return true;
|
|
}
|
|
|
|
void AdbMouse::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 0:
|
|
this->my_addr = in_data[0] & 0xF;
|
|
this->srq_flag = !!(in_data[0] & 0x20);
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
case 4: // switch over to extended mouse protocol
|
|
this->dev_handler_id = in_data[1];
|
|
break;
|
|
case 0xFE: // move to a new address if there was no collision
|
|
if (!this->got_collision) {
|
|
this->my_addr = in_data[0] & 0xF;
|
|
}
|
|
break;
|
|
default:
|
|
LOG_F(WARNING, "%s: unknown handler ID = 0x%X", this->name.c_str(), in_data[1]);
|
|
}
|
|
}
|
|
|
|
static const DeviceDescription AdbMouse_Descriptor = {
|
|
AdbMouse::create, {}, {}
|
|
};
|
|
|
|
REGISTER_DEVICE(AdbMouse, AdbMouse_Descriptor);
|