keyboard input works on mac gui (LMAO)
This commit is contained in:
parent
bf7c7b9169
commit
560f1d9693
4 changed files with 146 additions and 28 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -487,7 +487,7 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
|||
[[package]]
|
||||
name = "cacao"
|
||||
version = "0.4.0-beta2"
|
||||
source = "git+https://github.com/italicsjenga/cacao#6144e9f244abfd15687de00b6cfda6b4606f351a"
|
||||
source = "git+https://github.com/italicsjenga/cacao#4fd93e3faeec5e80aef36779745b3506c9b5017d"
|
||||
dependencies = [
|
||||
"bitmask-enum",
|
||||
"block2 0.2.0-alpha.6",
|
||||
|
|
|
@ -9,13 +9,16 @@ use std::{
|
|||
};
|
||||
|
||||
use cacao::{
|
||||
appkit::window::{Window, WindowConfig, WindowDelegate, WindowStyle},
|
||||
appkit::{
|
||||
window::{Window, WindowConfig, WindowDelegate, WindowStyle},
|
||||
Event, EventMask, EventMonitor,
|
||||
},
|
||||
core_foundation::base::TCFTypeRef,
|
||||
};
|
||||
use cpal::Stream;
|
||||
use frontend_common::window::{RendererChannel, WindowManager};
|
||||
use gb_emu_lib::{
|
||||
connect::{EmulatorMessage, RendererMessage, ResolutionData},
|
||||
connect::{EmulatorMessage, JoypadButtons, JoypadState, RendererMessage, ResolutionData},
|
||||
renderer::{RendererBackend, RendererBackendManager, WindowOptions},
|
||||
};
|
||||
use raw_window_handle::{
|
||||
|
@ -27,8 +30,15 @@ use uuid::Uuid;
|
|||
use super::{dispatch, AppMessage};
|
||||
|
||||
pub enum EmuWindowMessage {
|
||||
Closing,
|
||||
Renderer(RendererMessage<[u8; 4]>),
|
||||
Closing {
|
||||
id: Uuid,
|
||||
},
|
||||
Renderer {
|
||||
id: Uuid,
|
||||
renderer_message: RendererMessage<[u8; 4]>,
|
||||
},
|
||||
KeyDown(JoypadButtons),
|
||||
KeyUp(JoypadButtons),
|
||||
}
|
||||
|
||||
pub struct EmulatorHandles {
|
||||
|
@ -60,18 +70,101 @@ impl Drop for EmulatorHandles {
|
|||
}
|
||||
}
|
||||
|
||||
struct ButtonHandler {
|
||||
_down_monitor: EventMonitor,
|
||||
_up_monitor: EventMonitor,
|
||||
}
|
||||
|
||||
impl ButtonHandler {
|
||||
fn new() -> Self {
|
||||
let _down_monitor = Event::local_monitor(EventMask::KeyDown, |v| {
|
||||
if let Some(button) = get_buttons(&v) {
|
||||
dispatch(AppMessage::EmuWindow(EmuWindowMessage::KeyDown(button)));
|
||||
None
|
||||
} else {
|
||||
Some(v)
|
||||
}
|
||||
});
|
||||
let _up_monitor = Event::local_monitor(EventMask::KeyUp, |v| {
|
||||
if let Some(button) = get_buttons(&v) {
|
||||
dispatch(AppMessage::EmuWindow(EmuWindowMessage::KeyUp(button)));
|
||||
None
|
||||
} else {
|
||||
Some(v)
|
||||
}
|
||||
});
|
||||
|
||||
Self {
|
||||
_down_monitor,
|
||||
_up_monitor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait GetKeyChar {
|
||||
fn get_key_char(&self) -> char;
|
||||
}
|
||||
|
||||
impl GetKeyChar for JoypadButtons {
|
||||
fn get_key_char(&self) -> char {
|
||||
match self {
|
||||
JoypadButtons::Down => 's',
|
||||
JoypadButtons::Up => 'w',
|
||||
JoypadButtons::Left => 'a',
|
||||
JoypadButtons::Right => 'd',
|
||||
JoypadButtons::Start => '=',
|
||||
JoypadButtons::Select => '-',
|
||||
JoypadButtons::B => ';',
|
||||
JoypadButtons::A => '\'',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ALL_BUTTONS: [JoypadButtons; 8] = [
|
||||
JoypadButtons::Down,
|
||||
JoypadButtons::Up,
|
||||
JoypadButtons::Left,
|
||||
JoypadButtons::Right,
|
||||
JoypadButtons::Start,
|
||||
JoypadButtons::Select,
|
||||
JoypadButtons::B,
|
||||
JoypadButtons::A,
|
||||
];
|
||||
|
||||
fn get_buttons(event: &Event) -> Option<JoypadButtons> {
|
||||
let characters = event.characters();
|
||||
if characters.len() != 1 {
|
||||
panic!("ok that assumption was wrong lol. event characters CAN be != 1");
|
||||
}
|
||||
|
||||
if event.current_modifier_flags().is_empty() {
|
||||
for button in ALL_BUTTONS {
|
||||
if characters.contains(button.get_key_char()) {
|
||||
return Some(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub struct CacaoWindowManager {
|
||||
backend_manager: Arc<RendererBackendManager>,
|
||||
windows: HashMap<Uuid, Window<CacaoWindow>>,
|
||||
handles: Option<EmulatorHandles>,
|
||||
joypad_state: JoypadState,
|
||||
_button_handler: ButtonHandler,
|
||||
}
|
||||
|
||||
impl CacaoWindowManager {
|
||||
pub fn new(display_handle: RawDisplayHandle) -> Self {
|
||||
let _button_handler = ButtonHandler::new();
|
||||
|
||||
Self {
|
||||
backend_manager: Arc::new(RendererBackendManager::new(display_handle)),
|
||||
windows: HashMap::new(),
|
||||
handles: None,
|
||||
joypad_state: Default::default(),
|
||||
_button_handler,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,19 +182,22 @@ impl CacaoWindowManager {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn message(&mut self, id: Uuid, message: EmuWindowMessage) {
|
||||
pub fn message(&mut self, message: EmuWindowMessage) {
|
||||
match message {
|
||||
EmuWindowMessage::Closing => {
|
||||
EmuWindowMessage::Closing { id } => {
|
||||
self.windows.remove(&id);
|
||||
if self.windows.is_empty() {
|
||||
let _ = self.handles.take();
|
||||
}
|
||||
}
|
||||
EmuWindowMessage::Renderer(message) => {
|
||||
EmuWindowMessage::Renderer {
|
||||
id,
|
||||
renderer_message,
|
||||
} => {
|
||||
if let Some(window) = self.windows.get_mut(&id) {
|
||||
if let Some(delegate) = window.delegate.as_mut() {
|
||||
delegate.message(
|
||||
message,
|
||||
renderer_message,
|
||||
Window {
|
||||
delegate: None,
|
||||
objc: window.objc.clone(),
|
||||
|
@ -110,6 +206,30 @@ impl CacaoWindowManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
EmuWindowMessage::KeyDown(key) => {
|
||||
if let Some(handles) = self.handles.as_ref() {
|
||||
let old_state = self.joypad_state;
|
||||
self.joypad_state.set(key, true);
|
||||
if self.joypad_state != old_state {
|
||||
handles
|
||||
.sender
|
||||
.send(EmulatorMessage::JoypadUpdate(self.joypad_state))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
EmuWindowMessage::KeyUp(key) => {
|
||||
if let Some(handles) = self.handles.as_ref() {
|
||||
let old_state = self.joypad_state;
|
||||
self.joypad_state.set(key, false);
|
||||
if self.joypad_state != old_state {
|
||||
handles
|
||||
.sender
|
||||
.send(EmulatorMessage::JoypadUpdate(self.joypad_state))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,17 +292,18 @@ enum MonitorThreadState {
|
|||
impl MonitorThread {
|
||||
fn new(receiver: Receiver<RendererMessage<[u8; 4]>>, id: Uuid) -> Self {
|
||||
let (destroy, destroy_recv) = mpsc::channel();
|
||||
let thread = std::thread::spawn(move || loop {
|
||||
if let Ok(message) = receiver.recv() {
|
||||
dispatch(AppMessage::EmuWindow {
|
||||
id,
|
||||
message: EmuWindowMessage::Renderer(message),
|
||||
})
|
||||
}
|
||||
if let Ok(true) = destroy_recv.try_recv() {
|
||||
return;
|
||||
}
|
||||
});
|
||||
let thread =
|
||||
std::thread::spawn(move || loop {
|
||||
if let Ok(renderer_message) = receiver.recv() {
|
||||
dispatch(AppMessage::EmuWindow(EmuWindowMessage::Renderer {
|
||||
id,
|
||||
renderer_message,
|
||||
}));
|
||||
}
|
||||
if let Ok(true) = destroy_recv.try_recv() {
|
||||
return;
|
||||
}
|
||||
});
|
||||
Self {
|
||||
state: MonitorThreadState::Live { thread, destroy },
|
||||
}
|
||||
|
@ -292,10 +413,7 @@ impl WindowDelegate for CacaoWindow {
|
|||
}
|
||||
|
||||
fn will_close(&self) {
|
||||
dispatch(AppMessage::EmuWindow {
|
||||
id: self.id,
|
||||
message: EmuWindowMessage::Closing,
|
||||
})
|
||||
dispatch(AppMessage::EmuWindow(EmuWindowMessage::Closing { id: self.id }));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ use cacao::notification_center::Dispatcher;
|
|||
use frontend_common::audio;
|
||||
use gb_emu_lib::connect::{EmulatorCoreTrait, EmulatorMessage};
|
||||
use raw_window_handle::{AppKitDisplayHandle, RawDisplayHandle};
|
||||
use uuid::Uuid;
|
||||
|
||||
use self::cacao_window_manager::{CacaoWindowManager, EmuWindowMessage};
|
||||
use self::preferences::{PreferencesMessage, PreferencesUi};
|
||||
|
@ -21,7 +20,7 @@ mod preferences;
|
|||
pub(crate) enum AppMessage {
|
||||
Core(CoreMessage),
|
||||
Preferences(PreferencesMessage),
|
||||
EmuWindow { id: Uuid, message: EmuWindowMessage },
|
||||
EmuWindow(EmuWindowMessage),
|
||||
}
|
||||
|
||||
pub(crate) enum CoreMessage {
|
||||
|
@ -122,9 +121,9 @@ impl Dispatcher for TwincUiApp {
|
|||
}
|
||||
}
|
||||
}
|
||||
AppMessage::EmuWindow { id, message } => {
|
||||
AppMessage::EmuWindow(window_message) => {
|
||||
if let Ok(mut window_manager) = self.current_game.write() {
|
||||
window_manager.message(id, message);
|
||||
window_manager.message(window_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ pub struct JoypadState {
|
|||
pub a: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum JoypadButtons {
|
||||
Down,
|
||||
Up,
|
||||
|
|
Loading…
Add table
Reference in a new issue