diff --git a/src/key_handler.rs b/src/key_handler.rs new file mode 100644 index 0000000..1f6233c --- /dev/null +++ b/src/key_handler.rs @@ -0,0 +1,123 @@ +extern crate time; + +use std::mem; +use {Key, KeyRepeat}; + +pub struct KeyHandler { + prev_time: f64, + delta_time: f32, + keys: [bool; 512], + keys_down_duration: [f32; 512], + key_repeat_delay: f32, + key_repeat_rate: f32, +} + +impl KeyHandler { + pub fn new() -> KeyHandler { + KeyHandler { + keys: [false; 512], + keys_down_duration: [-1.0; 512], + prev_time: time::precise_time_s(), + delta_time: 0.0, + key_repeat_delay: 0.250, + key_repeat_rate: 0.050, + } + } + + #[inline] + pub fn set_key_state(&mut self, key: Key, state: bool) { + self.keys[key as usize] = state; + } + + pub fn get_keys(&self) -> Option> { + let mut index: u16 = 0; + let mut keys: Vec = Vec::new(); + + for i in self.keys.iter() { + if *i { + unsafe { + keys.push(mem::transmute(index as u8)); + } + } + + index += 1; + } + + Some(keys) + } + + pub fn update(&mut self) { + let current_time = time::precise_time_s(); + let delta_time = (current_time - self.prev_time) as f32; + self.prev_time = current_time; + self.delta_time = delta_time; + + for i in 0..self.keys.len() { + if self.keys[i] { + if self.keys_down_duration[i] < 0.0 { + self.keys_down_duration[i] = 0.0; + } else { + self.keys_down_duration[i] += delta_time; + } + } else { + self.keys_down_duration[i] = -1.0; + } + } + } + + pub fn get_keys_pressed(&self, repeat: KeyRepeat) -> Option> { + let mut index: u16 = 0; + let mut keys: Vec = Vec::new(); + + for i in self.keys.iter() { + if *i { + unsafe { + if Self::key_pressed(self, index as usize, repeat) { + keys.push(mem::transmute(index as u8)); + } + } + } + + index += 1; + } + + Some(keys) + } + + #[inline] + pub fn is_key_down(&self, key: Key) -> bool { + return self.keys[key as usize]; + } + + #[inline] + pub fn set_key_repeat_delay(&mut self, delay: f32) { + self.key_repeat_delay = delay; + } + + #[inline] + pub fn set_key_repeat_rate(&mut self, rate: f32) { + self.key_repeat_rate = rate; + } + + pub fn key_pressed(&self, index: usize, repeat: KeyRepeat) -> bool { + let t = self.keys_down_duration[index]; + + if t == 0.0 { + return true; + } + + if repeat == KeyRepeat::Yes && t > self.key_repeat_delay { + let delay = self.key_repeat_delay; + let rate = self.key_repeat_rate; + if ((((t - delay) % rate) > rate * 0.5)) != (((t - delay - self.delta_time) % rate) > rate * 0.5) { + return true; + } + } + + return false; + } + + pub fn is_key_pressed(&self, key: Key, repeat: KeyRepeat) -> bool { + return Self::key_pressed(self, key as usize, repeat); + } +} diff --git a/src/lib.rs b/src/lib.rs index 82c8bbb..eb2ef5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ pub enum KeyRepeat { No, } +#[derive(PartialEq, Clone, Copy)] pub enum Key { Key0 = 0, Key1 = 1, @@ -144,11 +145,22 @@ pub enum Key { NumPadPlus, NumPadEnter, - Count = 103, + LeftAlt, + RightAlt, + + LeftSuper, + RightSuper, + + /// Used when an Unknown key has been pressed + Unknown, + + Count = 107, } extern crate libc; +pub mod key_handler; + #[cfg(target_os = "windows")] pub mod windows; #[cfg(target_os = "windows")] diff --git a/src/macos.rs b/src/macos.rs index e2ecf3a..afa6de7 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -1,20 +1,171 @@ #![cfg(target_os = "macos")] use {Scale, Key, KeyRepeat}; +use key_handler::KeyHandler; use libc::{c_void, c_char, c_uchar}; use std::ffi::{CString}; use std::ptr; +use std::mem; + +// Table taken from GLFW and slightly modified + +static KEY_MAPPINGS: [Key; 128] = [ + /* 00 */ Key::A, + /* 01 */ Key::S, + /* 02 */ Key::D, + /* 03 */ Key::F, + /* 04 */ Key::H, + /* 05 */ Key::G, + /* 06 */ Key::Z, + /* 07 */ Key::X, + /* 08 */ Key::C, + /* 09 */ Key::V, + /* 0a */ Key::Unknown, // GraveAccent + /* 0b */ Key::B, + /* 0c */ Key::Q, + /* 0d */ Key::W, + /* 0e */ Key::E, + /* 0f */ Key::R, + /* 10 */ Key::Y, + /* 11 */ Key::T, + /* 12 */ Key::Key1, + /* 13 */ Key::Key2, + /* 14 */ Key::Key3, + /* 15 */ Key::Key4, + /* 16 */ Key::Key6, + /* 17 */ Key::Key5, + /* 18 */ Key::Equal, + /* 19 */ Key::Key9, + /* 1a */ Key::Key7, + /* 1b */ Key::Minus, + /* 1c */ Key::Key8, + /* 1d */ Key::Key0, + /* 1e */ Key::RightBracket, + /* 1f */ Key::O, + /* 20 */ Key::U, + /* 21 */ Key::LeftBracket, + /* 22 */ Key::I, + /* 23 */ Key::P, + /* 24 */ Key::Enter, + /* 25 */ Key::L, + /* 26 */ Key::J, + /* 27 */ Key::Apostrophe, + /* 28 */ Key::K, + /* 29 */ Key::Semicolon, + /* 2a */ Key::Backslash, + /* 2b */ Key::Comma, + /* 2c */ Key::Slash, + /* 2d */ Key::N, + /* 2e */ Key::M, + /* 2f */ Key::Period, + /* 30 */ Key::Tab, + /* 31 */ Key::Space, + /* 32 */ Key::Unknown, // World1 + /* 33 */ Key::Backspace, + /* 34 */ Key::Unknown, + /* 35 */ Key::Escape, + /* 36 */ Key::RightSuper, + /* 37 */ Key::LeftSuper, + /* 38 */ Key::LeftShift, + /* 39 */ Key::CapsLock, + /* 3a */ Key::LeftAlt, + /* 3b */ Key::LeftCtrl, + /* 3c */ Key::RightShift, + /* 3d */ Key::RightAlt, + /* 3e */ Key::RightCtrl, + /* 3f */ Key::Unknown, // Function + /* 40 */ Key::Unknown, // F17 + /* 41 */ Key::Unknown, // Decimal + /* 42 */ Key::Unknown, + /* 43 */ Key::Unknown, // Multiply + /* 44 */ Key::Unknown, + /* 45 */ Key::Unknown, // Add + /* 46 */ Key::Unknown, + /* 47 */ Key::NumLock, // Really KeypadClear... + /* 48 */ Key::Unknown, // VolumeUp + /* 49 */ Key::Unknown, // VolumeDown + /* 4a */ Key::Unknown, // Mute + /* 4b */ Key::Unknown, + /* 4c */ Key::Enter, + /* 4d */ Key::Unknown, + /* 4e */ Key::Unknown, // Subtrackt + /* 4f */ Key::Unknown, // F18 + /* 50 */ Key::Unknown, // F19 + /* 51 */ Key::Equal, + /* 52 */ Key::NumPad0, + /* 53 */ Key::NumPad1, + /* 54 */ Key::NumPad2, + /* 55 */ Key::NumPad3, + /* 56 */ Key::NumPad4, + /* 57 */ Key::NumPad5, + /* 58 */ Key::NumPad6, + /* 59 */ Key::NumPad7, + /* 5a */ Key::Unknown, // F20 + /* 5b */ Key::NumPad8, + /* 5c */ Key::NumPad9, + /* 5d */ Key::Unknown, + /* 5e */ Key::Unknown, + /* 5f */ Key::Unknown, + /* 60 */ Key::F5, + /* 61 */ Key::F6, + /* 62 */ Key::F7, + /* 63 */ Key::F3, + /* 64 */ Key::F8, + /* 65 */ Key::F9, + /* 66 */ Key::Unknown, + /* 67 */ Key::F11, + /* 68 */ Key::Unknown, + /* 69 */ Key::Unknown, // PrintScreen + /* 6a */ Key::Unknown, // F16 + /* 6b */ Key::F14, + /* 6c */ Key::Unknown, + /* 6d */ Key::F10, + /* 6e */ Key::Unknown, + /* 6f */ Key::F12, + /* 70 */ Key::Unknown, + /* 71 */ Key::F15, + /* 72 */ Key::Insert, /* Really Help... */ + /* 73 */ Key::Home, + /* 74 */ Key::PageUp, + /* 75 */ Key::Delete, + /* 76 */ Key::F4, + /* 77 */ Key::End, + /* 78 */ Key::F2, + /* 79 */ Key::PageDown, + /* 7a */ Key::F1, + /* 7b */ Key::Left, + /* 7c */ Key::Right, + /* 7d */ Key::Down, + /* 7e */ Key::Up, + /* 7f */ Key::Unknown, +]; #[link(name = "Cocoa", kind = "framework")] extern { fn mfb_open(name: *const c_char, width: u32, height: u32, scale: i32) -> *mut c_void; fn mfb_close(window: *mut c_void); fn mfb_update(window: *mut c_void, buffer: *const c_uchar); + fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32)); + fn mfb_should_close(window: *mut c_void) -> i32; + fn mfb_get_screen_size() -> u32; } pub struct Window { window_handle: *mut c_void, + key_handler: KeyHandler, +} + +unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, state: i32) { + let win: *mut Window = mem::transmute(window); + + let s = state == 1; + + if key > 128 { + (*win).key_handler.set_key_state(Key::Unknown, s); + } else { + (*win).key_handler.set_key_state(KEY_MAPPINGS[key as usize], s); + } } impl Window { @@ -34,51 +185,58 @@ impl Window { return Err("Unable to open Window"); } - Ok(Window { window_handle: handle }) + Ok(Window { + window_handle: handle, + key_handler: KeyHandler::new(), + }) } } pub fn update(&mut self, buffer: &[u32]) { + self.key_handler.update(); + unsafe { mfb_update(self.window_handle, buffer.as_ptr() as *const u8); + mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback); } } + #[inline] pub fn get_keys(&self) -> Option> { - None - } - - pub fn get_keys_pressed(&self, _: KeyRepeat) -> Option> { - None + self.key_handler.get_keys() } #[inline] - pub fn is_key_down(&self, _: Key) -> bool { - false + pub fn get_keys_pressed(&self, repeat: KeyRepeat) -> Option> { + self.key_handler.get_keys_pressed(repeat) } #[inline] - pub fn set_key_repeat_delay(&mut self, _: f32) { + pub fn is_key_down(&self, key: Key) -> bool { + self.key_handler.is_key_down(key) } #[inline] - pub fn set_key_repeat_rate(&mut self, _: f32) { + pub fn set_key_repeat_delay(&mut self, delay: f32) { + self.key_handler.set_key_repeat_delay(delay) } - pub fn key_pressed(&self, _: usize, _: KeyRepeat) -> bool { - false + #[inline] + pub fn set_key_repeat_rate(&mut self, rate: f32) { + self.key_handler.set_key_repeat_rate(rate) } - pub fn is_key_pressed(&self, _: Key, _: KeyRepeat) -> bool { - false + #[inline] + pub fn is_key_pressed(&self, key: Key, repeat: KeyRepeat) -> bool { + self.key_handler.is_key_pressed(key, repeat) } #[inline] pub fn is_open(&self) -> bool { - true + unsafe { mfb_should_close(self.window_handle) == 0 } } - unsafe fn get_scale_factor(_: usize, _: usize, scale: Scale) -> i32 { + unsafe fn get_scale_factor(width: usize, height: usize, scale: Scale) -> i32 { let factor: i32 = match scale { Scale::X1 => 1, Scale::X2 => 2, @@ -87,7 +245,24 @@ impl Window { Scale::X16 => 16, Scale::X32 => 32, Scale::FitScreen => { - 1 + let wh: u32 = mfb_get_screen_size(); + let screen_x = (wh >> 16) as i32; + let screen_y = (wh & 0xffff) as i32; + + let mut scale = 1i32; + + loop { + let w = width as i32 * (scale + 1); + let h = height as i32 * (scale + 1); + + if w > screen_x || h > screen_y { + break; + } + + scale *= 2; + } + + scale } }; diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index 8b0ab3f..4117534 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -5,6 +5,7 @@ static bool s_init = false; + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void* mfb_open(const char* name, int width, int height, int scale) @@ -25,6 +26,12 @@ void* mfb_open(const char* name, int width, int height, int scale) if (!window) return 0; + NSRect e = [[NSScreen mainScreen] frame]; + int H = (int)e.size.height; + int W = (int)e.size.width; + + printf("H %d W %d\n", W, H); + window->draw_buffer = malloc(width * height * 4); if (!window->draw_buffer) @@ -33,6 +40,7 @@ void* mfb_open(const char* name, int width, int height, int scale) window->width = width; window->height = height; window->scale = scale; + window->key_callback = 0; [window updateSize]; @@ -88,3 +96,31 @@ int mfb_update(void* window, void* buffer) [[win contentView] setNeedsDisplay:YES]; return state; } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_should_close(void* window) +{ + OSXWindow* win = (OSXWindow*)window; + return win->should_close; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +uint32_t mfb_get_screen_size() +{ + NSRect e = [[NSScreen mainScreen] frame]; + uint32_t w = (uint32_t)e.size.width; + uint32_t h = (uint32_t)e.size.height; + return (w << 16) | h; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mfb_set_key_callback(void* window, void* rust_data, void (*key_callback)(void* user_data, int key, int state)) +{ + OSXWindow* win = (OSXWindow*)window; + win->key_callback = key_callback; + win->rust_data = rust_data; +} + diff --git a/src/native/macosx/OSXWindow.h b/src/native/macosx/OSXWindow.h index 2541897..48b7532 100644 --- a/src/native/macosx/OSXWindow.h +++ b/src/native/macosx/OSXWindow.h @@ -3,10 +3,13 @@ @interface OSXWindow : NSWindow { NSView* childContentView; + @public void (*key_callback)(void* user_data, int key, int state); @public int width; @public int height; @public int scale; @public void* draw_buffer; + @public void* rust_data; + @public bool should_close; } @end diff --git a/src/native/macosx/OSXWindow.m b/src/native/macosx/OSXWindow.m index 0938eba..c406f55 100644 --- a/src/native/macosx/OSXWindow.m +++ b/src/native/macosx/OSXWindow.m @@ -58,19 +58,87 @@ newFrameSize.width += sizeDelta.width; newFrameSize.height += sizeDelta.height; - printf("conten size\n"); - [super setContentSize:newFrameSize]; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +-(void)flagsChanged:(NSEvent *)event +{ + const uint32_t flags = [event modifierFlags]; + + // Left Shift + key_callback(rust_data, 0x38, flags == 0x20102 ? 1 : 0); + + // RightShift + key_callback(rust_data, 0x3c, flags == 0x20104 ? 1 : 0); + + // Left Ctrl + key_callback(rust_data, 0x3b, flags == 0x40101 ? 1 : 0); + + // Right Ctrl + key_callback(rust_data, 0x3b, flags == 0x42101 ? 1 : 0); + + // Left Alt + key_callback(rust_data, 0x3a, flags == 0x80120 ? 1 : 0); + + // Right Super + key_callback(rust_data, 0x3d, flags == 0x80140 ? 1 : 0); + + // Left Super + key_callback(rust_data, 0x37, flags == 0x100108 ? 1 : 0); + + // Right Super + key_callback(rust_data, 0x36, flags == 0x100110 ? 1 : 0); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)keyDown:(NSEvent *)event +{ + // Cmd+Q always closes app + if ([event.characters.uppercaseString isEqualToString:@"Q"] && ([event modifierFlags] & NSCommandKeyMask)) { + [self performClose:self]; + return; + } + + if (key_callback) { + key_callback(rust_data, [event keyCode], 1); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)keyUp:(NSEvent *)event +{ + if (key_callback) { + key_callback(rust_data, [event keyCode], 0); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + - (void)mainWindowChanged:(NSNotification *)aNotification { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)windowWillClose:(NSNotification *)notification +{ + should_close = true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)windowShouldClose:(id)sender +{ + should_close = true; + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + - (void)setContentView:(NSView *)aView { if ([childContentView isEqualTo:aView]) diff --git a/src/windows.rs b/src/windows.rs index eb90143..257f2c6 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -6,9 +6,7 @@ extern crate winapi; extern crate gdi32; extern crate time; -use Scale; -use Key; -use KeyRepeat; +use {Scale, Key, KeyRepeat, KeyHandler}; use std::ptr; use std::os::windows::ffi::OsStrExt; @@ -217,17 +215,12 @@ fn to_wstring(str: &str) -> Vec { pub struct Window { dc: Option, window: Option, - keys: [bool; 512], - keys_down_duration: [f32; 512], buffer: Vec, is_open : bool, scale_factor: i32, width: i32, height: i32, - prev_time: f64, - delta_time: f32, - key_repeat_delay: f32, - key_repeat_rate: f32, + key_handler: KeyHandler, } impl Window { @@ -316,13 +309,8 @@ impl Window { let window = Window { dc: Some(user32::GetDC(handle.unwrap())), window: Some(handle.unwrap()), - keys: [false; 512], - keys_down_duration: [-1.0; 512], - prev_time: time::precise_time_s(), - delta_time: 0.0, - key_repeat_delay: 0.250, - key_repeat_rate: 0.050, buffer: Vec::new(), + key_handler: KeyHandler::new(), is_open: true, scale_factor: scale_factor, width: width as i32, @@ -415,23 +403,6 @@ impl Window { let mut msg = mem::uninitialized(); let window = self.window.unwrap(); - let current_time = time::precise_time_s(); - let delta_time = (current_time - self.prev_time) as f32; - self.prev_time = current_time; - self.delta_time = delta_time; - - for i in 0..self.keys.len() { - if self.keys[i] { - if self.keys_down_duration[i] < 0.0 { - self.keys_down_duration[i] = 0.0; - } else { - self.keys_down_duration[i] += delta_time; - } - } else { - self.keys_down_duration[i] = -1.0; - } - } - // TODO: Optimize self.buffer = buffer.iter().cloned().collect();