haiku_direct_window.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*************************************************************************/
  2. /* haiku_direct_window.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
  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. #include <UnicodeChar.h>
  31. #include "haiku_direct_window.h"
  32. #include "key_mapping_haiku.h"
  33. #include "main/main.h"
  34. #include "os/keyboard.h"
  35. HaikuDirectWindow::HaikuDirectWindow(BRect p_frame)
  36. : BDirectWindow(p_frame, "Godot", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE) {
  37. last_mouse_pos_valid = false;
  38. last_buttons_state = 0;
  39. last_button_mask = 0;
  40. last_key_modifier_state = 0;
  41. }
  42. HaikuDirectWindow::~HaikuDirectWindow() {
  43. delete update_runner;
  44. }
  45. void HaikuDirectWindow::SetHaikuGLView(HaikuGLView *p_view) {
  46. view = p_view;
  47. }
  48. void HaikuDirectWindow::StartMessageRunner() {
  49. update_runner = new BMessageRunner(BMessenger(this),
  50. new BMessage(REDRAW_MSG), 1000000 / 30 /* 30 fps */);
  51. }
  52. void HaikuDirectWindow::StopMessageRunner() {
  53. delete update_runner;
  54. }
  55. void HaikuDirectWindow::SetInput(InputDefault *p_input) {
  56. input = p_input;
  57. }
  58. void HaikuDirectWindow::SetMainLoop(MainLoop *p_main_loop) {
  59. main_loop = p_main_loop;
  60. }
  61. bool HaikuDirectWindow::QuitRequested() {
  62. main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
  63. return false;
  64. }
  65. void HaikuDirectWindow::DirectConnected(direct_buffer_info *info) {
  66. view->DirectConnected(info);
  67. view->EnableDirectMode(true);
  68. }
  69. void HaikuDirectWindow::MessageReceived(BMessage *message) {
  70. switch (message->what) {
  71. case REDRAW_MSG:
  72. if (Main::iteration() == true) {
  73. view->EnableDirectMode(false);
  74. Quit();
  75. }
  76. break;
  77. default:
  78. BDirectWindow::MessageReceived(message);
  79. }
  80. }
  81. void HaikuDirectWindow::DispatchMessage(BMessage *message, BHandler *handler) {
  82. switch (message->what) {
  83. case B_MOUSE_DOWN:
  84. case B_MOUSE_UP:
  85. HandleMouseButton(message);
  86. break;
  87. case B_MOUSE_MOVED:
  88. HandleMouseMoved(message);
  89. break;
  90. case B_MOUSE_WHEEL_CHANGED:
  91. HandleMouseWheelChanged(message);
  92. break;
  93. case B_KEY_DOWN:
  94. case B_KEY_UP:
  95. HandleKeyboardEvent(message);
  96. break;
  97. case B_MODIFIERS_CHANGED:
  98. HandleKeyboardModifierEvent(message);
  99. break;
  100. case B_WINDOW_RESIZED:
  101. HandleWindowResized(message);
  102. break;
  103. case LOCKGL_MSG:
  104. view->LockGL();
  105. break;
  106. case UNLOCKGL_MSG:
  107. view->UnlockGL();
  108. break;
  109. default:
  110. BDirectWindow::DispatchMessage(message, handler);
  111. }
  112. }
  113. void HaikuDirectWindow::HandleMouseButton(BMessage *message) {
  114. BPoint where;
  115. if (message->FindPoint("where", &where) != B_OK) {
  116. return;
  117. }
  118. uint32 modifiers = message->FindInt32("modifiers");
  119. uint32 buttons = message->FindInt32("buttons");
  120. uint32 button = buttons ^ last_buttons_state;
  121. last_buttons_state = buttons;
  122. // TODO: implement the mouse_mode checks
  123. /*
  124. if (mouse_mode == MOUSE_MODE_CAPTURED) {
  125. event.xbutton.x=last_mouse_pos.x;
  126. event.xbutton.y=last_mouse_pos.y;
  127. }
  128. */
  129. InputEvent mouse_event;
  130. mouse_event.type = InputEvent::MOUSE_BUTTON;
  131. mouse_event.device = 0;
  132. mouse_event.mouse_button.mod = GetKeyModifierState(modifiers);
  133. mouse_event.mouse_button.button_mask = GetMouseButtonState(buttons);
  134. mouse_event.mouse_button.x = where.x;
  135. mouse_event.mouse_button.y = where.y;
  136. mouse_event.mouse_button.global_x = where.x;
  137. mouse_event.mouse_button.global_y = where.y;
  138. switch (button) {
  139. default:
  140. case B_PRIMARY_MOUSE_BUTTON:
  141. mouse_event.mouse_button.button_index = 1;
  142. break;
  143. case B_SECONDARY_MOUSE_BUTTON:
  144. mouse_event.mouse_button.button_index = 2;
  145. break;
  146. case B_TERTIARY_MOUSE_BUTTON:
  147. mouse_event.mouse_button.button_index = 3;
  148. break;
  149. }
  150. mouse_event.mouse_button.pressed = (message->what == B_MOUSE_DOWN);
  151. if (message->what == B_MOUSE_DOWN && mouse_event.mouse_button.button_index == 1) {
  152. int32 clicks = message->FindInt32("clicks");
  153. if (clicks > 1) {
  154. mouse_event.mouse_button.doubleclick = true;
  155. }
  156. }
  157. input->parse_input_event(mouse_event);
  158. }
  159. void HaikuDirectWindow::HandleMouseMoved(BMessage *message) {
  160. BPoint where;
  161. if (message->FindPoint("where", &where) != B_OK) {
  162. return;
  163. }
  164. Point2i pos(where.x, where.y);
  165. uint32 modifiers = message->FindInt32("modifiers");
  166. uint32 buttons = message->FindInt32("buttons");
  167. if (!last_mouse_pos_valid) {
  168. last_mouse_position = pos;
  169. last_mouse_pos_valid = true;
  170. }
  171. Point2i rel = pos - last_mouse_position;
  172. InputEvent motion_event;
  173. motion_event.type = InputEvent::MOUSE_MOTION;
  174. motion_event.device = 0;
  175. motion_event.mouse_motion.mod = GetKeyModifierState(modifiers);
  176. motion_event.mouse_motion.button_mask = GetMouseButtonState(buttons);
  177. motion_event.mouse_motion.x = pos.x;
  178. motion_event.mouse_motion.y = pos.y;
  179. input->set_mouse_position(pos);
  180. motion_event.mouse_motion.global_x = pos.x;
  181. motion_event.mouse_motion.global_y = pos.y;
  182. motion_event.mouse_motion.speed_x = input->get_last_mouse_speed().x;
  183. motion_event.mouse_motion.speed_y = input->get_last_mouse_speed().y;
  184. motion_event.mouse_motion.relative_x = rel.x;
  185. motion_event.mouse_motion.relative_y = rel.y;
  186. last_mouse_position = pos;
  187. input->parse_input_event(motion_event);
  188. }
  189. void HaikuDirectWindow::HandleMouseWheelChanged(BMessage *message) {
  190. float wheel_delta_y = 0;
  191. if (message->FindFloat("be:wheel_delta_y", &wheel_delta_y) != B_OK) {
  192. return;
  193. }
  194. InputEvent mouse_event;
  195. mouse_event.type = InputEvent::MOUSE_BUTTON;
  196. mouse_event.device = 0;
  197. mouse_event.mouse_button.button_index = wheel_delta_y < 0 ? 4 : 5;
  198. mouse_event.mouse_button.mod = GetKeyModifierState(last_key_modifier_state);
  199. mouse_event.mouse_button.button_mask = last_button_mask;
  200. mouse_event.mouse_button.x = last_mouse_position.x;
  201. mouse_event.mouse_button.y = last_mouse_position.y;
  202. mouse_event.mouse_button.global_x = last_mouse_position.x;
  203. mouse_event.mouse_button.global_y = last_mouse_position.y;
  204. mouse_event.mouse_button.pressed = true;
  205. input->parse_input_event(mouse_event);
  206. mouse_event.mouse_button.pressed = false;
  207. input->parse_input_event(mouse_event);
  208. }
  209. void HaikuDirectWindow::HandleKeyboardEvent(BMessage *message) {
  210. int32 raw_char = 0;
  211. int32 key = 0;
  212. int32 modifiers = 0;
  213. if (message->FindInt32("raw_char", &raw_char) != B_OK) {
  214. return;
  215. }
  216. if (message->FindInt32("key", &key) != B_OK) {
  217. return;
  218. }
  219. if (message->FindInt32("modifiers", &modifiers) != B_OK) {
  220. return;
  221. }
  222. InputEvent event;
  223. event.type = InputEvent::KEY;
  224. event.device = 0;
  225. event.key.mod = GetKeyModifierState(modifiers);
  226. event.key.pressed = (message->what == B_KEY_DOWN);
  227. event.key.scancode = KeyMappingHaiku::get_keysym(raw_char, key);
  228. event.key.echo = message->HasInt32("be:key_repeat");
  229. event.key.unicode = 0;
  230. const char *bytes = NULL;
  231. if (message->FindString("bytes", &bytes) == B_OK) {
  232. event.key.unicode = BUnicodeChar::FromUTF8(&bytes);
  233. }
  234. //make it consistent across platforms.
  235. if (event.key.scancode == KEY_BACKTAB) {
  236. event.key.scancode = KEY_TAB;
  237. event.key.mod.shift = true;
  238. }
  239. input->parse_input_event(event);
  240. }
  241. void HaikuDirectWindow::HandleKeyboardModifierEvent(BMessage *message) {
  242. int32 old_modifiers = 0;
  243. int32 modifiers = 0;
  244. if (message->FindInt32("be:old_modifiers", &old_modifiers) != B_OK) {
  245. return;
  246. }
  247. if (message->FindInt32("modifiers", &modifiers) != B_OK) {
  248. return;
  249. }
  250. int32 key = old_modifiers ^ modifiers;
  251. InputEvent event;
  252. event.type = InputEvent::KEY;
  253. event.device = 0;
  254. event.key.mod = GetKeyModifierState(modifiers);
  255. event.key.pressed = ((modifiers & key) != 0);
  256. event.key.scancode = KeyMappingHaiku::get_modifier_keysym(key);
  257. event.key.echo = false;
  258. event.key.unicode = 0;
  259. input->parse_input_event(event);
  260. }
  261. void HaikuDirectWindow::HandleWindowResized(BMessage *message) {
  262. int32 width = 0;
  263. int32 height = 0;
  264. if ((message->FindInt32("width", &width) != B_OK) || (message->FindInt32("height", &height) != B_OK)) {
  265. return;
  266. }
  267. current_video_mode->width = width;
  268. current_video_mode->height = height;
  269. }
  270. inline InputModifierState HaikuDirectWindow::GetKeyModifierState(uint32 p_state) {
  271. last_key_modifier_state = p_state;
  272. InputModifierState state;
  273. state.shift = (p_state & B_SHIFT_KEY) != 0;
  274. state.control = (p_state & B_CONTROL_KEY) != 0;
  275. state.alt = (p_state & B_OPTION_KEY) != 0;
  276. state.meta = (p_state & B_COMMAND_KEY) != 0;
  277. return state;
  278. }
  279. inline int HaikuDirectWindow::GetMouseButtonState(uint32 p_state) {
  280. int state = 0;
  281. if (p_state & B_PRIMARY_MOUSE_BUTTON) {
  282. state |= 1 << 0;
  283. }
  284. if (p_state & B_SECONDARY_MOUSE_BUTTON) {
  285. state |= 1 << 1;
  286. }
  287. if (p_state & B_TERTIARY_MOUSE_BUTTON) {
  288. state |= 1 << 2;
  289. }
  290. last_button_mask = state;
  291. return state;
  292. }