Added working keyboard support for Mac

Also moved all code out from windows.rs to a shared key_handler impl
This commit is contained in:
Daniel Collin 2016-01-02 18:55:46 +01:00
parent 8e9f8d33a1
commit 867daf1ca9
7 changed files with 440 additions and 52 deletions

123
src/key_handler.rs Normal file
View file

@ -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<Vec<Key>> {
let mut index: u16 = 0;
let mut keys: Vec<Key> = 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<Vec<Key>> {
let mut index: u16 = 0;
let mut keys: Vec<Key> = 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);
}
}

View file

@ -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")]

View file

@ -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<Vec<Key>> {
None
}
pub fn get_keys_pressed(&self, _: KeyRepeat) -> Option<Vec<Key>> {
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<Vec<Key>> {
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
}
};

View file

@ -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;
}

View file

@ -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

View file

@ -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])

View file

@ -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<u16> {
pub struct Window {
dc: Option<HDC>,
window: Option<HWND>,
keys: [bool; 512],
keys_down_duration: [f32; 512],
buffer: Vec<u32>,
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();