godot_content_view.mm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  1. /**************************************************************************/
  2. /* godot_content_view.mm */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #import "godot_content_view.h"
  31. #import "display_server_macos.h"
  32. #import "key_mapping_macos.h"
  33. #include "main/main.h"
  34. @implementation GodotContentLayerDelegate
  35. - (id)init {
  36. self = [super init];
  37. window_id = DisplayServer::INVALID_WINDOW_ID;
  38. need_redraw = false;
  39. return self;
  40. }
  41. - (void)setWindowID:(DisplayServerMacOS::WindowID)wid {
  42. window_id = wid;
  43. }
  44. - (void)setNeedRedraw:(bool)redraw {
  45. need_redraw = redraw;
  46. }
  47. - (void)displayLayer:(CALayer *)layer {
  48. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  49. if (OS::get_singleton()->get_main_loop() && ds->get_is_resizing() && need_redraw) {
  50. Main::force_redraw();
  51. if (!Main::is_iterating()) { // Avoid cyclic loop.
  52. Main::iteration();
  53. }
  54. need_redraw = false;
  55. }
  56. }
  57. @end
  58. @implementation GodotContentView
  59. - (void)setFrameSize:(NSSize)newSize {
  60. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  61. if (ds && ds->has_window(window_id)) {
  62. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  63. NSRect frameRect = [wd.window_object frame];
  64. if (wd.fs_transition || wd.initial_size) {
  65. self.layerContentsPlacement = NSViewLayerContentsPlacementScaleAxesIndependently;
  66. wd.initial_size = false;
  67. } else {
  68. bool left = (wd.last_frame_rect.origin.x != frameRect.origin.x);
  69. bool bottom = (wd.last_frame_rect.origin.y != frameRect.origin.y);
  70. bool right = (wd.last_frame_rect.origin.x + wd.last_frame_rect.size.width != frameRect.origin.x + frameRect.size.width);
  71. bool top = (wd.last_frame_rect.origin.y + wd.last_frame_rect.size.height != frameRect.origin.y + frameRect.size.height);
  72. if (left && top) {
  73. self.layerContentsPlacement = NSViewLayerContentsPlacementBottomRight;
  74. } else if (left && bottom) {
  75. self.layerContentsPlacement = NSViewLayerContentsPlacementTopRight;
  76. } else if (left) {
  77. self.layerContentsPlacement = NSViewLayerContentsPlacementRight;
  78. } else if (right && top) {
  79. self.layerContentsPlacement = NSViewLayerContentsPlacementBottomLeft;
  80. } else if (right && bottom) {
  81. self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
  82. } else if (right) {
  83. self.layerContentsPlacement = NSViewLayerContentsPlacementLeft;
  84. }
  85. }
  86. wd.last_frame_rect = frameRect;
  87. }
  88. [super setFrameSize:newSize];
  89. [layer_delegate setNeedRedraw:true];
  90. [self.layer setNeedsDisplay]; // Force "drawRect" call.
  91. }
  92. - (void)updateLayerDelegate {
  93. self.layer.delegate = layer_delegate;
  94. self.layer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
  95. self.layer.needsDisplayOnBoundsChange = YES;
  96. }
  97. - (void)addObserver:(NSObject *)targetObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
  98. [registered_observers addObject:[[targetObserver description] stringByAppendingString:keyPath]];
  99. [super addObserver:targetObserver forKeyPath:keyPath options:options context:context];
  100. }
  101. - (void)removeObserver:(NSObject *)targetObserver forKeyPath:(NSString *)keyPath {
  102. if ([registered_observers containsObject:[[targetObserver description] stringByAppendingString:keyPath]]) {
  103. @try {
  104. [super removeObserver:targetObserver forKeyPath:keyPath];
  105. [registered_observers removeObject:[[targetObserver description] stringByAppendingString:keyPath]];
  106. } @catch (NSException *exception) {
  107. ERR_PRINT("NSException: " + String::utf8([exception reason].UTF8String));
  108. }
  109. }
  110. }
  111. - (id)init {
  112. self = [super init];
  113. layer_delegate = [[GodotContentLayerDelegate alloc] init];
  114. window_id = DisplayServer::INVALID_WINDOW_ID;
  115. tracking_area = nil;
  116. ime_input_event_in_progress = false;
  117. mouse_down_control = false;
  118. ignore_momentum_scroll = false;
  119. last_pen_inverted = false;
  120. registered_observers = [[NSMutableSet alloc] init];
  121. [self updateTrackingAreas];
  122. self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
  123. self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
  124. [self registerForDraggedTypes:[NSArray arrayWithObject:NSPasteboardTypeFileURL]];
  125. marked_text = [[NSMutableAttributedString alloc] init];
  126. return self;
  127. }
  128. - (void)setWindowID:(DisplayServerMacOS::WindowID)wid {
  129. window_id = wid;
  130. [layer_delegate setWindowID:window_id];
  131. }
  132. // MARK: Backing Layer
  133. - (CALayer *)makeBackingLayer {
  134. return [[CAMetalLayer class] layer];
  135. }
  136. - (BOOL)wantsUpdateLayer {
  137. return YES;
  138. }
  139. - (BOOL)isOpaque {
  140. return YES;
  141. }
  142. // MARK: IME
  143. - (BOOL)hasMarkedText {
  144. return (marked_text.length > 0);
  145. }
  146. - (NSRange)markedRange {
  147. return NSMakeRange(0, marked_text.length);
  148. }
  149. - (NSRange)selectedRange {
  150. static const NSRange kEmptyRange = { NSNotFound, 0 };
  151. return kEmptyRange;
  152. }
  153. - (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange {
  154. if ([aString isKindOfClass:[NSAttributedString class]]) {
  155. marked_text = [[NSMutableAttributedString alloc] initWithAttributedString:aString];
  156. } else {
  157. marked_text = [[NSMutableAttributedString alloc] initWithString:aString];
  158. }
  159. if (marked_text.length == 0) {
  160. [self unmarkText];
  161. return;
  162. }
  163. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  164. if (!ds || !ds->has_window(window_id)) {
  165. return;
  166. }
  167. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  168. if (wd.im_active) {
  169. ime_input_event_in_progress = true;
  170. ds->pop_last_key_event();
  171. ds->update_im_text(Point2i(selectedRange.location, selectedRange.length), String::utf8([[marked_text mutableString] UTF8String]));
  172. }
  173. }
  174. - (void)doCommandBySelector:(SEL)aSelector {
  175. [self tryToPerform:aSelector with:self];
  176. }
  177. - (void)unmarkText {
  178. if (ime_input_event_in_progress) {
  179. ime_suppress_next_keyup = true;
  180. }
  181. ime_input_event_in_progress = false;
  182. [[marked_text mutableString] setString:@""];
  183. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  184. if (!ds || !ds->has_window(window_id)) {
  185. return;
  186. }
  187. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  188. if (wd.im_active) {
  189. ds->update_im_text(Point2i(), String());
  190. }
  191. }
  192. - (NSArray *)validAttributesForMarkedText {
  193. return [NSArray array];
  194. }
  195. - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
  196. return nil;
  197. }
  198. - (NSUInteger)characterIndexForPoint:(NSPoint)aPoint {
  199. return 0;
  200. }
  201. - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange {
  202. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  203. if (!ds || !ds->has_window(window_id)) {
  204. return NSMakeRect(0, 0, 0, 0);
  205. }
  206. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  207. const NSRect content_rect = [wd.window_view frame];
  208. const float scale = ds->screen_get_max_scale();
  209. NSRect point_in_window_rect = NSMakeRect(wd.im_position.x / scale, content_rect.size.height - (wd.im_position.y / scale) - 1, 0, 0);
  210. NSPoint point_on_screen = [wd.window_object convertRectToScreen:point_in_window_rect].origin;
  211. return NSMakeRect(point_on_screen.x, point_on_screen.y, 0, 0);
  212. }
  213. - (void)cancelComposition {
  214. [self unmarkText];
  215. [[NSTextInputContext currentInputContext] discardMarkedText];
  216. }
  217. - (void)insertText:(id)aString {
  218. [self insertText:aString replacementRange:NSMakeRange(0, 0)];
  219. }
  220. - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
  221. NSString *characters;
  222. if ([aString isKindOfClass:[NSAttributedString class]]) {
  223. characters = [aString string];
  224. } else {
  225. characters = (NSString *)aString;
  226. }
  227. NSCharacterSet *ctrl_chars = [NSCharacterSet controlCharacterSet];
  228. NSCharacterSet *wsnl_chars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
  229. if ([characters rangeOfCharacterFromSet:ctrl_chars].length && [characters rangeOfCharacterFromSet:wsnl_chars].length == 0) {
  230. [[NSTextInputContext currentInputContext] discardMarkedText];
  231. [self cancelComposition];
  232. return;
  233. }
  234. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  235. if (!ds || !ds->has_window(window_id)) {
  236. [self cancelComposition];
  237. return;
  238. }
  239. Char16String text;
  240. text.resize([characters length] + 1);
  241. [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
  242. String u32text = String::utf16(text.ptr(), text.length());
  243. for (int i = 0; i < u32text.length(); i++) {
  244. const char32_t codepoint = u32text[i];
  245. if ((codepoint & 0xFF00) == 0xF700) {
  246. continue;
  247. }
  248. DisplayServerMacOS::KeyEvent ke;
  249. ke.window_id = window_id;
  250. ke.macos_state = 0;
  251. ke.pressed = true;
  252. ke.echo = false;
  253. ke.raw = false; // IME input event.
  254. ke.keycode = Key::NONE;
  255. ke.physical_keycode = Key::NONE;
  256. ke.key_label = Key::NONE;
  257. ke.unicode = fix_unicode(codepoint);
  258. ds->push_to_key_event_buffer(ke);
  259. }
  260. [self cancelComposition];
  261. }
  262. // MARK: Drag and drop
  263. - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
  264. return NSDragOperationCopy;
  265. }
  266. - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
  267. return NSDragOperationCopy;
  268. }
  269. - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
  270. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  271. if (!ds || !ds->has_window(window_id)) {
  272. return NO;
  273. }
  274. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  275. if (wd.drop_files_callback.is_valid()) {
  276. Vector<String> files;
  277. NSPasteboard *pboard = [sender draggingPasteboard];
  278. NSArray *items = pboard.pasteboardItems;
  279. for (NSPasteboardItem *item in items) {
  280. NSString *url = [item stringForType:NSPasteboardTypeFileURL];
  281. NSString *file = [NSURL URLWithString:url].path;
  282. files.push_back(String::utf8([file UTF8String]));
  283. }
  284. Variant v_files = files;
  285. const Variant *v_args[1] = { &v_files };
  286. Variant ret;
  287. Callable::CallError ce;
  288. wd.drop_files_callback.callp((const Variant **)&v_args, 1, ret, ce);
  289. if (ce.error != Callable::CallError::CALL_OK) {
  290. ERR_FAIL_V_MSG(NO, vformat("Failed to execute drop files callback: %s.", Variant::get_callable_error_text(wd.drop_files_callback, v_args, 1, ce)));
  291. }
  292. return YES;
  293. }
  294. return NO;
  295. }
  296. // MARK: Focus
  297. - (BOOL)canBecomeKeyView {
  298. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  299. if (!ds || !ds->has_window(window_id)) {
  300. return YES;
  301. }
  302. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  303. return !wd.no_focus;
  304. }
  305. - (BOOL)acceptsFirstResponder {
  306. return YES;
  307. }
  308. // MARK: Mouse
  309. - (void)cursorUpdate:(NSEvent *)event {
  310. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  311. if (!ds) {
  312. return;
  313. }
  314. ds->cursor_update_shape();
  315. }
  316. - (void)processMouseEvent:(NSEvent *)event index:(MouseButton)index pressed:(bool)pressed outofstream:(bool)outofstream {
  317. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  318. if (!ds || !ds->has_window(window_id)) {
  319. return;
  320. }
  321. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  322. Ref<InputEventMouseButton> mb;
  323. mb.instantiate();
  324. mb->set_window_id(window_id);
  325. if (outofstream) {
  326. ds->update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
  327. } else {
  328. ds->update_mouse_pos(wd, [event locationInWindow]);
  329. }
  330. ds->get_key_modifier_state([event modifierFlags], mb);
  331. mb->set_button_index(index);
  332. mb->set_pressed(pressed);
  333. mb->set_position(wd.mouse_pos);
  334. mb->set_global_position(wd.mouse_pos);
  335. mb->set_button_mask(ds->mouse_get_button_state());
  336. if (!outofstream && index == MouseButton::LEFT && pressed) {
  337. mb->set_double_click([event clickCount] == 2);
  338. }
  339. Input::get_singleton()->parse_input_event(mb);
  340. }
  341. - (void)mouseDown:(NSEvent *)event {
  342. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  343. if (ds && ds->has_window(window_id)) {
  344. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  345. wd.edge = DisplayServer::WINDOW_EDGE_MAX;
  346. }
  347. if (([event modifierFlags] & NSEventModifierFlagControl)) {
  348. mouse_down_control = true;
  349. [self processMouseEvent:event index:MouseButton::RIGHT pressed:true outofstream:false];
  350. } else {
  351. mouse_down_control = false;
  352. [self processMouseEvent:event index:MouseButton::LEFT pressed:true outofstream:false];
  353. }
  354. }
  355. - (void)mouseDragged:(NSEvent *)event {
  356. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  357. if (ds && ds->has_window(window_id)) {
  358. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  359. if (wd.edge != DisplayServer::WINDOW_EDGE_MAX) {
  360. Size2i max_size = wd.max_size / ds->screen_get_max_scale();
  361. Size2i min_size = wd.min_size / ds->screen_get_max_scale();
  362. NSRect frame = [wd.window_object frame];
  363. switch (wd.edge) {
  364. case DisplayServer::WINDOW_EDGE_TOP_LEFT: {
  365. int clamped_dx = CLAMP(frame.size.width - event.deltaX, min_size.x, max_size.x) - frame.size.width;
  366. int clamped_dy = CLAMP(frame.size.height - event.deltaY, min_size.y, max_size.y) - frame.size.height;
  367. [wd.window_object setFrame:NSMakeRect(frame.origin.x - clamped_dx, frame.origin.y, frame.size.width + clamped_dx, frame.size.height + clamped_dy) display:YES];
  368. } break;
  369. case DisplayServer::WINDOW_EDGE_TOP: {
  370. int clamped_dy = CLAMP(frame.size.height - event.deltaY, min_size.y, max_size.y) - frame.size.height;
  371. [wd.window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height + clamped_dy) display:YES];
  372. } break;
  373. case DisplayServer::WINDOW_EDGE_TOP_RIGHT: {
  374. int clamped_dx = CLAMP(frame.size.width + event.deltaX, min_size.x, max_size.x) - frame.size.width;
  375. int clamped_dy = CLAMP(frame.size.height - event.deltaY, min_size.y, max_size.y) - frame.size.height;
  376. [wd.window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width + clamped_dx, frame.size.height + clamped_dy) display:YES];
  377. } break;
  378. case DisplayServer::WINDOW_EDGE_LEFT: {
  379. int clamped_dx = CLAMP(frame.size.width - event.deltaX, min_size.x, max_size.x) - frame.size.width;
  380. [wd.window_object setFrame:NSMakeRect(frame.origin.x - clamped_dx, frame.origin.y, frame.size.width + clamped_dx, frame.size.height) display:YES];
  381. } break;
  382. case DisplayServer::WINDOW_EDGE_RIGHT: {
  383. int clamped_dx = CLAMP(frame.size.width + event.deltaX, min_size.x, max_size.x) - frame.size.width;
  384. [wd.window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width + clamped_dx, frame.size.height) display:YES];
  385. } break;
  386. case DisplayServer::WINDOW_EDGE_BOTTOM_LEFT: {
  387. int clamped_dx = CLAMP(frame.size.width - event.deltaX, min_size.x, max_size.x) - frame.size.width;
  388. int clamped_dy = CLAMP(frame.size.height + event.deltaY, min_size.y, max_size.y) - frame.size.height;
  389. [wd.window_object setFrame:NSMakeRect(frame.origin.x - clamped_dx, frame.origin.y - clamped_dy, frame.size.width + clamped_dx, frame.size.height + clamped_dy) display:YES];
  390. } break;
  391. case DisplayServer::WINDOW_EDGE_BOTTOM: {
  392. int clamped_dy = CLAMP(frame.size.height + event.deltaY, min_size.y, max_size.y) - frame.size.height;
  393. [wd.window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y - clamped_dy, frame.size.width, frame.size.height + clamped_dy) display:YES];
  394. } break;
  395. case DisplayServer::WINDOW_EDGE_BOTTOM_RIGHT: {
  396. int clamped_dx = CLAMP(frame.size.width + event.deltaX, min_size.x, max_size.x) - frame.size.width;
  397. int clamped_dy = CLAMP(frame.size.height + event.deltaY, min_size.y, max_size.y) - frame.size.height;
  398. [wd.window_object setFrame:NSMakeRect(frame.origin.x, frame.origin.y - clamped_dy, frame.size.width + clamped_dx, frame.size.height + clamped_dy) display:YES];
  399. } break;
  400. default:
  401. break;
  402. }
  403. return;
  404. }
  405. }
  406. [self mouseMoved:event];
  407. }
  408. - (void)mouseUp:(NSEvent *)event {
  409. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  410. if (ds && ds->has_window(window_id)) {
  411. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  412. wd.edge = DisplayServer::WINDOW_EDGE_MAX;
  413. }
  414. if (mouse_down_control) {
  415. [self processMouseEvent:event index:MouseButton::RIGHT pressed:false outofstream:false];
  416. } else {
  417. [self processMouseEvent:event index:MouseButton::LEFT pressed:false outofstream:false];
  418. }
  419. }
  420. - (void)mouseMoved:(NSEvent *)event {
  421. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  422. if (!ds || !ds->has_window(window_id)) {
  423. return;
  424. }
  425. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  426. NSPoint delta = NSMakePoint([event deltaX], [event deltaY]);
  427. NSPoint mpos = [event locationInWindow];
  428. if (ds->update_mouse_wrap(wd, delta, mpos, [event timestamp])) {
  429. return;
  430. }
  431. Ref<InputEventMouseMotion> mm;
  432. mm.instantiate();
  433. mm->set_window_id(window_id);
  434. mm->set_button_mask(ds->mouse_get_button_state());
  435. ds->update_mouse_pos(wd, mpos);
  436. mm->set_position(wd.mouse_pos);
  437. mm->set_pressure([event pressure]);
  438. NSEventSubtype subtype = [event subtype];
  439. if (subtype == NSEventSubtypeTabletPoint) {
  440. const NSPoint p = [event tilt];
  441. mm->set_tilt(Vector2(p.x, -p.y));
  442. mm->set_pen_inverted(last_pen_inverted);
  443. } else if (subtype == NSEventSubtypeTabletProximity) {
  444. // Check if using the eraser end of pen only on proximity event.
  445. last_pen_inverted = [event pointingDeviceType] == NSPointingDeviceTypeEraser;
  446. mm->set_pen_inverted(last_pen_inverted);
  447. }
  448. mm->set_global_position(wd.mouse_pos);
  449. mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
  450. mm->set_screen_velocity(mm->get_velocity());
  451. const Vector2i relativeMotion = Vector2i(delta.x, delta.y) * ds->screen_get_max_scale();
  452. mm->set_relative(relativeMotion);
  453. mm->set_relative_screen_position(relativeMotion);
  454. ds->get_key_modifier_state([event modifierFlags], mm);
  455. Input::get_singleton()->parse_input_event(mm);
  456. }
  457. - (void)rightMouseDown:(NSEvent *)event {
  458. [self processMouseEvent:event index:MouseButton::RIGHT pressed:true outofstream:false];
  459. }
  460. - (void)rightMouseDragged:(NSEvent *)event {
  461. [self mouseMoved:event];
  462. }
  463. - (void)rightMouseUp:(NSEvent *)event {
  464. [self processMouseEvent:event index:MouseButton::RIGHT pressed:false outofstream:false];
  465. }
  466. - (void)otherMouseDown:(NSEvent *)event {
  467. if ((int)[event buttonNumber] == 2) {
  468. [self processMouseEvent:event index:MouseButton::MIDDLE pressed:true outofstream:false];
  469. } else if ((int)[event buttonNumber] == 3) {
  470. [self processMouseEvent:event index:MouseButton::MB_XBUTTON1 pressed:true outofstream:false];
  471. } else if ((int)[event buttonNumber] == 4) {
  472. [self processMouseEvent:event index:MouseButton::MB_XBUTTON2 pressed:true outofstream:false];
  473. } else {
  474. return;
  475. }
  476. }
  477. - (void)otherMouseDragged:(NSEvent *)event {
  478. [self mouseMoved:event];
  479. }
  480. - (void)otherMouseUp:(NSEvent *)event {
  481. if ((int)[event buttonNumber] == 2) {
  482. [self processMouseEvent:event index:MouseButton::MIDDLE pressed:false outofstream:false];
  483. } else if ((int)[event buttonNumber] == 3) {
  484. [self processMouseEvent:event index:MouseButton::MB_XBUTTON1 pressed:false outofstream:false];
  485. } else if ((int)[event buttonNumber] == 4) {
  486. [self processMouseEvent:event index:MouseButton::MB_XBUTTON2 pressed:false outofstream:false];
  487. } else {
  488. return;
  489. }
  490. }
  491. - (void)swipeWithEvent:(NSEvent *)event {
  492. // Swipe gesture on Trackpad/Magic Mouse, or physical back/forward mouse buttons.
  493. if ([event phase] == NSEventPhaseEnded || [event phase] == NSEventPhaseChanged) {
  494. if (Math::is_equal_approx([event deltaX], 1.0)) {
  495. // Swipe left (back).
  496. [self processMouseEvent:event index:MouseButton::MB_XBUTTON1 pressed:true outofstream:true];
  497. [self processMouseEvent:event index:MouseButton::MB_XBUTTON1 pressed:false outofstream:true];
  498. } else if (Math::is_equal_approx([event deltaX], -1.0)) {
  499. // Swipe right (forward).
  500. [self processMouseEvent:event index:MouseButton::MB_XBUTTON2 pressed:true outofstream:true];
  501. [self processMouseEvent:event index:MouseButton::MB_XBUTTON2 pressed:false outofstream:true];
  502. }
  503. }
  504. }
  505. - (void)mouseExited:(NSEvent *)event {
  506. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  507. if (!ds || !ds->has_window(window_id)) {
  508. return;
  509. }
  510. if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_CAPTURED) {
  511. ds->mouse_exit_window(window_id);
  512. }
  513. }
  514. - (void)mouseEntered:(NSEvent *)event {
  515. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  516. if (!ds || !ds->has_window(window_id)) {
  517. return;
  518. }
  519. if (ds->mouse_get_mode() != DisplayServer::MOUSE_MODE_CAPTURED) {
  520. ds->mouse_enter_window(window_id);
  521. }
  522. ds->cursor_update_shape();
  523. }
  524. - (void)magnifyWithEvent:(NSEvent *)event {
  525. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  526. if (!ds || !ds->has_window(window_id)) {
  527. return;
  528. }
  529. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  530. Ref<InputEventMagnifyGesture> ev;
  531. ev.instantiate();
  532. ev->set_window_id(window_id);
  533. ds->get_key_modifier_state([event modifierFlags], ev);
  534. ds->update_mouse_pos(wd, [event locationInWindow]);
  535. ev->set_position(wd.mouse_pos);
  536. ev->set_factor([event magnification] + 1.0);
  537. Input::get_singleton()->parse_input_event(ev);
  538. }
  539. - (void)updateTrackingAreas {
  540. if (tracking_area != nil) {
  541. [self removeTrackingArea:tracking_area];
  542. }
  543. NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingActiveWhenFirstResponder | NSTrackingCursorUpdate | NSTrackingInVisibleRect;
  544. tracking_area = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil];
  545. [self addTrackingArea:tracking_area];
  546. [super updateTrackingAreas];
  547. }
  548. // MARK: Keyboard
  549. - (void)keyDown:(NSEvent *)event {
  550. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  551. if (!ds || !ds->has_window(window_id)) {
  552. return;
  553. }
  554. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  555. ignore_momentum_scroll = true;
  556. // Ignore all input if IME input is in progress.
  557. if (!ime_input_event_in_progress) {
  558. NSString *characters = [event characters];
  559. NSUInteger length = [characters length];
  560. if (!wd.im_active && length > 0 && keycode_has_unicode(KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true))) {
  561. // Fallback unicode character handler used if IME is not active.
  562. Char16String text;
  563. text.resize([characters length] + 1);
  564. [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
  565. String u32text = String::utf16(text.ptr(), text.length());
  566. DisplayServerMacOS::KeyEvent ke;
  567. ke.window_id = window_id;
  568. ke.macos_state = [event modifierFlags];
  569. ke.pressed = true;
  570. ke.echo = [event isARepeat];
  571. ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], false);
  572. ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
  573. ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
  574. ke.raw = true;
  575. if (u32text.is_empty()) {
  576. ke.unicode = 0;
  577. ds->push_to_key_event_buffer(ke);
  578. }
  579. for (int i = 0; i < u32text.length(); i++) {
  580. const char32_t codepoint = u32text[i];
  581. ke.unicode = fix_unicode(codepoint);
  582. ds->push_to_key_event_buffer(ke);
  583. }
  584. } else {
  585. DisplayServerMacOS::KeyEvent ke;
  586. ke.window_id = window_id;
  587. ke.macos_state = [event modifierFlags];
  588. ke.pressed = true;
  589. ke.echo = [event isARepeat];
  590. ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], false);
  591. ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
  592. ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
  593. ke.unicode = 0;
  594. ke.location = KeyMappingMacOS::translate_location([event keyCode]);
  595. ke.raw = false;
  596. ds->push_to_key_event_buffer(ke);
  597. }
  598. }
  599. // Pass events to IME handler
  600. if (wd.im_active) {
  601. [self interpretKeyEvents:[NSArray arrayWithObject:event]];
  602. }
  603. }
  604. - (void)flagsChanged:(NSEvent *)event {
  605. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  606. if (!ds || !ds->has_window(window_id)) {
  607. return;
  608. }
  609. ignore_momentum_scroll = true;
  610. DisplayServerMacOS::KeyEvent ke;
  611. ke.window_id = window_id;
  612. ke.echo = false;
  613. ke.raw = true;
  614. int key = [event keyCode];
  615. int mod = [event modifierFlags];
  616. if (key == 0x36 || key == 0x37) {
  617. if (mod & NSEventModifierFlagCommand) {
  618. mod &= ~NSEventModifierFlagCommand;
  619. ke.pressed = true;
  620. } else {
  621. ke.pressed = false;
  622. }
  623. } else if (key == 0x38 || key == 0x3c) {
  624. if (mod & NSEventModifierFlagShift) {
  625. mod &= ~NSEventModifierFlagShift;
  626. ke.pressed = true;
  627. } else {
  628. ke.pressed = false;
  629. }
  630. } else if (key == 0x3a || key == 0x3d) {
  631. if (mod & NSEventModifierFlagOption) {
  632. mod &= ~NSEventModifierFlagOption;
  633. ke.pressed = true;
  634. } else {
  635. ke.pressed = false;
  636. }
  637. } else if (key == 0x3b || key == 0x3e) {
  638. if (mod & NSEventModifierFlagControl) {
  639. mod &= ~NSEventModifierFlagControl;
  640. ke.pressed = true;
  641. } else {
  642. ke.pressed = false;
  643. }
  644. } else {
  645. return;
  646. }
  647. ke.macos_state = mod;
  648. ke.keycode = KeyMappingMacOS::remap_key(key, mod, false);
  649. ke.physical_keycode = KeyMappingMacOS::translate_key(key);
  650. ke.key_label = KeyMappingMacOS::remap_key(key, mod, true);
  651. ke.unicode = 0;
  652. ke.location = KeyMappingMacOS::translate_location(key);
  653. ds->push_to_key_event_buffer(ke);
  654. }
  655. - (void)keyUp:(NSEvent *)event {
  656. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  657. if (!ds || !ds->has_window(window_id)) {
  658. return;
  659. }
  660. // Ignore all input if IME input is in progress.
  661. if (ime_suppress_next_keyup) {
  662. ime_suppress_next_keyup = false;
  663. return;
  664. }
  665. if (!ime_input_event_in_progress) {
  666. DisplayServerMacOS::KeyEvent ke;
  667. ke.window_id = window_id;
  668. ke.macos_state = [event modifierFlags];
  669. ke.pressed = false;
  670. ke.echo = [event isARepeat];
  671. ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], false);
  672. ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
  673. ke.key_label = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags], true);
  674. ke.unicode = 0;
  675. ke.location = KeyMappingMacOS::translate_location([event keyCode]);
  676. ke.raw = true;
  677. ds->push_to_key_event_buffer(ke);
  678. }
  679. }
  680. // MARK: Scroll and pan
  681. - (void)processScrollEvent:(NSEvent *)event button:(MouseButton)button factor:(double)factor {
  682. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  683. if (!ds || !ds->has_window(window_id)) {
  684. return;
  685. }
  686. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  687. MouseButtonMask mask = mouse_button_to_mask(button);
  688. Ref<InputEventMouseButton> sc;
  689. sc.instantiate();
  690. sc->set_window_id(window_id);
  691. ds->get_key_modifier_state([event modifierFlags], sc);
  692. sc->set_button_index(button);
  693. sc->set_factor(factor);
  694. sc->set_pressed(true);
  695. sc->set_position(wd.mouse_pos);
  696. sc->set_global_position(wd.mouse_pos);
  697. BitField<MouseButtonMask> scroll_mask = ds->mouse_get_button_state();
  698. scroll_mask.set_flag(mask);
  699. sc->set_button_mask(scroll_mask);
  700. Input::get_singleton()->parse_input_event(sc);
  701. sc.instantiate();
  702. sc->set_window_id(window_id);
  703. sc->set_button_index(button);
  704. sc->set_factor(factor);
  705. sc->set_pressed(false);
  706. sc->set_position(wd.mouse_pos);
  707. sc->set_global_position(wd.mouse_pos);
  708. scroll_mask.clear_flag(mask);
  709. sc->set_button_mask(scroll_mask);
  710. Input::get_singleton()->parse_input_event(sc);
  711. }
  712. - (void)processPanEvent:(NSEvent *)event dx:(double)dx dy:(double)dy {
  713. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  714. if (!ds || !ds->has_window(window_id)) {
  715. return;
  716. }
  717. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  718. Ref<InputEventPanGesture> pg;
  719. pg.instantiate();
  720. pg->set_window_id(window_id);
  721. ds->get_key_modifier_state([event modifierFlags], pg);
  722. pg->set_position(wd.mouse_pos);
  723. pg->set_delta(Vector2(-dx, -dy));
  724. Input::get_singleton()->parse_input_event(pg);
  725. }
  726. - (void)scrollWheel:(NSEvent *)event {
  727. DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
  728. if (!ds || !ds->has_window(window_id)) {
  729. return;
  730. }
  731. DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
  732. ds->update_mouse_pos(wd, [event locationInWindow]);
  733. double delta_x = [event scrollingDeltaX];
  734. double delta_y = [event scrollingDeltaY];
  735. if ([event hasPreciseScrollingDeltas]) {
  736. delta_x *= 0.03;
  737. delta_y *= 0.03;
  738. }
  739. if ([event momentumPhase] != NSEventPhaseNone) {
  740. if (ignore_momentum_scroll) {
  741. return;
  742. }
  743. } else {
  744. ignore_momentum_scroll = false;
  745. }
  746. if ([event phase] != NSEventPhaseNone || [event momentumPhase] != NSEventPhaseNone) {
  747. [self processPanEvent:event dx:delta_x dy:delta_y];
  748. } else {
  749. if (std::abs(delta_x)) {
  750. [self processScrollEvent:event button:(0 > delta_x ? MouseButton::WHEEL_RIGHT : MouseButton::WHEEL_LEFT) factor:std::abs(delta_x * 0.3)];
  751. }
  752. if (std::abs(delta_y)) {
  753. [self processScrollEvent:event button:(0 < delta_y ? MouseButton::WHEEL_UP : MouseButton::WHEEL_DOWN) factor:std::abs(delta_y * 0.3)];
  754. }
  755. }
  756. }
  757. @end