mirror of
https://github.com/italicsjenga/rust_minifb.git
synced 2024-12-24 03:41:29 +11:00
Merge from mouse-support
This commit is contained in:
parent
8ba8047d11
commit
8bdbc850d5
11
CHANGELOG.md
Normal file
11
CHANGELOG.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
This project follows semantic versioning.
|
||||||
|
|
||||||
|
### v0.3.0 (2016-01-29)
|
||||||
|
|
||||||
|
- [added] get_mouse_pos
|
||||||
|
- [added] get_mouse_down
|
||||||
|
- [added] get_scroll_wheel
|
||||||
|
|
||||||
|
This relase adds support for mouse input. See the documentation and the examples for usage
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "minifb"
|
name = "minifb"
|
||||||
version = "0.2.7"
|
version = "0.3.0"
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
authors = ["Daniel Collin <daniel@collin.com>"]
|
authors = ["Daniel Collin <daniel@collin.com>"]
|
||||||
description = "Cross-platform window setup for bitmap rendering"
|
description = "Cross-platform window setup for bitmap rendering"
|
||||||
|
|
126
appveyor.yml
126
appveyor.yml
|
@ -1,16 +1,118 @@
|
||||||
|
## Operating System (VM environment) ##
|
||||||
|
|
||||||
|
# Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets.
|
||||||
|
os: Visual Studio 2015
|
||||||
|
|
||||||
|
## Build Matrix ##
|
||||||
|
|
||||||
|
# This configuration will setup a build for each channel & target combination (12 windows
|
||||||
|
# combinations in all).
|
||||||
|
#
|
||||||
|
# There are 3 channels: stable, beta, and nightly.
|
||||||
|
#
|
||||||
|
# The values for target are the set of windows Rust build targets. Each value is of the form
|
||||||
|
#
|
||||||
|
# ARCH-pc-windows-TOOLCHAIN
|
||||||
|
#
|
||||||
|
# Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker
|
||||||
|
# toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for
|
||||||
|
# a description of the toolchain differences.
|
||||||
|
#
|
||||||
|
# Comment out channel/target combos you do not wish to build in CI.
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- TARGET: x86_64-pc-windows-msvc
|
|
||||||
- TARGET: i686-pc-windows-msvc
|
|
||||||
- TARGET: i686-pc-windows-gnu
|
|
||||||
install:
|
|
||||||
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
|
|
||||||
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
|
|
||||||
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
|
|
||||||
- SET PATH=%PATH%;C:\MinGW\bin
|
|
||||||
- rustc -V
|
|
||||||
- cargo -V
|
|
||||||
build: false
|
|
||||||
|
|
||||||
|
### MSVC Toolchains ###
|
||||||
|
|
||||||
|
# Stable 64-bit MSVC
|
||||||
|
- channel: stable
|
||||||
|
target: x86_64-pc-windows-msvc
|
||||||
|
# Stable 32-bit MSVC
|
||||||
|
- channel: stable
|
||||||
|
target: i686-pc-windows-msvc
|
||||||
|
# Beta 64-bit MSVC
|
||||||
|
- channel: beta
|
||||||
|
target: x86_64-pc-windows-msvc
|
||||||
|
# Beta 32-bit MSVC
|
||||||
|
- channel: beta
|
||||||
|
target: i686-pc-windows-msvc
|
||||||
|
# Nightly 64-bit MSVC
|
||||||
|
- channel: nightly
|
||||||
|
target: x86_64-pc-windows-msvc
|
||||||
|
# Nightly 32-bit MSVC
|
||||||
|
- channel: nightly
|
||||||
|
target: i686-pc-windows-msvc
|
||||||
|
|
||||||
|
### GNU Toolchains ###
|
||||||
|
|
||||||
|
# Stable 64-bit GNU
|
||||||
|
- channel: stable
|
||||||
|
target: x86_64-pc-windows-gnu
|
||||||
|
# Stable 32-bit GNU
|
||||||
|
- channel: stable
|
||||||
|
target: i686-pc-windows-gnu
|
||||||
|
# Beta 64-bit GNU
|
||||||
|
- channel: beta
|
||||||
|
target: x86_64-pc-windows-gnu
|
||||||
|
# Beta 32-bit GNU
|
||||||
|
- channel: beta
|
||||||
|
target: i686-pc-windows-gnu
|
||||||
|
# Nightly 64-bit GNU
|
||||||
|
- channel: nightly
|
||||||
|
target: x86_64-pc-windows-gnu
|
||||||
|
# Nightly 32-bit GNU
|
||||||
|
- channel: nightly
|
||||||
|
target: i686-pc-windows-gnu
|
||||||
|
|
||||||
|
### Allowed failures ###
|
||||||
|
|
||||||
|
# See Appveyor documentation for specific details. In short, place any channel or targets you wish
|
||||||
|
# to allow build failures on (usually nightly at least is a wise choice). This will prevent a build
|
||||||
|
# or test failure in the matching channels/targets from failing the entire build.
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- channel: nightly
|
||||||
|
|
||||||
|
# If you only care about stable channel build failures, uncomment the following line:
|
||||||
|
#- channel: beta
|
||||||
|
|
||||||
|
# 32-bit MSVC isn't stablized yet, so you may optionally allow failures there (uncomment line):
|
||||||
|
#- target: i686-pc-windows-msvc
|
||||||
|
|
||||||
|
## Install Script ##
|
||||||
|
|
||||||
|
# This is the most important part of the Appveyor configuration. This installs the version of Rust
|
||||||
|
# specified by the 'channel' and 'target' environment variables from the build matrix. By default,
|
||||||
|
# Rust will be installed to C:\Rust for easy usage, but this path can be overridden by setting the
|
||||||
|
# RUST_INSTALL_DIR environment variable. The URL to download rust distributions defaults to
|
||||||
|
# https://static.rust-lang.org/dist/ but can overridden by setting the RUST_DOWNLOAD_URL environment
|
||||||
|
# variable.
|
||||||
|
#
|
||||||
|
# For simple configurations, instead of using the build matrix, you can override the channel and
|
||||||
|
# target environment variables with the -channel and -target script arguments.
|
||||||
|
#
|
||||||
|
# If no channel or target arguments or environment variables are specified, will default to stable
|
||||||
|
# channel and x86_64-pc-windows-msvc target.
|
||||||
|
#
|
||||||
|
# The file appveyor_rust_install.ps1 must exist in the root directory of the repository.
|
||||||
|
install:
|
||||||
|
- ps: .\appveyor_rust_install.ps1
|
||||||
|
|
||||||
|
# Alternative install command for simple configurations without build matrix (uncomment line and
|
||||||
|
# comment above line):
|
||||||
|
#- ps: .\appveyor_rust_install.ps1 -channel stable -target x86_64-pc-windows-msvc
|
||||||
|
|
||||||
|
## Build Script ##
|
||||||
|
|
||||||
|
# Uses 'cargo build' to build. Alternatively, the project may call rustc directly or perform other
|
||||||
|
# build commands. Rust will automatically be placed in the PATH environment variable.
|
||||||
|
build_script:
|
||||||
|
- cmd: cargo build --verbose
|
||||||
|
|
||||||
|
## Build Script ##
|
||||||
|
|
||||||
|
# Uses 'cargo test' to run tests. Alternatively, the project may call compiled programs directly or
|
||||||
|
# perform other testing commands. Rust will automatically be placed in the PATH environment
|
||||||
|
# variable.
|
||||||
test_script:
|
test_script:
|
||||||
- cargo test --verbose
|
- cmd: cargo test --verbose
|
||||||
|
|
66
appveyor_rust_install.ps1
Normal file
66
appveyor_rust_install.ps1
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
##### Appveyor Rust Install Script #####
|
||||||
|
|
||||||
|
# This is the most important part of the Appveyor configuration. This installs the version of Rust
|
||||||
|
# specified by the "channel" and "target" environment variables from the build matrix. By default,
|
||||||
|
# Rust will be installed to C:\Rust for easy usage, but this path can be overridden by setting the
|
||||||
|
# RUST_INSTALL_DIR environment variable. The URL to download rust distributions defaults to
|
||||||
|
# https://static.rust-lang.org/dist/ but can overridden by setting the RUST_DOWNLOAD_URL environment
|
||||||
|
# variable.
|
||||||
|
#
|
||||||
|
# For simple configurations, instead of using the build matrix, you can override the channel and
|
||||||
|
# target environment variables with the --channel and --target script arguments.
|
||||||
|
#
|
||||||
|
# If no channel or target arguments or environment variables are specified, will default to stable
|
||||||
|
# channel and x86_64-pc-windows-msvc target.
|
||||||
|
|
||||||
|
param([string]$channel=${env:channel}, [string]$target=${env:target})
|
||||||
|
|
||||||
|
# Initialize our parameters from arguments and environment variables, falling back to defaults
|
||||||
|
if (!$channel) {
|
||||||
|
$channel = "stable"
|
||||||
|
}
|
||||||
|
if (!$target) {
|
||||||
|
$target = "x86_64-pc-windows-msvc"
|
||||||
|
}
|
||||||
|
|
||||||
|
$downloadUrl = "https://static.rust-lang.org/dist/"
|
||||||
|
if ($env:RUST_DOWNLOAD_URL) {
|
||||||
|
$downloadUrl = $env:RUST_DOWNLOAD_URL
|
||||||
|
}
|
||||||
|
|
||||||
|
$installDir = "C:\Rust"
|
||||||
|
if ($env:RUST_INSTALL_DIR) {
|
||||||
|
$installUrl = $env:RUST_INSTALL_DIR
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download manifest so we can find actual filename of installer to download. Needed mostly for
|
||||||
|
# stable channel.
|
||||||
|
echo "Downloading $channel channel manifest"
|
||||||
|
$manifest = "${env:Temp}\channel-rust-${channel}"
|
||||||
|
Start-FileDownload "${downloadUrl}channel-rust-${channel}" -FileName "$manifest"
|
||||||
|
|
||||||
|
# Search the manifest lines for the correct filename based on target
|
||||||
|
$match = Get-Content "$manifest" | Select-String -pattern "${target}.exe" -simplematch
|
||||||
|
|
||||||
|
if (!$match -or !$match.line) {
|
||||||
|
throw "Could not find $target in $channel channel manifest"
|
||||||
|
}
|
||||||
|
|
||||||
|
$installer = $match.line
|
||||||
|
|
||||||
|
# Download installer
|
||||||
|
echo "Downloading ${downloadUrl}$installer"
|
||||||
|
Start-FileDownload "${downloadUrl}$installer" -FileName "${env:Temp}\$installer"
|
||||||
|
|
||||||
|
# Execute installer and wait for it to finish
|
||||||
|
echo "Installing $installer to $installDir"
|
||||||
|
&"${env:Temp}\$installer" /VERYSILENT /NORESTART /DIR="$installDir" | Write-Output
|
||||||
|
|
||||||
|
# Add Rust to the path.
|
||||||
|
$env:Path += ";${installDir}\bin;C:\MinGW\bin"
|
||||||
|
|
||||||
|
echo "Installation of $channel Rust $target completed"
|
||||||
|
|
||||||
|
# Test and display installed version information for rustc and cargo
|
||||||
|
rustc -V
|
||||||
|
cargo -V
|
38
examples/mouse.rs
Normal file
38
examples/mouse.rs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
extern crate minifb;
|
||||||
|
|
||||||
|
use minifb::{MouseButton, MouseMode, Window, Key, Scale};
|
||||||
|
|
||||||
|
const WIDTH: usize = 640;
|
||||||
|
const HEIGHT: usize = 360;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut buffer: Vec<u32> = vec![0; WIDTH * HEIGHT];
|
||||||
|
|
||||||
|
let mut window = match Window::new("Mouse Draw - Press ESC to exit", WIDTH, HEIGHT, Scale::X2) {
|
||||||
|
Ok(win) => win,
|
||||||
|
Err(err) => {
|
||||||
|
println!("Unable to create window {}", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
while window.is_open() && !window.is_key_down(Key::Escape) {
|
||||||
|
window.get_mouse_pos(MouseMode::Discard).map(|mouse| {
|
||||||
|
let screen_pos = ((mouse.1 as usize) * WIDTH) + mouse.0 as usize;
|
||||||
|
|
||||||
|
if window.get_mouse_down(MouseButton::Left) {
|
||||||
|
buffer[screen_pos] = 0x00ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if window.get_mouse_down(MouseButton::Right) {
|
||||||
|
buffer[screen_pos] = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.get_scroll_wheel().map(|scroll| {
|
||||||
|
println!("Scrolling {} - {}", scroll.0, scroll.1);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.update(&buffer);
|
||||||
|
}
|
||||||
|
}
|
79
src/lib.rs
79
src/lib.rs
|
@ -30,6 +30,18 @@ pub enum KeyRepeat {
|
||||||
No,
|
No,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The various mouse buttons that are availible
|
||||||
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
|
pub enum MouseButton
|
||||||
|
{
|
||||||
|
/// Left mouse button
|
||||||
|
Left,
|
||||||
|
/// Middle mouse button
|
||||||
|
Middle,
|
||||||
|
/// Right mouse button
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
/// Key is used by the get key functions to check if some keys on the keyboard has been pressed
|
/// Key is used by the get key functions to check if some keys on the keyboard has been pressed
|
||||||
#[derive(PartialEq, Clone, Copy)]
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
pub enum Key {
|
pub enum Key {
|
||||||
|
@ -158,9 +170,22 @@ pub enum Key {
|
||||||
Count = 107,
|
Count = 107,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Key is used by the get key functions to check if some keys on the keyboard has been pressed
|
||||||
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
|
pub enum MouseMode {
|
||||||
|
/// Return mouse coords from outside of the window (may be negative)
|
||||||
|
Pass,
|
||||||
|
/// Clamp the mouse coordinates within the window
|
||||||
|
Clamp,
|
||||||
|
/// Discared if the mouse is outside the window
|
||||||
|
Discard,
|
||||||
|
}
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
pub mod os;
|
pub mod os;
|
||||||
|
mod mouse_handler;
|
||||||
mod key_handler;
|
mod key_handler;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
@ -258,7 +283,6 @@ impl Window {
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// // Moves the window to pixel postion 20, 20 on the screen
|
/// // Moves the window to pixel postion 20, 20 on the screen
|
||||||
/// window.set_position(20, 20);
|
/// window.set_position(20, 20);
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -266,6 +290,59 @@ impl Window {
|
||||||
self.0.set_position(x, y)
|
self.0.set_position(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the current position of the mouse relative to the current window
|
||||||
|
/// The coordinate system is as 0, 0 as the upper left corner
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// window.get_mouse_pos(MouseMode::Clamp).map(|mouse| {
|
||||||
|
/// println!("x {} y {}", mouse.0, mouse.1);
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mouse_pos(&self, mode: MouseMode) -> Option<(f32, f32)> {
|
||||||
|
self.0.get_mouse_pos(mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Check if a mouse button is down or not
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// let left_down = window.get_mouse_down(MouseButton::Left);
|
||||||
|
/// println!("is left down? {}", left_down)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mouse_down(&self, button: MouseButton) -> bool {
|
||||||
|
self.0.get_mouse_down(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the current movement of the scroll wheel.
|
||||||
|
/// Scroll wheel can mean different thing depending on the device attach.
|
||||||
|
/// For example on Mac with trackpad "scroll wheel" means two finger
|
||||||
|
/// swiping up/down (y axis) and to the sides (x-axis)
|
||||||
|
/// When using a mouse this assumes the scroll wheel which often is only y direction.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// window.get_scroll_wheel().map(|scroll| {
|
||||||
|
/// println!("scrolling - x {} y {}", scroll.0, scroll.1);
|
||||||
|
/// });
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
///
|
||||||
|
#[inline]
|
||||||
|
pub fn get_scroll_wheel(&self) -> Option<(f32, f32)> {
|
||||||
|
self.0.get_scroll_wheel()
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Get the current keys that are down.
|
/// Get the current keys that are down.
|
||||||
///
|
///
|
||||||
|
|
29
src/mouse_handler.rs
Normal file
29
src/mouse_handler.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
use MouseMode;
|
||||||
|
|
||||||
|
fn clamp(v: f32, lb: f32, ub: f32) -> f32 {
|
||||||
|
f32::min(f32::max(v, lb), ub)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pos(mode: MouseMode, mx: f32, my: f32, scale: f32, width: f32, height: f32) -> Option<(f32, f32)> {
|
||||||
|
let s = 1.0 / scale as f32;
|
||||||
|
let x = mx * s;
|
||||||
|
let y = my * s;
|
||||||
|
let window_width = width * s;
|
||||||
|
let window_height = height * s;
|
||||||
|
|
||||||
|
match mode {
|
||||||
|
MouseMode::Pass => Some((x, y)),
|
||||||
|
MouseMode::Clamp => {
|
||||||
|
Some((clamp(x, 0.0, window_width),
|
||||||
|
clamp(y, 0.0, window_height)))
|
||||||
|
},
|
||||||
|
MouseMode::Discard => {
|
||||||
|
if x < 0.0 || y < 0.0 || x >= window_width || y >= window_height {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((x, y))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
|
|
||||||
#include "OSXWindow.h"
|
#include "OSXWindow.h"
|
||||||
|
#include "OSXWindowFrameView.h"
|
||||||
#include <Cocoa/Cocoa.h>
|
#include <Cocoa/Cocoa.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
static bool s_init = false;
|
static bool s_init = false;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic ignored "-Wobjc-method-access" // [window updateSize];
|
||||||
|
#endif
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -35,12 +41,14 @@ void* mfb_open(const char* name, int width, int height, int scale)
|
||||||
window->height = height;
|
window->height = height;
|
||||||
window->scale = scale;
|
window->scale = scale;
|
||||||
window->key_callback = 0;
|
window->key_callback = 0;
|
||||||
|
window->shared_data = 0;
|
||||||
|
|
||||||
[window updateSize];
|
[window updateSize];
|
||||||
|
|
||||||
[window setTitle:[NSString stringWithUTF8String:name]];
|
[window setTitle:[NSString stringWithUTF8String:name]];
|
||||||
[window setReleasedWhenClosed:NO];
|
[window setReleasedWhenClosed:NO];
|
||||||
[window performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES];
|
[window performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES];
|
||||||
|
[window setAcceptsMouseMovedEvents:YES];
|
||||||
|
|
||||||
[window center];
|
[window center];
|
||||||
|
|
||||||
|
@ -85,8 +93,16 @@ int mfb_update(void* window, void* buffer)
|
||||||
OSXWindow* win = (OSXWindow*)window;
|
OSXWindow* win = (OSXWindow*)window;
|
||||||
memcpy(win->draw_buffer, buffer, win->width * win->height * 4);
|
memcpy(win->draw_buffer, buffer, win->width * win->height * 4);
|
||||||
|
|
||||||
//g_updateBuffer = buffer;
|
|
||||||
int state = update_events();
|
int state = update_events();
|
||||||
|
|
||||||
|
if (win->shared_data) {
|
||||||
|
NSPoint p = [win mouseLocationOutsideOfEventStream];
|
||||||
|
NSRect originalFrame = [win frame];
|
||||||
|
NSRect contentRect = [NSWindow contentRectForFrameRect: originalFrame styleMask: NSTitledWindowMask];
|
||||||
|
win->shared_data->mouse_x = p.x;
|
||||||
|
win->shared_data->mouse_y = contentRect.size.height - p.y;
|
||||||
|
}
|
||||||
|
|
||||||
[[win contentView] setNeedsDisplay:YES];
|
[[win contentView] setNeedsDisplay:YES];
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -138,3 +154,12 @@ void mfb_set_key_callback(void* window, void* rust_data, void (*key_callback)(vo
|
||||||
win->rust_data = rust_data;
|
win->rust_data = rust_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void mfb_set_mouse_data(void* window, SharedData* shared_data)
|
||||||
|
{
|
||||||
|
OSXWindow* win = (OSXWindow*)window;
|
||||||
|
win->shared_data = shared_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#include "shared_data.h"
|
||||||
|
|
||||||
@interface OSXWindow : NSWindow
|
@interface OSXWindow : NSWindow
|
||||||
{
|
{
|
||||||
|
@ -9,6 +10,7 @@
|
||||||
@public int scale;
|
@public int scale;
|
||||||
@public void* draw_buffer;
|
@public void* draw_buffer;
|
||||||
@public void* rust_data;
|
@public void* rust_data;
|
||||||
|
@public SharedData* shared_data;
|
||||||
@public bool should_close;
|
@public bool should_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
@public int width;
|
@public int width;
|
||||||
@public int height;
|
@public int height;
|
||||||
@public void* draw_buffer;
|
@public void* draw_buffer;
|
||||||
|
@private NSTrackingArea* trackingArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -1,9 +1,27 @@
|
||||||
#import "OSXWindowFrameView.h"
|
#import "OSXWindowFrameView.h"
|
||||||
|
#import "OSXWindow.h"
|
||||||
|
|
||||||
@implementation OSXWindowFrameView
|
@implementation OSXWindowFrameView
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
-(void)updateTrackingAreas
|
||||||
|
{
|
||||||
|
if(trackingArea != nil) {
|
||||||
|
[self removeTrackingArea:trackingArea];
|
||||||
|
[trackingArea release];
|
||||||
|
}
|
||||||
|
|
||||||
|
int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
|
||||||
|
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds]
|
||||||
|
options:opts
|
||||||
|
owner:self
|
||||||
|
userInfo:nil];
|
||||||
|
[self addTrackingArea:trackingArea];
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
- (void)drawRect:(NSRect)rect
|
- (void)drawRect:(NSRect)rect
|
||||||
{
|
{
|
||||||
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
|
||||||
|
@ -22,5 +40,60 @@
|
||||||
CGImageRelease(img);
|
CGImageRelease(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
- (void)mouseDown:(NSEvent*)event
|
||||||
|
{
|
||||||
|
OSXWindow* window = (OSXWindow*)[self window];
|
||||||
|
window->shared_data->mouse_state[0] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
- (void)mouseUp:(NSEvent*)event
|
||||||
|
{
|
||||||
|
OSXWindow* window = (OSXWindow*)[self window];
|
||||||
|
window->shared_data->mouse_state[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
- (void)rightMouseDown:(NSEvent*)event
|
||||||
|
{
|
||||||
|
OSXWindow* window = (OSXWindow*)[self window];
|
||||||
|
window->shared_data->mouse_state[2] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
- (void)rightMouseUp:(NSEvent*)event
|
||||||
|
{
|
||||||
|
OSXWindow* window = (OSXWindow*)[self window];
|
||||||
|
window->shared_data->mouse_state[2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
- (void)scrollWheel:(NSEvent *)event
|
||||||
|
{
|
||||||
|
OSXWindow* window = (OSXWindow*)[self window];
|
||||||
|
window->shared_data->scroll_x = [event deltaX];
|
||||||
|
window->shared_data->scroll_y = [event deltaY];
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
- (BOOL)canBecomeKeyView
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstResponder
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
12
src/native/macosx/shared_data.h
Normal file
12
src/native/macosx/shared_data.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct SharedData {
|
||||||
|
unsigned int width;
|
||||||
|
unsigned int height;
|
||||||
|
float mouse_x;
|
||||||
|
float mouse_y;
|
||||||
|
float scroll_x;
|
||||||
|
float scroll_y;
|
||||||
|
unsigned char mouse_state[8];
|
||||||
|
} SharedData;
|
||||||
|
|
|
@ -4,11 +4,14 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#define KEY_FUNCTION 0xFF
|
#define KEY_FUNCTION 0xFF
|
||||||
#define KEY_ESC 0x1B
|
#define KEY_ESC 0x1B
|
||||||
|
#define Button6 6
|
||||||
|
#define Button7 7
|
||||||
|
|
||||||
void mfb_close(void* window_info);
|
void mfb_close(void* window_info);
|
||||||
|
|
||||||
|
@ -28,9 +31,23 @@ static Atom s_wm_delete_window;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef struct SharedData {
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
float scale;
|
||||||
|
float mouse_x;
|
||||||
|
float mouse_y;
|
||||||
|
float scroll_x;
|
||||||
|
float scroll_y;
|
||||||
|
uint8_t state[3];
|
||||||
|
} SharedData;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
typedef struct WindowInfo {
|
typedef struct WindowInfo {
|
||||||
void (*key_callback)(void* user_data, int key, int state);
|
void (*key_callback)(void* user_data, int key, int state);
|
||||||
void* rust_data;
|
void* rust_data;
|
||||||
|
SharedData* shared_data;
|
||||||
Window window;
|
Window window;
|
||||||
XImage* ximage;
|
XImage* ximage;
|
||||||
void* draw_buffer;
|
void* draw_buffer;
|
||||||
|
@ -91,8 +108,6 @@ static int setup_display() {
|
||||||
|
|
||||||
s_setup_done = 1;
|
s_setup_done = 1;
|
||||||
|
|
||||||
printf("setup done\n");
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +154,7 @@ void* mfb_open(const char* title, int width, int height, int scale)
|
||||||
sizeHints.min_height = height;
|
sizeHints.min_height = height;
|
||||||
sizeHints.max_height = height;
|
sizeHints.max_height = height;
|
||||||
|
|
||||||
XSelectInput(s_display, window, KeyPressMask | KeyReleaseMask);
|
XSelectInput(s_display, window, ButtonPressMask | KeyPressMask | KeyReleaseMask | ButtonReleaseMask);
|
||||||
XSetWMNormalHints(s_display, window, &sizeHints);
|
XSetWMNormalHints(s_display, window, &sizeHints);
|
||||||
XClearWindow(s_display, window);
|
XClearWindow(s_display, window);
|
||||||
XMapRaised(s_display, window);
|
XMapRaised(s_display, window);
|
||||||
|
@ -207,13 +222,63 @@ static int process_event(XEvent* event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((event->type == KeyPress) || (event->type == KeyRelease) && info->key_callback) {
|
switch (event->type)
|
||||||
int sym = XLookupKeysym(&event->xkey, 0);
|
{
|
||||||
|
case KeyPress:
|
||||||
|
{
|
||||||
|
sym = XLookupKeysym(&event->xkey, 0);
|
||||||
|
|
||||||
if (event->type == KeyPress) {
|
if (info->key_callback)
|
||||||
info->key_callback(info->rust_data, sym, 1);
|
info->key_callback(info->rust_data, sym, 1);
|
||||||
} else if (event->type == KeyRelease) {
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KeyRelease:
|
||||||
|
{
|
||||||
|
sym = XLookupKeysym(&event->xkey, 0);
|
||||||
|
|
||||||
|
if (info->key_callback)
|
||||||
info->key_callback(info->rust_data, sym, 0);
|
info->key_callback(info->rust_data, sym, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ButtonPress:
|
||||||
|
{
|
||||||
|
if (!info->shared_data)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (event->xbutton.button == Button1)
|
||||||
|
info->shared_data->state[0] = 1;
|
||||||
|
else if (event->xbutton.button == Button2)
|
||||||
|
info->shared_data->state[1] = 1;
|
||||||
|
else if (event->xbutton.button == Button3)
|
||||||
|
info->shared_data->state[2] = 1;
|
||||||
|
else if (event->xbutton.button == Button4)
|
||||||
|
info->shared_data->scroll_y = 10.0f;
|
||||||
|
else if (event->xbutton.button == Button5)
|
||||||
|
info->shared_data->scroll_y = -10.0f;
|
||||||
|
else if (event->xbutton.button == Button6)
|
||||||
|
info->shared_data->scroll_x = 10.0f;
|
||||||
|
else if (event->xbutton.button == Button7)
|
||||||
|
info->shared_data->scroll_y = -10.0f;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ButtonRelease:
|
||||||
|
{
|
||||||
|
if (!info->shared_data)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (event->xbutton.button == Button1)
|
||||||
|
info->shared_data->state[0] = 0;
|
||||||
|
else if (event->xbutton.button == Button2)
|
||||||
|
info->shared_data->state[1] = 0;
|
||||||
|
else if (event->xbutton.button == Button3)
|
||||||
|
info->shared_data->state[2] = 0;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +287,24 @@ static int process_event(XEvent* event) {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static void get_mouse_pos(WindowInfo* info) {
|
||||||
|
Window root, child;
|
||||||
|
int rootX, rootY, childX, childY;
|
||||||
|
unsigned int mask;
|
||||||
|
|
||||||
|
XQueryPointer(s_display, info->window,
|
||||||
|
&root, &child,
|
||||||
|
&rootX, &rootY, &childX, &childY,
|
||||||
|
&mask);
|
||||||
|
|
||||||
|
if (info->shared_data) {
|
||||||
|
info->shared_data->mouse_x = (float)childX;
|
||||||
|
info->shared_data->mouse_y = (float)childY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static int process_events()
|
static int process_events()
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
|
@ -261,6 +344,8 @@ static void scale_2x(unsigned int* dest, unsigned int* source, int width, int he
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void scale_4x(unsigned int* dest, unsigned int* source, int width, int height, int scale) {
|
static void scale_4x(unsigned int* dest, unsigned int* source, int width, int height, int scale) {
|
||||||
int x, y;
|
int x, y;
|
||||||
for (y = 0; y < height; y += scale) {
|
for (y = 0; y < height; y += scale) {
|
||||||
|
@ -319,6 +404,14 @@ void mfb_update(void* window_info, void* buffer)
|
||||||
XFlush(s_display);
|
XFlush(s_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear before processing new events
|
||||||
|
|
||||||
|
if (info->shared_data) {
|
||||||
|
info->shared_data->scroll_x = 0.0f;
|
||||||
|
info->shared_data->scroll_y = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_mouse_pos(info);
|
||||||
process_events();
|
process_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,6 +455,16 @@ void mfb_set_key_callback(void* window, void* rust_data, void (*key_callback)(vo
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void mfb_set_shared_data(void* window, SharedData* data)
|
||||||
|
{
|
||||||
|
WindowInfo* win = (WindowInfo*)window;
|
||||||
|
win->shared_data = data;
|
||||||
|
win->shared_data->width = win->width;
|
||||||
|
win->shared_data->height = win->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int mfb_should_close(void* window) {
|
int mfb_should_close(void* window) {
|
||||||
WindowInfo* win = (WindowInfo*)window;
|
WindowInfo* win = (WindowInfo*)window;
|
||||||
return !!win->update;
|
return !!win->update;
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#![cfg(target_os = "macos")]
|
#![cfg(target_os = "macos")]
|
||||||
|
|
||||||
use {Scale, Key, KeyRepeat};
|
use {MouseButton, MouseMode, Scale, Key, KeyRepeat};
|
||||||
use key_handler::KeyHandler;
|
use key_handler::KeyHandler;
|
||||||
|
use mouse_handler;
|
||||||
|
|
||||||
use libc::{c_void, c_char, c_uchar};
|
use libc::{c_void, c_char, c_uchar};
|
||||||
use std::ffi::{CString};
|
use std::ffi::{CString};
|
||||||
|
@ -148,13 +149,29 @@ extern {
|
||||||
fn mfb_update(window: *mut c_void, buffer: *const c_uchar);
|
fn mfb_update(window: *mut c_void, buffer: *const c_uchar);
|
||||||
fn mfb_set_position(window: *mut c_void, x: i32, y: i32);
|
fn mfb_set_position(window: *mut c_void, x: i32, y: i32);
|
||||||
fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32));
|
fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32));
|
||||||
|
fn mfb_set_mouse_data(window_handle: *mut c_void, shared_data: *mut SharedData);
|
||||||
fn mfb_should_close(window: *mut c_void) -> i32;
|
fn mfb_should_close(window: *mut c_void) -> i32;
|
||||||
fn mfb_get_screen_size() -> u32;
|
fn mfb_get_screen_size() -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SharedData {
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
pub mouse_x: f32,
|
||||||
|
pub mouse_y: f32,
|
||||||
|
pub scroll_x: f32,
|
||||||
|
pub scroll_y: f32,
|
||||||
|
pub state: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
window_handle: *mut c_void,
|
window_handle: *mut c_void,
|
||||||
|
scale_factor: usize,
|
||||||
|
pub shared_data: SharedData,
|
||||||
key_handler: KeyHandler,
|
key_handler: KeyHandler,
|
||||||
|
pub has_set_data: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, state: i32) {
|
unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, state: i32) {
|
||||||
|
@ -180,7 +197,8 @@ impl Window {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let handle = mfb_open(n.as_ptr(), width as u32, height as u32, Self::get_scale_factor(width, height, scale));
|
let scale_factor = Self::get_scale_factor(width, height, scale) as usize;
|
||||||
|
let handle = mfb_open(n.as_ptr(), width as u32, height as u32, scale_factor as i32);
|
||||||
|
|
||||||
if handle == ptr::null_mut() {
|
if handle == ptr::null_mut() {
|
||||||
return Err("Unable to open Window");
|
return Err("Unable to open Window");
|
||||||
|
@ -188,16 +206,28 @@ impl Window {
|
||||||
|
|
||||||
Ok(Window {
|
Ok(Window {
|
||||||
window_handle: handle,
|
window_handle: handle,
|
||||||
|
scale_factor: scale_factor,
|
||||||
|
shared_data: SharedData {
|
||||||
|
width: width as u32 * scale_factor as u32,
|
||||||
|
height: height as u32 * scale_factor as u32,
|
||||||
|
.. SharedData::default()
|
||||||
|
},
|
||||||
key_handler: KeyHandler::new(),
|
key_handler: KeyHandler::new(),
|
||||||
|
has_set_data: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn set_mouse_data(&mut self) {
|
||||||
|
mfb_set_mouse_data(self.window_handle, &mut self.shared_data);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, buffer: &[u32]) {
|
pub fn update(&mut self, buffer: &[u32]) {
|
||||||
self.key_handler.update();
|
self.key_handler.update();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
mfb_update(self.window_handle, buffer.as_ptr() as *const u8);
|
mfb_update(self.window_handle, buffer.as_ptr() as *const u8);
|
||||||
|
Self::set_mouse_data(self);
|
||||||
mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
|
mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,6 +237,33 @@ impl Window {
|
||||||
unsafe { mfb_set_position(self.window_handle, x as i32, y as i32) }
|
unsafe { mfb_set_position(self.window_handle, x as i32, y as i32) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_scroll_wheel(&self) -> Option<(f32, f32)> {
|
||||||
|
let sx = self.shared_data.scroll_x;
|
||||||
|
let sy = self.shared_data.scroll_y;
|
||||||
|
|
||||||
|
if sx.abs() > 0.0001 || sy.abs() > 0.0001 {
|
||||||
|
Some((sx, sy))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mouse_down(&self, button: MouseButton) -> bool {
|
||||||
|
match button {
|
||||||
|
MouseButton::Left => self.shared_data.state[0] > 0,
|
||||||
|
MouseButton::Middle => self.shared_data.state[1] > 0,
|
||||||
|
MouseButton::Right => self.shared_data.state[2] > 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mouse_pos(&self, mode: MouseMode) -> Option<(f32, f32)> {
|
||||||
|
let s = self.scale_factor as f32;
|
||||||
|
let w = self.shared_data.width as f32;
|
||||||
|
let h = self.shared_data.height as f32;
|
||||||
|
|
||||||
|
mouse_handler::get_pos(mode, self.shared_data.mouse_x, self.shared_data.mouse_y, s, w, h)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_keys(&self) -> Option<Vec<Key>> {
|
pub fn get_keys(&self) -> Option<Vec<Key>> {
|
||||||
self.key_handler.get_keys()
|
self.key_handler.get_keys()
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
extern crate x11_dl;
|
extern crate x11_dl;
|
||||||
|
|
||||||
use {Scale, Key, KeyRepeat};
|
use {MouseMode, MouseButton, Scale, Key, KeyRepeat};
|
||||||
use key_handler::KeyHandler;
|
use key_handler::KeyHandler;
|
||||||
use self::x11_dl::keysym::*;
|
use self::x11_dl::keysym::*;
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ use libc::{c_void, c_char, c_uchar};
|
||||||
use std::ffi::{CString};
|
use std::ffi::{CString};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use mouse_handler;
|
||||||
|
|
||||||
#[link(name = "X11")]
|
#[link(name = "X11")]
|
||||||
extern {
|
extern {
|
||||||
|
@ -22,12 +23,27 @@ extern {
|
||||||
fn mfb_update(window: *mut c_void, buffer: *const c_uchar);
|
fn mfb_update(window: *mut c_void, buffer: *const c_uchar);
|
||||||
fn mfb_set_position(window: *mut c_void, x: i32, y: i32);
|
fn mfb_set_position(window: *mut c_void, x: i32, y: i32);
|
||||||
fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32));
|
fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32));
|
||||||
|
fn mfb_set_shared_data(window: *mut c_void, target: *mut SharedData);
|
||||||
fn mfb_should_close(window: *mut c_void) -> i32;
|
fn mfb_should_close(window: *mut c_void) -> i32;
|
||||||
fn mfb_get_screen_size() -> u32;
|
fn mfb_get_screen_size() -> u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct SharedData {
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
pub scale: f32,
|
||||||
|
pub mouse_x: f32,
|
||||||
|
pub mouse_y: f32,
|
||||||
|
pub scroll_x: f32,
|
||||||
|
pub scroll_y: f32,
|
||||||
|
pub state: [u8; 3],
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
window_handle: *mut c_void,
|
window_handle: *mut c_void,
|
||||||
|
shared_data: SharedData,
|
||||||
key_handler: KeyHandler,
|
key_handler: KeyHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,7 +170,8 @@ impl Window {
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let handle = mfb_open(n.as_ptr(), width as u32, height as u32, Self::get_scale_factor(width, height, scale));
|
let scale = Self::get_scale_factor(width, height, scale);
|
||||||
|
let handle = mfb_open(n.as_ptr(), width as u32, height as u32, scale);
|
||||||
|
|
||||||
if handle == ptr::null_mut() {
|
if handle == ptr::null_mut() {
|
||||||
return Err("Unable to open Window");
|
return Err("Unable to open Window");
|
||||||
|
@ -162,15 +179,24 @@ impl Window {
|
||||||
|
|
||||||
Ok(Window {
|
Ok(Window {
|
||||||
window_handle: handle,
|
window_handle: handle,
|
||||||
|
shared_data: SharedData {
|
||||||
|
scale: scale as f32,
|
||||||
|
.. SharedData::default()
|
||||||
|
},
|
||||||
key_handler: KeyHandler::new(),
|
key_handler: KeyHandler::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn set_shared_data(&mut self) {
|
||||||
|
mfb_set_shared_data(self.window_handle, &mut self.shared_data);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, buffer: &[u32]) {
|
pub fn update(&mut self, buffer: &[u32]) {
|
||||||
self.key_handler.update();
|
self.key_handler.update();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
Self::set_shared_data(self);
|
||||||
mfb_update(self.window_handle, buffer.as_ptr() as *const u8);
|
mfb_update(self.window_handle, buffer.as_ptr() as *const u8);
|
||||||
mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
|
mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback);
|
||||||
}
|
}
|
||||||
|
@ -181,6 +207,31 @@ impl Window {
|
||||||
unsafe { mfb_set_position(self.window_handle, x as i32, y as i32) }
|
unsafe { mfb_set_position(self.window_handle, x as i32, y as i32) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mouse_pos(&self, mode: MouseMode) -> Option<(f32, f32)> {
|
||||||
|
let s = self.shared_data.scale as f32;
|
||||||
|
let w = self.shared_data.width as f32;
|
||||||
|
let h = self.shared_data.height as f32;
|
||||||
|
|
||||||
|
mouse_handler::get_pos(mode, self.shared_data.mouse_x, self.shared_data.mouse_y, s, w, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mouse_down(&self, button: MouseButton) -> bool {
|
||||||
|
match button {
|
||||||
|
MouseButton::Left => self.shared_data.state[0] > 0,
|
||||||
|
MouseButton::Middle => self.shared_data.state[1] > 0,
|
||||||
|
MouseButton::Right => self.shared_data.state[2] > 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_scroll_wheel(&self) -> Option<(f32, f32)> {
|
||||||
|
if self.shared_data.scroll_x.abs() > 0.0 ||
|
||||||
|
self.shared_data.scroll_y.abs() > 0.0 {
|
||||||
|
Some((self.shared_data.scroll_x, self.shared_data.scroll_y))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_keys(&self) -> Option<Vec<Key>> {
|
pub fn get_keys(&self) -> Option<Vec<Key>> {
|
||||||
self.key_handler.get_keys()
|
self.key_handler.get_keys()
|
||||||
|
|
|
@ -6,7 +6,7 @@ extern crate winapi;
|
||||||
extern crate gdi32;
|
extern crate gdi32;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
use {Scale, Key, KeyRepeat};
|
use {Scale, Key, KeyRepeat, MouseButton, MouseMode};
|
||||||
|
|
||||||
use key_handler::KeyHandler;
|
use key_handler::KeyHandler;
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ use std::ptr;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use mouse_handler;
|
||||||
|
|
||||||
use self::winapi::windef::HWND;
|
use self::winapi::windef::HWND;
|
||||||
use self::winapi::windef::HDC;
|
use self::winapi::windef::HDC;
|
||||||
|
@ -171,11 +172,50 @@ unsafe extern "system" fn wnd_proc(window: winapi::HWND,
|
||||||
let mut wnd: &mut Window = mem::transmute(user_data);
|
let mut wnd: &mut Window = mem::transmute(user_data);
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
|
/*
|
||||||
|
winapi::winuser::WM_MOUSEMOVE => {
|
||||||
|
let mouse_coords = lparam as u32;
|
||||||
|
let scale = user_data.scale as f32;
|
||||||
|
user_data.mouse.local_x = (((mouse_coords >> 16) & 0xffff) as f32) / scale;
|
||||||
|
user_data.mouse.local_y = ((mouse_coords & 0xffff) as f32) / scale;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
winapi::winuser::WM_MOUSEWHEEL => {
|
||||||
|
let scroll = ((((wparam as u32) >> 16) & 0xffff) as i16) as f32 * 0.1;
|
||||||
|
wnd.mouse.scroll = scroll;
|
||||||
|
}
|
||||||
|
|
||||||
winapi::winuser::WM_KEYDOWN => {
|
winapi::winuser::WM_KEYDOWN => {
|
||||||
update_key_state(wnd, (lparam as u32) >> 16, true);
|
update_key_state(wnd, (lparam as u32) >> 16, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
winapi::winuser::WM_LBUTTONDOWN => {
|
||||||
|
wnd.mouse.state[0] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
winapi::winuser::WM_LBUTTONUP => {
|
||||||
|
wnd.mouse.state[0] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
winapi::winuser::WM_MBUTTONDOWN => {
|
||||||
|
wnd.mouse.state[1] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
winapi::winuser::WM_MBUTTONUP => {
|
||||||
|
wnd.mouse.state[1] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
winapi::winuser::WM_RBUTTONDOWN => {
|
||||||
|
wnd.mouse.state[2] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
winapi::winuser::WM_RBUTTONUP => {
|
||||||
|
wnd.mouse.state[2] = false
|
||||||
|
}
|
||||||
|
|
||||||
winapi::winuser::WM_CLOSE => {
|
winapi::winuser::WM_CLOSE => {
|
||||||
wnd.is_open = false;
|
wnd.is_open = false;
|
||||||
}
|
}
|
||||||
|
@ -233,7 +273,16 @@ fn to_wstring(str: &str) -> Vec<u16> {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct MouseData {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32,
|
||||||
|
pub state: [bool; 8],
|
||||||
|
pub scroll: f32,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
mouse: MouseData,
|
||||||
dc: Option<HDC>,
|
dc: Option<HDC>,
|
||||||
window: Option<HWND>,
|
window: Option<HWND>,
|
||||||
buffer: Vec<u32>,
|
buffer: Vec<u32>,
|
||||||
|
@ -328,6 +377,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
let window = Window {
|
let window = Window {
|
||||||
|
mouse: MouseData::default(),
|
||||||
dc: Some(user32::GetDC(handle.unwrap())),
|
dc: Some(user32::GetDC(handle.unwrap())),
|
||||||
window: Some(handle.unwrap()),
|
window: Some(handle.unwrap()),
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
|
@ -350,6 +400,31 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_mouse_pos(&self, mode: MouseMode) -> Option<(f32, f32)> {
|
||||||
|
let s = self.scale_factor as f32;
|
||||||
|
let w = self.width as f32;
|
||||||
|
let h = self.height as f32;
|
||||||
|
|
||||||
|
// TODO: Needs to be fixed with resize support
|
||||||
|
mouse_handler::get_pos(mode, self.mouse.x, self.mouse.y, s, w * s, h * s)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mouse_down(&self, button: MouseButton) -> bool {
|
||||||
|
match button {
|
||||||
|
MouseButton::Left => self.mouse.state[0],
|
||||||
|
MouseButton::Middle => self.mouse.state[1],
|
||||||
|
MouseButton::Right => self.mouse.state[2],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_scroll_wheel(&self) -> Option<(f32, f32)> {
|
||||||
|
if self.mouse.scroll.abs() > 0.0 {
|
||||||
|
Some((0.0, self.mouse.scroll))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_keys(&self) -> Option<Vec<Key>> {
|
pub fn get_keys(&self) -> Option<Vec<Key>> {
|
||||||
self.key_handler.get_keys()
|
self.key_handler.get_keys()
|
||||||
|
@ -391,6 +466,18 @@ impl Window {
|
||||||
let mut msg = mem::uninitialized();
|
let mut msg = mem::uninitialized();
|
||||||
let window = self.window.unwrap();
|
let window = self.window.unwrap();
|
||||||
|
|
||||||
|
let mut point: winapi::POINT = mem::uninitialized();
|
||||||
|
user32::GetCursorPos(&mut point);
|
||||||
|
user32::ScreenToClient(window, &mut point);
|
||||||
|
|
||||||
|
self.mouse.x = point.x as f32;
|
||||||
|
self.mouse.y = point.y as f32;
|
||||||
|
self.mouse.scroll = 0.0;
|
||||||
|
|
||||||
|
//self.mouse_data.x
|
||||||
|
|
||||||
|
//println!("{} {}", point.x, point.y);
|
||||||
|
|
||||||
self.key_handler.update();
|
self.key_handler.update();
|
||||||
|
|
||||||
// TODO: Optimize
|
// TODO: Optimize
|
||||||
|
|
Loading…
Reference in a new issue