2019-05-02 09:03:30 +10:00
use std ::{
2019-06-22 01:33:15 +10:00
boxed ::Box ,
collections ::VecDeque ,
os ::raw ::* ,
slice , str ,
2019-05-02 09:03:30 +10:00
sync ::{ Arc , Mutex , Weak } ,
} ;
use cocoa ::{
appkit ::{ NSApp , NSEvent , NSEventModifierFlags , NSEventPhase , NSView , NSWindow } ,
2019-06-22 01:33:15 +10:00
base ::{ id , nil } ,
foundation ::{ NSPoint , NSRect , NSSize , NSString , NSUInteger } ,
} ;
use objc ::{
declare ::ClassDecl ,
runtime ::{ Class , Object , Protocol , Sel , BOOL , NO , YES } ,
2019-05-02 09:03:30 +10:00
} ;
2019-06-18 04:27:00 +10:00
use crate ::{
2019-05-02 09:03:30 +10:00
event ::{
2019-06-22 01:33:15 +10:00
DeviceEvent , ElementState , Event , KeyboardInput , MouseButton , MouseScrollDelta , TouchPhase ,
VirtualKeyCode , WindowEvent ,
} ,
platform_impl ::platform ::{
app_state ::AppState ,
event ::{
char_to_keycode , check_function_keys , event_mods , get_scancode , modifier_event ,
scancode_to_keycode ,
} ,
ffi ::* ,
util ::{ self , IdRef } ,
window ::get_window_id ,
DEVICE_ID ,
2019-05-02 09:03:30 +10:00
} ,
window ::WindowId ,
} ;
#[ derive(Default) ]
struct Modifiers {
shift_pressed : bool ,
ctrl_pressed : bool ,
win_pressed : bool ,
alt_pressed : bool ,
}
2018-05-18 11:28:30 +10:00
struct ViewState {
2019-06-11 09:09:38 +10:00
ns_window : id ,
2019-05-02 09:03:30 +10:00
pub cursor : Arc < Mutex < util ::Cursor > > ,
2018-06-15 09:42:18 +10:00
ime_spot : Option < ( f64 , f64 ) > ,
2018-05-18 11:28:30 +10:00
raw_characters : Option < String > ,
2018-10-18 13:03:26 +11:00
is_key_down : bool ,
2019-05-02 09:03:30 +10:00
modifiers : Modifiers ,
2018-05-18 11:28:30 +10:00
}
2019-06-11 09:09:38 +10:00
pub fn new_view ( ns_window : id ) -> ( IdRef , Weak < Mutex < util ::Cursor > > ) {
2018-12-29 07:29:29 +11:00
let cursor = Default ::default ( ) ;
let cursor_access = Arc ::downgrade ( & cursor ) ;
2018-05-22 23:05:33 +10:00
let state = ViewState {
2019-06-11 09:09:38 +10:00
ns_window ,
2018-12-29 07:29:29 +11:00
cursor ,
2018-05-22 23:05:33 +10:00
ime_spot : None ,
raw_characters : None ,
2018-10-18 13:03:26 +11:00
is_key_down : false ,
2019-05-02 09:03:30 +10:00
modifiers : Default ::default ( ) ,
2018-05-22 23:05:33 +10:00
} ;
2018-05-18 11:28:30 +10:00
unsafe {
// This is free'd in `dealloc`
let state_ptr = Box ::into_raw ( Box ::new ( state ) ) as * mut c_void ;
2019-06-11 09:09:38 +10:00
let ns_view : id = msg_send! [ VIEW_CLASS . 0 , alloc ] ;
2019-06-22 01:33:15 +10:00
(
IdRef ::new ( msg_send! [ ns_view , initWithWinit : state_ptr ] ) ,
cursor_access ,
)
2018-05-18 11:28:30 +10:00
}
}
2019-06-11 09:09:38 +10:00
pub unsafe fn set_ime_position ( ns_view : id , input_context : id , x : f64 , y : f64 ) {
let state_ptr : * mut c_void = * ( * ns_view ) . get_mut_ivar ( " winitState " ) ;
2019-05-02 09:03:30 +10:00
let state = & mut * ( state_ptr as * mut ViewState ) ;
2019-06-22 01:33:15 +10:00
let content_rect =
NSWindow ::contentRectForFrameRect_ ( state . ns_window , NSWindow ::frame ( state . ns_window ) ) ;
2019-05-02 09:03:30 +10:00
let base_x = content_rect . origin . x as f64 ;
let base_y = ( content_rect . origin . y + content_rect . size . height ) as f64 ;
state . ime_spot = Some ( ( base_x + x , base_y - y ) ) ;
let _ : ( ) = msg_send! [ input_context , invalidateCharacterCoordinates ] ;
2018-05-18 11:28:30 +10:00
}
struct ViewClass ( * const Class ) ;
unsafe impl Send for ViewClass { }
unsafe impl Sync for ViewClass { }
lazy_static! {
static ref VIEW_CLASS : ViewClass = unsafe {
2018-07-20 02:02:33 +10:00
let superclass = class! ( NSView ) ;
2018-05-18 11:28:30 +10:00
let mut decl = ClassDecl ::new ( " WinitView " , superclass ) . unwrap ( ) ;
2019-06-22 01:33:15 +10:00
decl . add_method ( sel! ( dealloc ) , dealloc as extern " C " fn ( & Object , Sel ) ) ;
2018-05-18 11:28:30 +10:00
decl . add_method (
sel! ( initWithWinit :) ,
2019-06-22 01:33:15 +10:00
init_with_winit as extern " C " fn ( & Object , Sel , * mut c_void ) -> id ,
2018-05-18 11:28:30 +10:00
) ;
2019-05-02 09:03:30 +10:00
decl . add_method (
sel! ( viewDidMoveToWindow ) ,
2019-06-22 01:33:15 +10:00
view_did_move_to_window as extern " C " fn ( & Object , Sel ) ,
2019-05-02 09:03:30 +10:00
) ;
2018-12-28 07:16:58 +11:00
decl . add_method (
sel! ( drawRect :) ,
2019-08-14 14:01:22 +10:00
draw_rect as extern " C " fn ( & Object , Sel , NSRect ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( acceptsFirstResponder ) ,
2019-06-22 01:33:15 +10:00
accepts_first_responder as extern " C " fn ( & Object , Sel ) -> BOOL ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( touchBar ) ,
2019-06-22 01:33:15 +10:00
touch_bar as extern " C " fn ( & Object , Sel ) -> BOOL ,
2018-12-28 07:16:58 +11:00
) ;
2018-12-29 07:29:29 +11:00
decl . add_method (
sel! ( resetCursorRects ) ,
2019-06-22 01:33:15 +10:00
reset_cursor_rects as extern " C " fn ( & Object , Sel ) ,
2018-12-29 07:29:29 +11:00
) ;
2019-05-02 09:03:30 +10:00
decl . add_method (
sel! ( hasMarkedText ) ,
2019-06-22 01:33:15 +10:00
has_marked_text as extern " C " fn ( & Object , Sel ) -> BOOL ,
2019-05-02 09:03:30 +10:00
) ;
2018-05-18 11:28:30 +10:00
decl . add_method (
sel! ( markedRange ) ,
2019-06-22 01:33:15 +10:00
marked_range as extern " C " fn ( & Object , Sel ) -> NSRange ,
2018-05-18 11:28:30 +10:00
) ;
2019-05-02 09:03:30 +10:00
decl . add_method (
sel! ( selectedRange ) ,
2019-06-22 01:33:15 +10:00
selected_range as extern " C " fn ( & Object , Sel ) -> NSRange ,
2019-05-02 09:03:30 +10:00
) ;
2018-05-18 11:28:30 +10:00
decl . add_method (
sel! ( setMarkedText :selectedRange :replacementRange :) ,
2019-06-22 01:33:15 +10:00
set_marked_text as extern " C " fn ( & mut Object , Sel , id , NSRange , NSRange ) ,
2019-05-02 09:03:30 +10:00
) ;
2019-06-22 01:33:15 +10:00
decl . add_method ( sel! ( unmarkText ) , unmark_text as extern " C " fn ( & Object , Sel ) ) ;
2018-05-18 11:28:30 +10:00
decl . add_method (
sel! ( validAttributesForMarkedText ) ,
2019-06-22 01:33:15 +10:00
valid_attributes_for_marked_text as extern " C " fn ( & Object , Sel ) -> id ,
2018-05-18 11:28:30 +10:00
) ;
decl . add_method (
sel! ( attributedSubstringForProposedRange :actualRange :) ,
2019-06-22 01:33:15 +10:00
attributed_substring_for_proposed_range
as extern " C " fn ( & Object , Sel , NSRange , * mut c_void ) -> id ,
2018-05-18 11:28:30 +10:00
) ;
decl . add_method (
sel! ( insertText :replacementRange :) ,
2019-06-22 01:33:15 +10:00
insert_text as extern " C " fn ( & Object , Sel , id , NSRange ) ,
2018-05-18 11:28:30 +10:00
) ;
decl . add_method (
sel! ( characterIndexForPoint :) ,
2019-06-22 01:33:15 +10:00
character_index_for_point as extern " C " fn ( & Object , Sel , NSPoint ) -> NSUInteger ,
2018-05-18 11:28:30 +10:00
) ;
decl . add_method (
sel! ( firstRectForCharacterRange :actualRange :) ,
2019-06-22 01:33:15 +10:00
first_rect_for_character_range
as extern " C " fn ( & Object , Sel , NSRange , * mut c_void ) -> NSRect ,
2018-05-18 11:28:30 +10:00
) ;
decl . add_method (
sel! ( doCommandBySelector :) ,
2019-06-22 01:33:15 +10:00
do_command_by_selector as extern " C " fn ( & Object , Sel , Sel ) ,
2019-05-02 09:03:30 +10:00
) ;
2019-06-22 01:33:15 +10:00
decl . add_method ( sel! ( keyDown :) , key_down as extern " C " fn ( & Object , Sel , id ) ) ;
decl . add_method ( sel! ( keyUp :) , key_up as extern " C " fn ( & Object , Sel , id ) ) ;
2019-05-02 09:03:30 +10:00
decl . add_method (
sel! ( flagsChanged :) ,
2019-06-22 01:33:15 +10:00
flags_changed as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( insertTab :) ,
2019-06-22 01:33:15 +10:00
insert_tab as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( insertBackTab :) ,
2019-06-22 01:33:15 +10:00
insert_back_tab as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( mouseDown :) ,
2019-06-22 01:33:15 +10:00
mouse_down as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
2019-06-22 01:33:15 +10:00
decl . add_method ( sel! ( mouseUp :) , mouse_up as extern " C " fn ( & Object , Sel , id ) ) ;
2019-05-02 09:03:30 +10:00
decl . add_method (
sel! ( rightMouseDown :) ,
2019-06-22 01:33:15 +10:00
right_mouse_down as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( rightMouseUp :) ,
2019-06-22 01:33:15 +10:00
right_mouse_up as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( otherMouseDown :) ,
2019-06-22 01:33:15 +10:00
other_mouse_down as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( otherMouseUp :) ,
2019-06-22 01:33:15 +10:00
other_mouse_up as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( mouseMoved :) ,
2019-06-22 01:33:15 +10:00
mouse_moved as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( mouseDragged :) ,
2019-06-22 01:33:15 +10:00
mouse_dragged as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( rightMouseDragged :) ,
2019-06-22 01:33:15 +10:00
right_mouse_dragged as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( otherMouseDragged :) ,
2019-06-22 01:33:15 +10:00
other_mouse_dragged as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( mouseEntered :) ,
2019-06-22 01:33:15 +10:00
mouse_entered as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( mouseExited :) ,
2019-06-22 01:33:15 +10:00
mouse_exited as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( scrollWheel :) ,
2019-06-22 01:33:15 +10:00
scroll_wheel as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( pressureChangeWithEvent :) ,
2019-06-22 01:33:15 +10:00
pressure_change_with_event as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( _wantsKeyDownForEvent :) ,
2019-06-22 01:33:15 +10:00
wants_key_down_for_event as extern " C " fn ( & Object , Sel , id ) -> BOOL ,
2019-05-02 09:03:30 +10:00
) ;
decl . add_method (
sel! ( cancelOperation :) ,
2019-06-22 01:33:15 +10:00
cancel_operation as extern " C " fn ( & Object , Sel , id ) ,
2019-05-02 09:03:30 +10:00
) ;
2018-05-18 11:28:30 +10:00
decl . add_ivar ::< * mut c_void > ( " winitState " ) ;
decl . add_ivar ::< id > ( " markedText " ) ;
let protocol = Protocol ::get ( " NSTextInputClient " ) . unwrap ( ) ;
decl . add_protocol ( & protocol ) ;
ViewClass ( decl . register ( ) )
} ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn dealloc ( this : & Object , _sel : Sel ) {
2018-05-18 11:28:30 +10:00
unsafe {
let state : * mut c_void = * this . get_ivar ( " winitState " ) ;
let marked_text : id = * this . get_ivar ( " markedText " ) ;
let _ : ( ) = msg_send! [ marked_text , release ] ;
Box ::from_raw ( state as * mut ViewState ) ;
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn init_with_winit ( this : & Object , _sel : Sel , state : * mut c_void ) -> id {
2018-05-18 11:28:30 +10:00
unsafe {
let this : id = msg_send! [ this , init ] ;
if this ! = nil {
( * this ) . set_ivar ( " winitState " , state ) ;
2019-06-22 01:33:15 +10:00
let marked_text =
< id as NSMutableAttributedString > ::init ( NSMutableAttributedString ::alloc ( nil ) ) ;
2018-05-18 11:28:30 +10:00
( * this ) . set_ivar ( " markedText " , marked_text ) ;
}
this
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn view_did_move_to_window ( this : & Object , _sel : Sel ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `viewDidMoveToWindow` " ) ;
unsafe {
let rect : NSRect = msg_send! [ this , visibleRect ] ;
let _ : ( ) = msg_send! [ this ,
addTrackingRect :rect
owner :this
userData :nil
assumeInside :NO
] ;
}
trace! ( " Completed `viewDidMoveToWindow` " ) ;
}
2019-08-14 14:01:22 +10:00
extern " C " fn draw_rect ( this : & Object , _sel : Sel , rect : NSRect ) {
2018-12-28 07:16:58 +11:00
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
2019-06-11 09:09:38 +10:00
AppState ::queue_redraw ( WindowId ( get_window_id ( state . ns_window ) ) ) ;
2018-12-28 07:16:58 +11:00
let superclass = util ::superclass ( this ) ;
2019-06-22 01:33:15 +10:00
let ( ) = msg_send! [ super ( this , superclass ) , drawRect : rect ] ;
2018-12-28 07:16:58 +11:00
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn accepts_first_responder ( _this : & Object , _sel : Sel ) -> BOOL {
2019-05-02 09:03:30 +10:00
YES
}
// This is necessary to prevent a beefy terminal error on MacBook Pros:
// IMKInputSession [0x7fc573576ff0 presentFunctionRowItemTextInputViewWithEndpoint:completionHandler:] : [self textInputContext]=0x7fc573558e10 *NO* NSRemoteViewController to client, NSError=Error Domain=NSCocoaErrorDomain Code=4099 "The connection from pid 0 was invalidated from this process." UserInfo={NSDebugDescription=The connection from pid 0 was invalidated from this process.}, com.apple.inputmethod.EmojiFunctionRowItem
// TODO: Add an API extension for using `NSTouchBar`
2019-06-22 01:33:15 +10:00
extern " C " fn touch_bar ( _this : & Object , _sel : Sel ) -> BOOL {
2019-05-02 09:03:30 +10:00
NO
}
2019-06-22 01:33:15 +10:00
extern " C " fn reset_cursor_rects ( this : & Object , _sel : Sel ) {
2018-12-29 07:29:29 +11:00
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let bounds : NSRect = msg_send! [ this , bounds ] ;
let cursor = state . cursor . lock ( ) . unwrap ( ) . load ( ) ;
let _ : ( ) = msg_send! [ this ,
addCursorRect :bounds
cursor :cursor
] ;
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn has_marked_text ( this : & Object , _sel : Sel ) -> BOOL {
2018-05-18 11:28:30 +10:00
unsafe {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `hasMarkedText` " ) ;
2018-05-18 11:28:30 +10:00
let marked_text : id = * this . get_ivar ( " markedText " ) ;
2019-05-02 09:03:30 +10:00
trace! ( " Completed `hasMarkedText` " ) ;
2018-05-18 11:28:30 +10:00
( marked_text . length ( ) > 0 ) as i8
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn marked_range ( this : & Object , _sel : Sel ) -> NSRange {
2018-05-18 11:28:30 +10:00
unsafe {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `markedRange` " ) ;
2018-05-18 11:28:30 +10:00
let marked_text : id = * this . get_ivar ( " markedText " ) ;
let length = marked_text . length ( ) ;
2019-05-02 09:03:30 +10:00
trace! ( " Completed `markedRange` " ) ;
2018-05-18 11:28:30 +10:00
if length > 0 {
NSRange ::new ( 0 , length - 1 )
} else {
util ::EMPTY_RANGE
}
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn selected_range ( _this : & Object , _sel : Sel ) -> NSRange {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `selectedRange` " ) ;
trace! ( " Completed `selectedRange` " ) ;
2018-05-18 11:28:30 +10:00
util ::EMPTY_RANGE
}
2019-06-22 01:33:15 +10:00
extern " C " fn set_marked_text (
2018-05-18 11:28:30 +10:00
this : & mut Object ,
_sel : Sel ,
string : id ,
_selected_range : NSRange ,
_replacement_range : NSRange ,
) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `setMarkedText` " ) ;
2018-05-18 11:28:30 +10:00
unsafe {
let marked_text_ref : & mut id = this . get_mut_ivar ( " markedText " ) ;
let _ : ( ) = msg_send! [ ( * marked_text_ref ) , release ] ;
let marked_text = NSMutableAttributedString ::alloc ( nil ) ;
2019-06-22 01:33:15 +10:00
let has_attr = msg_send! [ string , isKindOfClass : class ! ( NSAttributedString ) ] ;
2018-05-18 11:28:30 +10:00
if has_attr {
marked_text . initWithAttributedString ( string ) ;
} else {
marked_text . initWithString ( string ) ;
} ;
* marked_text_ref = marked_text ;
}
2019-05-02 09:03:30 +10:00
trace! ( " Completed `setMarkedText` " ) ;
2018-05-18 11:28:30 +10:00
}
2019-06-22 01:33:15 +10:00
extern " C " fn unmark_text ( this : & Object , _sel : Sel ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `unmarkText` " ) ;
2018-05-18 11:28:30 +10:00
unsafe {
let marked_text : id = * this . get_ivar ( " markedText " ) ;
let mutable_string = marked_text . mutableString ( ) ;
let _ : ( ) = msg_send! [ mutable_string , setString :" " ] ;
let input_context : id = msg_send! [ this , inputContext ] ;
let _ : ( ) = msg_send! [ input_context , discardMarkedText ] ;
}
2019-05-02 09:03:30 +10:00
trace! ( " Completed `unmarkText` " ) ;
2018-05-18 11:28:30 +10:00
}
2019-06-22 01:33:15 +10:00
extern " C " fn valid_attributes_for_marked_text ( _this : & Object , _sel : Sel ) -> id {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `validAttributesForMarkedText` " ) ;
trace! ( " Completed `validAttributesForMarkedText` " ) ;
2018-07-20 02:02:33 +10:00
unsafe { msg_send! [ class! ( NSArray ) , array ] }
2018-05-18 11:28:30 +10:00
}
2019-06-22 01:33:15 +10:00
extern " C " fn attributed_substring_for_proposed_range (
2018-05-18 11:28:30 +10:00
_this : & Object ,
_sel : Sel ,
_range : NSRange ,
_actual_range : * mut c_void , // *mut NSRange
) -> id {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `attributedSubstringForProposedRange` " ) ;
trace! ( " Completed `attributedSubstringForProposedRange` " ) ;
2018-05-18 11:28:30 +10:00
nil
}
2019-06-22 01:33:15 +10:00
extern " C " fn character_index_for_point ( _this : & Object , _sel : Sel , _point : NSPoint ) -> NSUInteger {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `characterIndexForPoint` " ) ;
trace! ( " Completed `characterIndexForPoint` " ) ;
2018-05-18 11:28:30 +10:00
0
}
2019-06-22 01:33:15 +10:00
extern " C " fn first_rect_for_character_range (
2018-05-18 11:28:30 +10:00
this : & Object ,
_sel : Sel ,
_range : NSRange ,
_actual_range : * mut c_void , // *mut NSRange
) -> NSRect {
unsafe {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `firstRectForCharacterRange` " ) ;
2018-05-18 11:28:30 +10:00
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let ( x , y ) = state . ime_spot . unwrap_or_else ( | | {
let content_rect = NSWindow ::contentRectForFrameRect_ (
2019-06-11 09:09:38 +10:00
state . ns_window ,
NSWindow ::frame ( state . ns_window ) ,
2018-05-18 11:28:30 +10:00
) ;
let x = content_rect . origin . x ;
let y = util ::bottom_left_to_top_left ( content_rect ) ;
2018-06-15 09:42:18 +10:00
( x , y )
2018-05-18 11:28:30 +10:00
} ) ;
2019-05-02 09:03:30 +10:00
trace! ( " Completed `firstRectForCharacterRange` " ) ;
2019-06-22 01:33:15 +10:00
NSRect ::new ( NSPoint ::new ( x as _ , y as _ ) , NSSize ::new ( 0.0 , 0.0 ) )
2018-05-18 11:28:30 +10:00
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn insert_text ( this : & Object , _sel : Sel , string : id , _replacement_range : NSRange ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `insertText` " ) ;
2018-05-18 11:28:30 +10:00
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
2019-06-22 01:33:15 +10:00
let has_attr = msg_send! [ string , isKindOfClass : class ! ( NSAttributedString ) ] ;
2018-05-18 11:28:30 +10:00
let characters = if has_attr {
// This is a *mut NSAttributedString
msg_send! [ string , string ]
} else {
// This is already a *mut NSString
string
} ;
2019-06-22 01:33:15 +10:00
let slice =
slice ::from_raw_parts ( characters . UTF8String ( ) as * const c_uchar , characters . len ( ) ) ;
2018-05-18 11:28:30 +10:00
let string = str ::from_utf8_unchecked ( slice ) ;
2018-10-18 13:03:26 +11:00
state . is_key_down = true ;
2018-05-18 11:28:30 +10:00
// We don't need this now, but it's here if that changes.
2019-05-02 09:03:30 +10:00
//let event: id = msg_send![NSApp(), currentEvent];
2018-05-18 11:28:30 +10:00
let mut events = VecDeque ::with_capacity ( characters . len ( ) ) ;
2019-11-27 20:14:36 +11:00
for character in string . chars ( ) . filter ( | c | ! is_corporate_character ( * c ) ) {
2018-05-18 11:28:30 +10:00
events . push_back ( Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2018-05-18 11:28:30 +10:00
event : WindowEvent ::ReceivedCharacter ( character ) ,
} ) ;
}
2019-05-02 09:03:30 +10:00
AppState ::queue_events ( events ) ;
2018-05-18 11:28:30 +10:00
}
2019-05-02 09:03:30 +10:00
trace! ( " Completed `insertText` " ) ;
2018-05-18 11:28:30 +10:00
}
2019-06-22 01:33:15 +10:00
extern " C " fn do_command_by_selector ( this : & Object , _sel : Sel , command : Sel ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `doCommandBySelector` " ) ;
2018-05-18 11:28:30 +10:00
// Basically, we're sent this message whenever a keyboard event that doesn't generate a "human readable" character
// happens, i.e. newlines, tabs, and Ctrl+C.
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let mut events = VecDeque ::with_capacity ( 1 ) ;
if command = = sel! ( insertNewline :) {
// The `else` condition would emit the same character, but I'm keeping this here both...
// 1) as a reminder for how `doCommandBySelector` works
2018-05-22 23:05:33 +10:00
// 2) to make our use of carriage return explicit
2018-05-18 11:28:30 +10:00
events . push_back ( Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2018-05-22 23:05:33 +10:00
event : WindowEvent ::ReceivedCharacter ( '\r' ) ,
2018-05-18 11:28:30 +10:00
} ) ;
} else {
let raw_characters = state . raw_characters . take ( ) ;
if let Some ( raw_characters ) = raw_characters {
2019-11-27 20:14:36 +11:00
for character in raw_characters
. chars ( )
. filter ( | c | ! is_corporate_character ( * c ) )
{
2018-05-18 11:28:30 +10:00
events . push_back ( Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2018-05-18 11:28:30 +10:00
event : WindowEvent ::ReceivedCharacter ( character ) ,
} ) ;
}
}
} ;
2019-05-02 09:03:30 +10:00
AppState ::queue_events ( events ) ;
2018-05-18 11:28:30 +10:00
}
2019-05-02 09:03:30 +10:00
trace! ( " Completed `doCommandBySelector` " ) ;
2018-05-18 11:28:30 +10:00
}
2019-02-24 07:41:55 +11:00
fn get_characters ( event : id , ignore_modifiers : bool ) -> String {
2018-09-13 03:04:16 +10:00
unsafe {
2019-02-24 07:41:55 +11:00
let characters : id = if ignore_modifiers {
msg_send! [ event , charactersIgnoringModifiers ]
} else {
msg_send! [ event , characters ]
} ;
assert_ne! ( characters , nil ) ;
2019-06-22 01:33:15 +10:00
let slice =
slice ::from_raw_parts ( characters . UTF8String ( ) as * const c_uchar , characters . len ( ) ) ;
2019-02-24 07:41:55 +11:00
2018-09-13 03:04:16 +10:00
let string = str ::from_utf8_unchecked ( slice ) ;
2019-02-24 07:41:55 +11:00
string . to_owned ( )
}
}
2019-11-27 20:14:36 +11:00
// As defined in: https://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT
fn is_corporate_character ( c : char ) -> bool {
match c {
'\u{F700}' ..= '\u{F747}'
| '\u{F802}' ..= '\u{F84F}'
| '\u{F850}'
| '\u{F85C}'
| '\u{F85D}'
| '\u{F85F}'
| '\u{F860}' ..= '\u{F86B}'
| '\u{F870}' ..= '\u{F8FF}' = > true ,
_ = > false ,
}
}
2019-02-24 07:41:55 +11:00
// Retrieves a layout-independent keycode given an event.
2019-05-02 09:03:30 +10:00
fn retrieve_keycode ( event : id ) -> Option < VirtualKeyCode > {
2019-02-24 07:41:55 +11:00
#[ inline ]
2019-05-02 09:03:30 +10:00
fn get_code ( ev : id , raw : bool ) -> Option < VirtualKeyCode > {
2019-02-24 07:41:55 +11:00
let characters = get_characters ( ev , raw ) ;
2019-10-24 10:45:25 +11:00
characters . chars ( ) . next ( ) . and_then ( | c | char_to_keycode ( c ) )
2018-09-13 03:04:16 +10:00
}
2019-02-24 07:41:55 +11:00
// Cmd switches Roman letters for Dvorak-QWERTY layout, so we try modified characters first.
// If we don't get a match, then we fall back to unmodified characters.
2019-06-22 01:33:15 +10:00
let code = get_code ( event , false ) . or_else ( | | get_code ( event , true ) ) ;
2019-02-24 07:41:55 +11:00
// We've checked all layout related keys, so fall through to scancode.
// Reaching this code means that the key is layout-independent (e.g. Backspace, Return).
//
// We're additionally checking here for F21-F24 keys, since their keycode
// can vary, but we know that they are encoded
// in characters property.
code . or_else ( | | {
let scancode = get_scancode ( event ) ;
2019-06-22 01:33:15 +10:00
scancode_to_keycode ( scancode ) . or_else ( | | check_function_keys ( & get_characters ( event , true ) ) )
2019-02-24 07:41:55 +11:00
} )
2018-09-13 03:04:16 +10:00
}
2019-06-22 01:33:15 +10:00
extern " C " fn key_down ( this : & Object , _sel : Sel , event : id ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `keyDown` " ) ;
2018-05-18 11:28:30 +10:00
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
2019-06-11 09:09:38 +10:00
let window_id = WindowId ( get_window_id ( state . ns_window ) ) ;
2019-02-24 07:41:55 +11:00
let characters = get_characters ( event , false ) ;
2018-05-18 11:28:30 +10:00
2019-02-24 07:41:55 +11:00
state . raw_characters = Some ( characters . clone ( ) ) ;
2018-09-13 03:04:16 +10:00
2019-02-24 07:41:55 +11:00
let scancode = get_scancode ( event ) as u32 ;
let virtual_keycode = retrieve_keycode ( event ) ;
2019-05-02 09:03:30 +10:00
2018-05-22 23:05:33 +10:00
let is_repeat = msg_send! [ event , isARepeat ] ;
2018-05-18 11:28:30 +10:00
let window_event = Event ::WindowEvent {
2018-05-22 23:05:33 +10:00
window_id ,
2018-05-18 11:28:30 +10:00
event : WindowEvent ::KeyboardInput {
device_id : DEVICE_ID ,
input : KeyboardInput {
state : ElementState ::Pressed ,
scancode ,
virtual_keycode ,
modifiers : event_mods ( event ) ,
} ,
2019-12-08 09:51:37 +11:00
is_synthetic : false ,
2018-05-18 11:28:30 +10:00
} ,
} ;
2019-05-02 09:03:30 +10:00
let pass_along = {
AppState ::queue_event ( window_event ) ;
2018-05-22 23:05:33 +10:00
// Emit `ReceivedCharacter` for key repeats
2019-05-02 09:03:30 +10:00
if is_repeat & & state . is_key_down {
2019-11-27 20:14:36 +11:00
for character in characters . chars ( ) . filter ( | c | ! is_corporate_character ( * c ) ) {
2019-05-02 09:03:30 +10:00
AppState ::queue_event ( Event ::WindowEvent {
2018-05-22 23:05:33 +10:00
window_id ,
event : WindowEvent ::ReceivedCharacter ( character ) ,
2019-05-02 09:03:30 +10:00
} ) ;
2018-05-22 23:05:33 +10:00
}
2019-05-02 09:03:30 +10:00
false
2018-06-18 05:08:26 +10:00
} else {
2019-05-02 09:03:30 +10:00
true
2018-05-22 23:05:33 +10:00
}
2019-05-02 09:03:30 +10:00
} ;
if pass_along {
// Some keys (and only *some*, with no known reason) don't trigger `insertText`, while others do...
// So, we don't give repeats the opportunity to trigger that, since otherwise our hack will cause some
// keys to generate twice as many characters.
2019-06-22 01:33:15 +10:00
let array : id = msg_send! [ class! ( NSArray ) , arrayWithObject : event ] ;
let _ : ( ) = msg_send! [ this , interpretKeyEvents : array ] ;
2018-05-18 11:28:30 +10:00
}
}
2019-05-02 09:03:30 +10:00
trace! ( " Completed `keyDown` " ) ;
2018-05-18 11:28:30 +10:00
}
2019-06-22 01:33:15 +10:00
extern " C " fn key_up ( this : & Object , _sel : Sel , event : id ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `keyUp` " ) ;
2018-05-18 11:28:30 +10:00
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
2018-10-18 13:03:26 +11:00
state . is_key_down = false ;
2018-05-22 23:05:33 +10:00
2019-02-24 07:41:55 +11:00
let scancode = get_scancode ( event ) as u32 ;
let virtual_keycode = retrieve_keycode ( event ) ;
2018-09-13 03:04:16 +10:00
2018-05-18 11:28:30 +10:00
let window_event = Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2018-05-18 11:28:30 +10:00
event : WindowEvent ::KeyboardInput {
device_id : DEVICE_ID ,
input : KeyboardInput {
state : ElementState ::Released ,
scancode ,
virtual_keycode ,
modifiers : event_mods ( event ) ,
} ,
2019-12-08 09:51:37 +11:00
is_synthetic : false ,
2018-05-18 11:28:30 +10:00
} ,
} ;
2019-05-02 09:03:30 +10:00
AppState ::queue_event ( window_event ) ;
}
trace! ( " Completed `keyUp` " ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn flags_changed ( this : & Object , _sel : Sel , event : id ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `flagsChanged` " ) ;
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let mut events = VecDeque ::with_capacity ( 4 ) ;
if let Some ( window_event ) = modifier_event (
event ,
NSEventModifierFlags ::NSShiftKeyMask ,
state . modifiers . shift_pressed ,
) {
state . modifiers . shift_pressed = ! state . modifiers . shift_pressed ;
events . push_back ( window_event ) ;
}
if let Some ( window_event ) = modifier_event (
event ,
NSEventModifierFlags ::NSControlKeyMask ,
state . modifiers . ctrl_pressed ,
) {
state . modifiers . ctrl_pressed = ! state . modifiers . ctrl_pressed ;
events . push_back ( window_event ) ;
}
if let Some ( window_event ) = modifier_event (
event ,
NSEventModifierFlags ::NSCommandKeyMask ,
state . modifiers . win_pressed ,
) {
state . modifiers . win_pressed = ! state . modifiers . win_pressed ;
events . push_back ( window_event ) ;
}
if let Some ( window_event ) = modifier_event (
event ,
NSEventModifierFlags ::NSAlternateKeyMask ,
state . modifiers . alt_pressed ,
) {
state . modifiers . alt_pressed = ! state . modifiers . alt_pressed ;
events . push_back ( window_event ) ;
}
for event in events {
AppState ::queue_event ( Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2019-05-02 09:03:30 +10:00
event ,
} ) ;
2018-05-18 11:28:30 +10:00
}
}
2019-05-02 09:03:30 +10:00
trace! ( " Completed `flagsChanged` " ) ;
2018-05-18 11:28:30 +10:00
}
2019-06-22 01:33:15 +10:00
extern " C " fn insert_tab ( this : & Object , _sel : Sel , _sender : id ) {
2018-05-18 11:28:30 +10:00
unsafe {
let window : id = msg_send! [ this , window ] ;
let first_responder : id = msg_send! [ window , firstResponder ] ;
let this_ptr = this as * const _ as * mut _ ;
if first_responder = = this_ptr {
2019-06-22 01:33:15 +10:00
let ( ) : _ = msg_send! [ window , selectNextKeyView : this ] ;
2018-05-18 11:28:30 +10:00
}
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn insert_back_tab ( this : & Object , _sel : Sel , _sender : id ) {
2018-05-18 11:28:30 +10:00
unsafe {
let window : id = msg_send! [ this , window ] ;
let first_responder : id = msg_send! [ window , firstResponder ] ;
let this_ptr = this as * const _ as * mut _ ;
if first_responder = = this_ptr {
2019-06-22 01:33:15 +10:00
let ( ) : _ = msg_send! [ window , selectPreviousKeyView : this ] ;
2018-05-18 11:28:30 +10:00
}
}
}
2018-06-12 01:16:39 +10:00
2019-05-02 09:03:30 +10:00
// Allows us to receive Cmd-. (the shortcut for closing a dialog)
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=300620#c6
2019-06-22 01:33:15 +10:00
extern " C " fn cancel_operation ( this : & Object , _sel : Sel , _sender : id ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `cancelOperation` " ) ;
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let scancode = 0x2f ;
let virtual_keycode = scancode_to_keycode ( scancode ) ;
debug_assert_eq! ( virtual_keycode , Some ( VirtualKeyCode ::Period ) ) ;
let event : id = msg_send! [ NSApp ( ) , currentEvent ] ;
let window_event = Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2019-05-02 09:03:30 +10:00
event : WindowEvent ::KeyboardInput {
device_id : DEVICE_ID ,
input : KeyboardInput {
state : ElementState ::Pressed ,
scancode : scancode as _ ,
virtual_keycode ,
modifiers : event_mods ( event ) ,
} ,
2019-12-08 09:51:37 +11:00
is_synthetic : false ,
2019-05-02 09:03:30 +10:00
} ,
} ;
AppState ::queue_event ( window_event ) ;
}
trace! ( " Completed `cancelOperation` " ) ;
}
2018-06-12 01:16:39 +10:00
fn mouse_click ( this : & Object , event : id , button : MouseButton , button_state : ElementState ) {
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let window_event = Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2018-06-12 01:16:39 +10:00
event : WindowEvent ::MouseInput {
device_id : DEVICE_ID ,
state : button_state ,
button ,
modifiers : event_mods ( event ) ,
} ,
} ;
2019-05-02 09:03:30 +10:00
AppState ::queue_event ( window_event ) ;
2018-06-12 01:16:39 +10:00
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn mouse_down ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_click ( this , event , MouseButton ::Left , ElementState ::Pressed ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn mouse_up ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_click ( this , event , MouseButton ::Left , ElementState ::Released ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn right_mouse_down ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_click ( this , event , MouseButton ::Right , ElementState ::Pressed ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn right_mouse_up ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_click ( this , event , MouseButton ::Right , ElementState ::Released ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn other_mouse_down ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_click ( this , event , MouseButton ::Middle , ElementState ::Pressed ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn other_mouse_up ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_click ( this , event , MouseButton ::Middle , ElementState ::Released ) ;
}
fn mouse_motion ( this : & Object , event : id ) {
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
// We have to do this to have access to the `NSView` trait...
let view : id = this as * const _ as * mut _ ;
let window_point = event . locationInWindow ( ) ;
let view_point = view . convertPoint_fromView_ ( window_point , nil ) ;
let view_rect = NSView ::frame ( view ) ;
if view_point . x . is_sign_negative ( )
2019-06-22 01:33:15 +10:00
| | view_point . y . is_sign_negative ( )
| | view_point . x > view_rect . size . width
| | view_point . y > view_rect . size . height
{
2018-06-12 01:16:39 +10:00
// Point is outside of the client area (view)
return ;
}
2018-06-15 09:42:18 +10:00
let x = view_point . x as f64 ;
let y = view_rect . size . height as f64 - view_point . y as f64 ;
2018-06-12 01:16:39 +10:00
let window_event = Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2018-06-12 01:16:39 +10:00
event : WindowEvent ::CursorMoved {
device_id : DEVICE_ID ,
2018-06-15 09:42:18 +10:00
position : ( x , y ) . into ( ) ,
2018-06-12 01:16:39 +10:00
modifiers : event_mods ( event ) ,
} ,
} ;
2019-05-02 09:03:30 +10:00
AppState ::queue_event ( window_event ) ;
2018-06-12 01:16:39 +10:00
}
}
2019-06-22 01:33:15 +10:00
extern " C " fn mouse_moved ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_motion ( this , event ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn mouse_dragged ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_motion ( this , event ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn right_mouse_dragged ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_motion ( this , event ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn other_mouse_dragged ( this : & Object , _sel : Sel , event : id ) {
2018-06-12 01:16:39 +10:00
mouse_motion ( this , event ) ;
}
2018-08-16 09:42:57 +10:00
2019-06-22 01:33:15 +10:00
extern " C " fn mouse_entered ( this : & Object , _sel : Sel , event : id ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `mouseEntered` " ) ;
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let enter_event = Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2019-06-22 01:33:15 +10:00
event : WindowEvent ::CursorEntered {
device_id : DEVICE_ID ,
} ,
2019-05-02 09:03:30 +10:00
} ;
let move_event = {
let window_point = event . locationInWindow ( ) ;
let view_point : NSPoint = msg_send! [ this ,
convertPoint :window_point
fromView :nil // convert from window coordinates
] ;
let view_rect : NSRect = msg_send! [ this , frame ] ;
let x = view_point . x as f64 ;
let y = ( view_rect . size . height - view_point . y ) as f64 ;
Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2019-05-02 09:03:30 +10:00
event : WindowEvent ::CursorMoved {
device_id : DEVICE_ID ,
position : ( x , y ) . into ( ) ,
modifiers : event_mods ( event ) ,
2019-06-22 01:33:15 +10:00
} ,
2019-05-02 09:03:30 +10:00
}
} ;
AppState ::queue_event ( enter_event ) ;
AppState ::queue_event ( move_event ) ;
}
trace! ( " Completed `mouseEntered` " ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn mouse_exited ( this : & Object , _sel : Sel , _event : id ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `mouseExited` " ) ;
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let window_event = Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2019-06-22 01:33:15 +10:00
event : WindowEvent ::CursorLeft {
device_id : DEVICE_ID ,
} ,
2019-05-02 09:03:30 +10:00
} ;
AppState ::queue_event ( window_event ) ;
}
trace! ( " Completed `mouseExited` " ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn scroll_wheel ( this : & Object , _sel : Sel , event : id ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `scrollWheel` " ) ;
unsafe {
let delta = {
let ( x , y ) = ( event . scrollingDeltaX ( ) , event . scrollingDeltaY ( ) ) ;
if event . hasPreciseScrollingDeltas ( ) = = YES {
MouseScrollDelta ::PixelDelta ( ( x as f64 , y as f64 ) . into ( ) )
} else {
MouseScrollDelta ::LineDelta ( x as f32 , y as f32 )
}
} ;
let phase = match event . phase ( ) {
2019-06-22 01:33:15 +10:00
NSEventPhase ::NSEventPhaseMayBegin | NSEventPhase ::NSEventPhaseBegan = > {
TouchPhase ::Started
2019-06-25 02:14:55 +10:00
}
2019-05-02 09:03:30 +10:00
NSEventPhase ::NSEventPhaseEnded = > TouchPhase ::Ended ,
_ = > TouchPhase ::Moved ,
} ;
let device_event = Event ::DeviceEvent {
device_id : DEVICE_ID ,
event : DeviceEvent ::MouseWheel { delta } ,
} ;
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let window_event = Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2019-05-02 09:03:30 +10:00
event : WindowEvent ::MouseWheel {
device_id : DEVICE_ID ,
delta ,
phase ,
modifiers : event_mods ( event ) ,
} ,
} ;
AppState ::queue_event ( device_event ) ;
AppState ::queue_event ( window_event ) ;
}
trace! ( " Completed `scrollWheel` " ) ;
}
2019-06-22 01:33:15 +10:00
extern " C " fn pressure_change_with_event ( this : & Object , _sel : Sel , event : id ) {
2019-05-02 09:03:30 +10:00
trace! ( " Triggered `pressureChangeWithEvent` " ) ;
unsafe {
let state_ptr : * mut c_void = * this . get_ivar ( " winitState " ) ;
let state = & mut * ( state_ptr as * mut ViewState ) ;
let pressure = event . pressure ( ) ;
let stage = event . stage ( ) ;
let window_event = Event ::WindowEvent {
2019-06-11 09:09:38 +10:00
window_id : WindowId ( get_window_id ( state . ns_window ) ) ,
2019-05-02 09:03:30 +10:00
event : WindowEvent ::TouchpadPressure {
device_id : DEVICE_ID ,
pressure ,
stage ,
} ,
} ;
AppState ::queue_event ( window_event ) ;
}
trace! ( " Completed `pressureChangeWithEvent` " ) ;
}
// Allows us to receive Ctrl-Tab and Ctrl-Esc.
// Note that this *doesn't* help with any missing Cmd inputs.
2018-08-16 09:42:57 +10:00
// https://github.com/chromium/chromium/blob/a86a8a6bcfa438fa3ac2eba6f02b3ad1f8e0756f/ui/views/cocoa/bridged_content_view.mm#L816
2019-06-22 01:33:15 +10:00
extern " C " fn wants_key_down_for_event ( _this : & Object , _sel : Sel , _event : id ) -> BOOL {
2018-08-16 09:42:57 +10:00
YES
}