Added mouse support, but it's not used yet

This commit is contained in:
transistor 2022-10-02 20:39:02 -07:00
parent 4cb423d85a
commit a9b8633531
10 changed files with 202 additions and 25 deletions

3
.gitignore vendored
View File

@ -1,6 +1,6 @@
Cargo.lock
.*.sw?
/target
target
*.vim
junk/
@ -9,3 +9,4 @@ perf.data.old
binaries/*/*.asm
binaries/*/*.bin
binaries/*/*.smd

View File

@ -1,7 +1,6 @@
use std::mem;
use std::sync::{Arc, Mutex};
use std::collections::VecDeque;
use crate::Clock;
use crate::Error;

View File

@ -110,3 +110,17 @@ pub enum Key {
Unknown,
}
pub struct KeyEvent {
pub key: Key,
pub state: bool,
}
impl KeyEvent {
pub fn new(key: Key, state: bool) -> Self {
Self {
key,
state,
}
}
}

View File

@ -2,11 +2,13 @@
mod traits;
mod keys;
mod controllers;
mod mouse;
pub mod gfx;
pub mod audio;
pub use self::keys::Key;
pub use self::keys::{Key, KeyEvent};
pub use self::mouse::{MouseButton, MouseEventType, MouseEvent, MouseState};
pub use self::controllers::{ControllerDevice, ControllerEvent};
pub use self::traits::{Host, Tty, WindowUpdater, ControllerUpdater, KeyboardUpdater, Audio, BlitableSurface, HostData, DummyAudio};
pub use self::traits::{Host, Tty, WindowUpdater, ControllerUpdater, KeyboardUpdater, MouseUpdater, Audio, BlitableSurface, HostData, DummyAudio};

View File

@ -0,0 +1,106 @@
pub enum MouseButton {
Left,
Right,
Middle,
}
pub enum MouseEventType {
Down(MouseButton),
Up(MouseButton),
Move,
}
pub struct MouseEvent {
pub etype: MouseEventType,
pub pos: (u32, u32),
}
#[derive(Clone, Default, PartialEq, Eq)]
pub struct MouseState {
pub buttons: [bool; 3],
pub pos: (u32, u32),
}
impl MouseEvent {
pub fn new(etype: MouseEventType, pos: (u32, u32)) -> Self {
Self {
etype,
pos,
}
}
}
impl From<usize> for MouseButton {
fn from(index: usize) -> MouseButton {
match index {
0 => MouseButton::Left,
1 => MouseButton::Right,
2 => MouseButton::Middle,
_ => panic!("unexpected mouse button index: {:?}", index),
}
}
}
impl From<MouseButton> for usize {
fn from(button: MouseButton) -> usize {
match button {
MouseButton::Left => 0,
MouseButton::Right => 1,
MouseButton::Middle => 2,
}
}
}
impl MouseState {
pub fn with(left: bool, right: bool, middle: bool, x: u32, y: u32) -> Self {
Self {
buttons: [left, right, middle],
pos: (x, y),
}
}
pub fn to_events(&mut self, next_state: MouseState) -> Vec<MouseEvent> {
if *self != next_state {
self.pos = next_state.pos;
let events: Vec<MouseEvent> = self
.buttons.into_iter()
.zip(next_state.buttons.into_iter())
.enumerate()
.filter_map(|(i, (prev, next))| {
if prev != next {
self.buttons[i] = next;
let button = MouseButton::from(i);
let etype = if next {
MouseEventType::Down(button)
} else {
MouseEventType::Up(button)
};
Some(MouseEvent::new(etype, next_state.pos))
} else {
None
}
})
.collect();
if !events.is_empty() {
events
} else {
vec![MouseEvent::new(MouseEventType::Move, next_state.pos)]
}
} else {
vec![]
}
}
pub fn update_with(&mut self, event: MouseEvent) {
self.pos = event.pos;
match event.etype {
MouseEventType::Up(button) => self.buttons[usize::from(button)] = false,
MouseEventType::Down(button) => self.buttons[usize::from(button)] = true,
MouseEventType::Move => { },
}
}
}

View File

@ -3,9 +3,10 @@ use std::collections::VecDeque;
use std::sync::{Arc, Mutex, MutexGuard};
use crate::{Clock, Error};
use crate::host::keys::Key;
use crate::host::gfx::Frame;
use crate::host::keys::KeyEvent;
use crate::host::controllers::{ControllerDevice, ControllerEvent};
use crate::host::mouse::MouseEvent;
pub trait Host {
fn create_pty(&self) -> Result<Box<dyn Tty>, Error> {
@ -24,6 +25,10 @@ pub trait Host {
Err(Error::new("This frontend doesn't support the keyboard"))
}
fn register_mouse(&mut self, _input: Box<dyn MouseUpdater>) -> Result<(), Error> {
Err(Error::new("This frontend doesn't support the mouse"))
}
fn create_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> {
Err(Error::new("This frontend doesn't support the sound"))
}
@ -56,7 +61,11 @@ pub trait ControllerUpdater: Send {
}
pub trait KeyboardUpdater: Send {
fn update_keyboard(&mut self, key: Key, state: bool);
fn update_keyboard(&mut self, event: KeyEvent);
}
pub trait MouseUpdater: Send {
fn update_mouse(&mut self, event: MouseEvent);
}
pub trait Audio {

View File

@ -5,25 +5,31 @@ use moa_minifb;
use moa_peripherals_yamaha::{Ym2612, Sn76489};
use moa_core::host::gfx::{Frame, FrameQueue};
use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key};
use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key, KeyEvent, MouseUpdater, MouseState, MouseEvent};
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
pub struct SynthControlsUpdater(mpsc::Sender<(Key, bool)>);
pub struct SynthControlsUpdater(mpsc::Sender<KeyEvent>);
impl KeyboardUpdater for SynthControlsUpdater {
fn update_keyboard(&mut self, key: Key, state: bool) {
self.0.send((key, state)).unwrap();
fn update_keyboard(&mut self, event: KeyEvent) {
self.0.send(event).unwrap();
}
}
//impl MouseUpdater for SynthControlsUpdater {
// fn update_mouse(&mut self, event: MouseEvent) {
// self.0.send(event).unwrap();
// }
//}
struct SynthControl {
queue: FrameQueue,
receiver: mpsc::Receiver<(Key, bool)>,
receiver: mpsc::Receiver<KeyEvent>,
}
impl SynthControl {
pub fn new(queue: FrameQueue, receiver: mpsc::Receiver<(Key, bool)>) -> Self {
pub fn new(queue: FrameQueue, receiver: mpsc::Receiver<KeyEvent>) -> Self {
Self {
queue,
receiver,
@ -33,18 +39,18 @@ impl SynthControl {
impl Steppable for SynthControl {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
if let Ok((key, state)) = self.receiver.try_recv() {
if let Ok(event) = self.receiver.try_recv() {
match key {
match event.key {
Key::Enter => {
system.get_bus().write_u8(0x00, 0x28)?;
system.get_bus().write_u8(0x01, if state { 0xF0 } else { 0x00 })?;
system.get_bus().write_u8(0x01, if event.state { 0xF0 } else { 0x00 })?;
},
Key::A => {
system.get_bus().write_u8(0x10, 0x84)?;
system.get_bus().write_u8(0x10, 0x0F)?;
system.get_bus().write_u8(0x10, if state { 0x90 } else { 0x9F })?;
system.get_bus().write_u8(0x10, if event.state { 0x90 } else { 0x9F })?;
},
_ => { },
@ -108,6 +114,7 @@ fn main() {
host.add_window(Box::new(queue.clone()))?;
host.register_keyboard(Box::new(SynthControlsUpdater(sender)))?;
//host.register_mouse(Box::new(SynthControlsUpdater(sender)))?;
Ok(system)
});

View File

@ -4,11 +4,11 @@ use std::str::FromStr;
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use minifb::{self, Key};
use minifb::{self, Key, MouseMode, MouseButton};
use clap::{App, Arg, ArgMatches};
use moa_core::{System, Error, Clock};
use moa_core::host::{Host, HostData, ControllerUpdater, KeyboardUpdater, WindowUpdater, Audio, ControllerDevice};
use moa_core::host::{Host, HostData, ControllerUpdater, KeyboardUpdater, KeyEvent, MouseUpdater, MouseState, WindowUpdater, Audio, ControllerDevice};
use moa_core::host::gfx::Frame;
use moa_common::audio::{AudioOutput, AudioMixer, AudioSource};
@ -98,6 +98,7 @@ pub struct MiniFrontendBuilder {
pub window: Option<Box<dyn WindowUpdater>>,
pub controller: Option<Box<dyn ControllerUpdater>>,
pub keyboard: Option<Box<dyn KeyboardUpdater>>,
pub mouse: Option<Box<dyn MouseUpdater>>,
pub mixer: Option<HostData<AudioMixer>>,
pub finalized: bool,
}
@ -108,6 +109,7 @@ impl MiniFrontendBuilder {
window: None,
controller: None,
keyboard: None,
mouse: None,
mixer: Some(AudioMixer::new_default()),
finalized: false,
}
@ -121,8 +123,9 @@ impl MiniFrontendBuilder {
let window = std::mem::take(&mut self.window);
let controller = std::mem::take(&mut self.controller);
let keyboard = std::mem::take(&mut self.keyboard);
let mouse = std::mem::take(&mut self.mouse);
let mixer = std::mem::take(&mut self.mixer);
MiniFrontend::new(window, controller, keyboard, mixer.unwrap())
MiniFrontend::new(window, controller, keyboard, mouse, mixer.unwrap())
}
}
@ -155,6 +158,14 @@ impl Host for MiniFrontendBuilder {
Ok(())
}
fn register_mouse(&mut self, input: Box<dyn MouseUpdater>) -> Result<(), Error> {
if self.mouse.is_some() {
return Err(Error::new("A mouse updater has already been registered with the frontend"));
}
self.mouse = Some(input);
Ok(())
}
fn create_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> {
let source = AudioSource::new(self.mixer.as_ref().unwrap().clone());
Ok(Box::new(source))
@ -164,20 +175,30 @@ impl Host for MiniFrontendBuilder {
pub struct MiniFrontend {
pub modifiers: u16,
pub mouse_state: MouseState,
pub window: Option<Box<dyn WindowUpdater>>,
pub controller: Option<Box<dyn ControllerUpdater>>,
pub keyboard: Option<Box<dyn KeyboardUpdater>>,
pub mouse: Option<Box<dyn MouseUpdater>>,
pub audio: Option<AudioOutput>,
pub mixer: HostData<AudioMixer>,
}
impl MiniFrontend {
pub fn new(window: Option<Box<dyn WindowUpdater>>, controller: Option<Box<dyn ControllerUpdater>>, keyboard: Option<Box<dyn KeyboardUpdater>>, mixer: HostData<AudioMixer>) -> Self {
pub fn new(
window: Option<Box<dyn WindowUpdater>>,
controller: Option<Box<dyn ControllerUpdater>>,
keyboard: Option<Box<dyn KeyboardUpdater>>,
mouse: Option<Box<dyn MouseUpdater>>,
mixer: HostData<AudioMixer>,
) -> Self {
Self {
modifiers: 0,
mouse_state: Default::default(),
window,
controller,
keyboard,
mouse,
audio: None,
mixer,
}
@ -259,6 +280,20 @@ impl MiniFrontend {
}
}
if let Some(updater) = self.mouse.as_mut() {
if let Some((x, y)) = window.get_mouse_pos(MouseMode::Clamp) {
let left = window.get_mouse_down(MouseButton::Left);
let right = window.get_mouse_down(MouseButton::Right);
let middle = window.get_mouse_down(MouseButton::Middle);
let next_state = MouseState::with(left, right, middle, x as u32, y as u32);
self.mouse_state
.to_events(next_state)
.into_iter()
.for_each(|event| updater.update_mouse(event));
}
}
if let Some(updater) = self.window.as_mut() {
if let Ok(frame) = updater.take_frame() {
last_frame = frame
@ -270,7 +305,7 @@ impl MiniFrontend {
fn check_key(&mut self, key: Key, state: bool) {
if let Some(updater) = self.keyboard.as_mut() {
updater.update_keyboard(map_key(key), state);
updater.update_keyboard(KeyEvent::new(map_key(key), state));
}
if let Some(updater) = self.controller.as_mut() {

View File

@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex};
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, debug, warning};
use moa_core::host::gfx::{Frame, FrameQueue};
use moa_core::host::{Host, BlitableSurface, KeyboardUpdater, Key};
use moa_core::host::{Host, BlitableSurface, KeyboardUpdater, KeyEvent};
use super::keymap;
use super::charset::CharacterGenerator;
@ -37,9 +37,9 @@ impl Model1Peripherals {
pub struct Model1KeyboardUpdater(Arc<Mutex<[u8; 8]>>);
impl KeyboardUpdater for Model1KeyboardUpdater {
fn update_keyboard(&mut self, key: Key, state: bool) {
println!(">>> {:?}", key);
keymap::record_key_press(&mut self.0.lock().unwrap(), key, state);
fn update_keyboard(&mut self, event: KeyEvent) {
println!(">>> {:?}", event.key);
keymap::record_key_press(&mut self.0.lock().unwrap(), event.key, event.state);
}
}

View File

@ -1,4 +1,8 @@
* can you get audio working without the need to lock during an update? Use the ClockedQueue like frames do... but should the queue be used for the mixer-to-output,
the sources to mixer, or both?
* add mouse support, particularly to allow the synth system to have buttons and keys that can be clicked
* test the Z80 more, add tests
* double check the functioning of the banked areas and register settings for Z80 coprocessor
* address repeater on ym2612 doesn't seem to work the same, when it's on the 68000 device. The Z80 device doesn't have an affect, but maybe it's not being used