input.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573
  1. //========================================================================
  2. // GLFW 3.4 - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2002-2006 Marcus Geelnard
  5. // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
  6. //
  7. // This software is provided 'as-is', without any express or implied
  8. // warranty. In no event will the authors be held liable for any damages
  9. // arising from the use of this software.
  10. //
  11. // Permission is granted to anyone to use this software for any purpose,
  12. // including commercial applications, and to alter it and redistribute it
  13. // freely, subject to the following restrictions:
  14. //
  15. // 1. The origin of this software must not be misrepresented; you must not
  16. // claim that you wrote the original software. If you use this software
  17. // in a product, an acknowledgment in the product documentation would
  18. // be appreciated but is not required.
  19. //
  20. // 2. Altered source versions must be plainly marked as such, and must not
  21. // be misrepresented as being the original software.
  22. //
  23. // 3. This notice may not be removed or altered from any source
  24. // distribution.
  25. //
  26. //========================================================================
  27. // Please use C89 style variable declarations in this file because VS 2010
  28. //========================================================================
  29. #include "internal.h"
  30. #include "../kitty/monotonic.h"
  31. #include <assert.h>
  32. #include <float.h>
  33. #include <math.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. // Internal key state used for sticky keys
  37. #define _GLFW_STICK 3
  38. // Internal constants for gamepad mapping source types
  39. #define _GLFW_JOYSTICK_AXIS 1
  40. #define _GLFW_JOYSTICK_BUTTON 2
  41. #define _GLFW_JOYSTICK_HATBIT 3
  42. // Initializes the platform joystick API if it has not been already
  43. //
  44. static bool initJoysticks(void)
  45. {
  46. if (!_glfw.joysticksInitialized)
  47. {
  48. if (!_glfwPlatformInitJoysticks())
  49. {
  50. _glfwPlatformTerminateJoysticks();
  51. return false;
  52. }
  53. }
  54. return _glfw.joysticksInitialized = true;
  55. }
  56. // Finds a mapping based on joystick GUID
  57. //
  58. static _GLFWmapping* findMapping(const char* guid)
  59. {
  60. int i;
  61. for (i = 0; i < _glfw.mappingCount; i++)
  62. {
  63. if (strcmp(_glfw.mappings[i].guid, guid) == 0)
  64. return _glfw.mappings + i;
  65. }
  66. return NULL;
  67. }
  68. // Checks whether a gamepad mapping element is present in the hardware
  69. //
  70. static bool isValidElementForJoystick(const _GLFWmapelement* e,
  71. const _GLFWjoystick* js)
  72. {
  73. if (e->type == _GLFW_JOYSTICK_HATBIT && (e->index >> 4) >= js->hatCount)
  74. return false;
  75. else if (e->type == _GLFW_JOYSTICK_BUTTON && e->index >= js->buttonCount)
  76. return false;
  77. else if (e->type == _GLFW_JOYSTICK_AXIS && e->index >= js->axisCount)
  78. return false;
  79. return true;
  80. }
  81. // Finds a mapping based on joystick GUID and verifies element indices
  82. //
  83. static _GLFWmapping* findValidMapping(const _GLFWjoystick* js)
  84. {
  85. _GLFWmapping* mapping = findMapping(js->guid);
  86. if (mapping)
  87. {
  88. int i;
  89. for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
  90. {
  91. if (!isValidElementForJoystick(mapping->buttons + i, js))
  92. {
  93. _glfwInputError(GLFW_INVALID_VALUE,
  94. "Invalid button in gamepad mapping %s (%s)",
  95. mapping->guid,
  96. mapping->name);
  97. return NULL;
  98. }
  99. }
  100. for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++)
  101. {
  102. if (!isValidElementForJoystick(mapping->axes + i, js))
  103. {
  104. _glfwInputError(GLFW_INVALID_VALUE,
  105. "Invalid axis in gamepad mapping %s (%s)",
  106. mapping->guid,
  107. mapping->name);
  108. return NULL;
  109. }
  110. }
  111. }
  112. return mapping;
  113. }
  114. // Parses an SDL_GameControllerDB line and adds it to the mapping list
  115. //
  116. static bool parseMapping(_GLFWmapping* mapping, const char* string)
  117. {
  118. const char* c = string;
  119. size_t i, length;
  120. struct
  121. {
  122. const char* name;
  123. _GLFWmapelement* element;
  124. } fields[] =
  125. {
  126. { "platform", NULL },
  127. { "a", mapping->buttons + GLFW_GAMEPAD_BUTTON_A },
  128. { "b", mapping->buttons + GLFW_GAMEPAD_BUTTON_B },
  129. { "x", mapping->buttons + GLFW_GAMEPAD_BUTTON_X },
  130. { "y", mapping->buttons + GLFW_GAMEPAD_BUTTON_Y },
  131. { "back", mapping->buttons + GLFW_GAMEPAD_BUTTON_BACK },
  132. { "start", mapping->buttons + GLFW_GAMEPAD_BUTTON_START },
  133. { "guide", mapping->buttons + GLFW_GAMEPAD_BUTTON_GUIDE },
  134. { "leftshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_BUMPER },
  135. { "rightshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER },
  136. { "leftstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_THUMB },
  137. { "rightstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_THUMB },
  138. { "dpup", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_UP },
  139. { "dpright", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_RIGHT },
  140. { "dpdown", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_DOWN },
  141. { "dpleft", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_LEFT },
  142. { "lefttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_TRIGGER },
  143. { "righttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER },
  144. { "leftx", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_X },
  145. { "lefty", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_Y },
  146. { "rightx", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_X },
  147. { "righty", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_Y }
  148. };
  149. length = strcspn(c, ",");
  150. if (length != 32 || c[length] != ',')
  151. {
  152. _glfwInputError(GLFW_INVALID_VALUE, NULL);
  153. return false;
  154. }
  155. memcpy(mapping->guid, c, length);
  156. c += length + 1;
  157. length = strcspn(c, ",");
  158. if (length >= sizeof(mapping->name) || c[length] != ',')
  159. {
  160. _glfwInputError(GLFW_INVALID_VALUE, NULL);
  161. return false;
  162. }
  163. memcpy(mapping->name, c, length);
  164. c += length + 1;
  165. while (*c)
  166. {
  167. // TODO: Implement output modifiers
  168. if (*c == '+' || *c == '-')
  169. return false;
  170. for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++)
  171. {
  172. length = strlen(fields[i].name);
  173. if (strncmp(c, fields[i].name, length) != 0 || c[length] != ':')
  174. continue;
  175. c += length + 1;
  176. if (fields[i].element)
  177. {
  178. _GLFWmapelement* e = fields[i].element;
  179. int8_t minimum = -1;
  180. int8_t maximum = 1;
  181. if (*c == '+')
  182. {
  183. minimum = 0;
  184. c += 1;
  185. }
  186. else if (*c == '-')
  187. {
  188. maximum = 0;
  189. c += 1;
  190. }
  191. if (*c == 'a')
  192. e->type = _GLFW_JOYSTICK_AXIS;
  193. else if (*c == 'b')
  194. e->type = _GLFW_JOYSTICK_BUTTON;
  195. else if (*c == 'h')
  196. e->type = _GLFW_JOYSTICK_HATBIT;
  197. else
  198. break;
  199. if (e->type == _GLFW_JOYSTICK_HATBIT)
  200. {
  201. const unsigned long hat = strtoul(c + 1, (char**) &c, 10);
  202. const unsigned long bit = strtoul(c + 1, (char**) &c, 10);
  203. e->index = (uint8_t) ((hat << 4) | bit);
  204. }
  205. else
  206. e->index = (uint8_t) strtoul(c + 1, (char**) &c, 10);
  207. if (e->type == _GLFW_JOYSTICK_AXIS)
  208. {
  209. e->axisScale = 2 / (maximum - minimum);
  210. e->axisOffset = -(maximum + minimum);
  211. if (*c == '~')
  212. {
  213. e->axisScale = -e->axisScale;
  214. e->axisOffset = -e->axisOffset;
  215. }
  216. }
  217. }
  218. else
  219. {
  220. length = strlen(_GLFW_PLATFORM_MAPPING_NAME);
  221. if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0)
  222. return false;
  223. }
  224. break;
  225. }
  226. c += strcspn(c, ",");
  227. c += strspn(c, ",");
  228. }
  229. for (i = 0; i < 32; i++)
  230. {
  231. if (mapping->guid[i] >= 'A' && mapping->guid[i] <= 'F')
  232. mapping->guid[i] += 'a' - 'A';
  233. }
  234. _glfwPlatformUpdateGamepadGUID(mapping->guid);
  235. return true;
  236. }
  237. //////////////////////////////////////////////////////////////////////////
  238. ////// GLFW event API //////
  239. //////////////////////////////////////////////////////////////////////////
  240. static void
  241. set_key_action(_GLFWwindow *window, const GLFWkeyevent *ev, int action, int idx) {
  242. const unsigned sz = arraysz(window->activated_keys);
  243. if (idx < 0) {
  244. for (unsigned i = 0; i < sz; i++) {
  245. if (window->activated_keys[i].native_key_id == 0) {
  246. idx = i;
  247. break;
  248. }
  249. }
  250. if (idx < 0) {
  251. idx = sz - 1;
  252. memmove(window->activated_keys, window->activated_keys + 1, sizeof(window->activated_keys[0]) * (sz - 1));
  253. window->activated_keys[sz - 1].native_key_id = 0;
  254. }
  255. }
  256. if (action == GLFW_RELEASE) {
  257. memset(window->activated_keys + idx, 0, sizeof(window->activated_keys[0]));
  258. if (idx < (int)sz - 1) {
  259. memmove(window->activated_keys + idx, window->activated_keys + idx + 1, sizeof(window->activated_keys[0]) * (sz - 1 - idx));
  260. memset(window->activated_keys + sz - 1, 0, sizeof(window->activated_keys[0]));
  261. }
  262. } else {
  263. window->activated_keys[idx] = *ev;
  264. window->activated_keys[idx].text = NULL;
  265. }
  266. }
  267. // Notifies shared code of a physical key event
  268. //
  269. void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev)
  270. {
  271. if (ev->native_key_id > 0)
  272. {
  273. bool repeated = false;
  274. int idx = -1;
  275. int current_action = GLFW_RELEASE;
  276. const unsigned sz = arraysz(window->activated_keys);
  277. for (unsigned i = 0; i < sz; i++) {
  278. if (window->activated_keys[i].native_key_id == ev->native_key_id) {
  279. idx = i;
  280. current_action = window->activated_keys[i].action;
  281. break;
  282. }
  283. }
  284. if (ev->action == GLFW_RELEASE) {
  285. if (current_action == GLFW_RELEASE) return;
  286. if (idx > -1) {
  287. const GLFWkeyevent *press_event = window->activated_keys + idx;
  288. if (press_event->action == GLFW_PRESS || press_event->action == GLFW_REPEAT) {
  289. // Compose sequences under X11 give a different key value for press and release events
  290. // but we want the same key value so override it.
  291. ev->native_key = press_event->native_key;
  292. ev->key = press_event->key;
  293. ev->shifted_key = press_event->shifted_key;
  294. ev->alternate_key = press_event->alternate_key;
  295. }
  296. }
  297. }
  298. if (ev->action == GLFW_PRESS && current_action == GLFW_PRESS)
  299. repeated = true;
  300. set_key_action(window, ev, (ev->action == GLFW_RELEASE && window->stickyKeys) ? _GLFW_STICK : ev->action, idx);
  301. if (repeated)
  302. ev->action = GLFW_REPEAT;
  303. }
  304. // FIXME: will need to update ev->virtual_mods here too?
  305. if (window->callbacks.keyboard) {
  306. if (!window->lockKeyMods) ev->mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
  307. window->callbacks.keyboard((GLFWwindow*) window, ev);
  308. }
  309. }
  310. // Notifies shared code of a scroll event
  311. //
  312. void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags, int mods)
  313. {
  314. if (window->callbacks.scroll)
  315. window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags, mods);
  316. }
  317. // Notifies shared code of a mouse button click event
  318. //
  319. void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
  320. {
  321. if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
  322. return;
  323. if (!window->lockKeyMods)
  324. mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
  325. if (action == GLFW_RELEASE && window->stickyMouseButtons)
  326. window->mouseButtons[button] = _GLFW_STICK;
  327. else
  328. window->mouseButtons[button] = (char) action;
  329. if (window->callbacks.mouseButton)
  330. window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
  331. }
  332. // Notifies shared code of a cursor motion event
  333. // The position is specified in content area relative screen coordinates
  334. //
  335. void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
  336. {
  337. if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
  338. return;
  339. window->virtualCursorPosX = xpos;
  340. window->virtualCursorPosY = ypos;
  341. if (window->callbacks.cursorPos)
  342. window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos);
  343. }
  344. // Notifies shared code of a cursor enter/leave event
  345. //
  346. void _glfwInputCursorEnter(_GLFWwindow* window, bool entered)
  347. {
  348. if (window->callbacks.cursorEnter)
  349. window->callbacks.cursorEnter((GLFWwindow*) window, entered);
  350. }
  351. // Notifies shared code of files or directories dropped on a window
  352. //
  353. int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz)
  354. {
  355. if (window->callbacks.drop)
  356. return window->callbacks.drop((GLFWwindow*) window, mime, text, sz);
  357. return 0;
  358. }
  359. // Notifies shared code of a joystick connection or disconnection
  360. //
  361. void _glfwInputJoystick(_GLFWjoystick* js, int event)
  362. {
  363. const int jid = (int) (js - _glfw.joysticks);
  364. if (_glfw.callbacks.joystick)
  365. _glfw.callbacks.joystick(jid, event);
  366. }
  367. // Notifies shared code of the new value of a joystick axis
  368. //
  369. void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value)
  370. {
  371. js->axes[axis] = value;
  372. }
  373. // Notifies shared code of the new value of a joystick button
  374. //
  375. void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value)
  376. {
  377. js->buttons[button] = value;
  378. }
  379. // Notifies shared code of the new value of a joystick hat
  380. //
  381. void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
  382. {
  383. const int base = js->buttonCount + hat * 4;
  384. js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE;
  385. js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE;
  386. js->buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE;
  387. js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE;
  388. js->hats[hat] = value;
  389. }
  390. void _glfwInputColorScheme(GLFWColorScheme value) {
  391. _glfwPlatformInputColorScheme(value);
  392. if (_glfw.callbacks.system_color_theme_change) _glfw.callbacks.system_color_theme_change(value);
  393. }
  394. //////////////////////////////////////////////////////////////////////////
  395. ////// GLFW internal API //////
  396. //////////////////////////////////////////////////////////////////////////
  397. // Returns an available joystick object with arrays and name allocated
  398. //
  399. _GLFWjoystick* _glfwAllocJoystick(const char* name,
  400. const char* guid,
  401. int axisCount,
  402. int buttonCount,
  403. int hatCount)
  404. {
  405. int jid;
  406. _GLFWjoystick* js;
  407. for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
  408. {
  409. if (!_glfw.joysticks[jid].present)
  410. break;
  411. }
  412. if (jid > GLFW_JOYSTICK_LAST)
  413. return NULL;
  414. js = _glfw.joysticks + jid;
  415. js->present = true;
  416. js->name = _glfw_strdup(name);
  417. js->axes = calloc(axisCount, sizeof(float));
  418. js->buttons = calloc(buttonCount + (size_t) hatCount * 4, 1);
  419. js->hats = calloc(hatCount, 1);
  420. js->axisCount = axisCount;
  421. js->buttonCount = buttonCount;
  422. js->hatCount = hatCount;
  423. strncpy(js->guid, guid, sizeof(js->guid) - 1);
  424. js->mapping = findValidMapping(js);
  425. return js;
  426. }
  427. // Frees arrays and name and flags the joystick object as unused
  428. //
  429. void _glfwFreeJoystick(_GLFWjoystick* js)
  430. {
  431. free(js->name);
  432. free(js->axes);
  433. free(js->buttons);
  434. free(js->hats);
  435. memset(js, 0, sizeof(_GLFWjoystick));
  436. }
  437. unsigned int
  438. encode_utf8(uint32_t ch, char* dest) {
  439. if (ch < 0x80) {
  440. dest[0] = (char)ch;
  441. return 1;
  442. }
  443. if (ch < 0x800) {
  444. dest[0] = (ch>>6) | 0xC0;
  445. dest[1] = (ch & 0x3F) | 0x80;
  446. return 2;
  447. }
  448. if (ch < 0x10000) {
  449. dest[0] = (ch>>12) | 0xE0;
  450. dest[1] = ((ch>>6) & 0x3F) | 0x80;
  451. dest[2] = (ch & 0x3F) | 0x80;
  452. return 3;
  453. }
  454. if (ch < 0x110000) {
  455. dest[0] = (ch>>18) | 0xF0;
  456. dest[1] = ((ch>>12) & 0x3F) | 0x80;
  457. dest[2] = ((ch>>6) & 0x3F) | 0x80;
  458. dest[3] = (ch & 0x3F) | 0x80;
  459. return 4;
  460. }
  461. return 0;
  462. }
  463. const char*
  464. _glfwGetKeyName(int key)
  465. {
  466. switch (key)
  467. {
  468. /* start functional key names (auto generated by gen-key-constants.py do not edit) */
  469. case GLFW_FKEY_ESCAPE: return "ESCAPE";
  470. case GLFW_FKEY_ENTER: return "ENTER";
  471. case GLFW_FKEY_TAB: return "TAB";
  472. case GLFW_FKEY_BACKSPACE: return "BACKSPACE";
  473. case GLFW_FKEY_INSERT: return "INSERT";
  474. case GLFW_FKEY_DELETE: return "DELETE";
  475. case GLFW_FKEY_LEFT: return "LEFT";
  476. case GLFW_FKEY_RIGHT: return "RIGHT";
  477. case GLFW_FKEY_UP: return "UP";
  478. case GLFW_FKEY_DOWN: return "DOWN";
  479. case GLFW_FKEY_PAGE_UP: return "PAGE_UP";
  480. case GLFW_FKEY_PAGE_DOWN: return "PAGE_DOWN";
  481. case GLFW_FKEY_HOME: return "HOME";
  482. case GLFW_FKEY_END: return "END";
  483. case GLFW_FKEY_CAPS_LOCK: return "CAPS_LOCK";
  484. case GLFW_FKEY_SCROLL_LOCK: return "SCROLL_LOCK";
  485. case GLFW_FKEY_NUM_LOCK: return "NUM_LOCK";
  486. case GLFW_FKEY_PRINT_SCREEN: return "PRINT_SCREEN";
  487. case GLFW_FKEY_PAUSE: return "PAUSE";
  488. case GLFW_FKEY_MENU: return "MENU";
  489. case GLFW_FKEY_F1: return "F1";
  490. case GLFW_FKEY_F2: return "F2";
  491. case GLFW_FKEY_F3: return "F3";
  492. case GLFW_FKEY_F4: return "F4";
  493. case GLFW_FKEY_F5: return "F5";
  494. case GLFW_FKEY_F6: return "F6";
  495. case GLFW_FKEY_F7: return "F7";
  496. case GLFW_FKEY_F8: return "F8";
  497. case GLFW_FKEY_F9: return "F9";
  498. case GLFW_FKEY_F10: return "F10";
  499. case GLFW_FKEY_F11: return "F11";
  500. case GLFW_FKEY_F12: return "F12";
  501. case GLFW_FKEY_F13: return "F13";
  502. case GLFW_FKEY_F14: return "F14";
  503. case GLFW_FKEY_F15: return "F15";
  504. case GLFW_FKEY_F16: return "F16";
  505. case GLFW_FKEY_F17: return "F17";
  506. case GLFW_FKEY_F18: return "F18";
  507. case GLFW_FKEY_F19: return "F19";
  508. case GLFW_FKEY_F20: return "F20";
  509. case GLFW_FKEY_F21: return "F21";
  510. case GLFW_FKEY_F22: return "F22";
  511. case GLFW_FKEY_F23: return "F23";
  512. case GLFW_FKEY_F24: return "F24";
  513. case GLFW_FKEY_F25: return "F25";
  514. case GLFW_FKEY_F26: return "F26";
  515. case GLFW_FKEY_F27: return "F27";
  516. case GLFW_FKEY_F28: return "F28";
  517. case GLFW_FKEY_F29: return "F29";
  518. case GLFW_FKEY_F30: return "F30";
  519. case GLFW_FKEY_F31: return "F31";
  520. case GLFW_FKEY_F32: return "F32";
  521. case GLFW_FKEY_F33: return "F33";
  522. case GLFW_FKEY_F34: return "F34";
  523. case GLFW_FKEY_F35: return "F35";
  524. case GLFW_FKEY_KP_0: return "KP_0";
  525. case GLFW_FKEY_KP_1: return "KP_1";
  526. case GLFW_FKEY_KP_2: return "KP_2";
  527. case GLFW_FKEY_KP_3: return "KP_3";
  528. case GLFW_FKEY_KP_4: return "KP_4";
  529. case GLFW_FKEY_KP_5: return "KP_5";
  530. case GLFW_FKEY_KP_6: return "KP_6";
  531. case GLFW_FKEY_KP_7: return "KP_7";
  532. case GLFW_FKEY_KP_8: return "KP_8";
  533. case GLFW_FKEY_KP_9: return "KP_9";
  534. case GLFW_FKEY_KP_DECIMAL: return "KP_DECIMAL";
  535. case GLFW_FKEY_KP_DIVIDE: return "KP_DIVIDE";
  536. case GLFW_FKEY_KP_MULTIPLY: return "KP_MULTIPLY";
  537. case GLFW_FKEY_KP_SUBTRACT: return "KP_SUBTRACT";
  538. case GLFW_FKEY_KP_ADD: return "KP_ADD";
  539. case GLFW_FKEY_KP_ENTER: return "KP_ENTER";
  540. case GLFW_FKEY_KP_EQUAL: return "KP_EQUAL";
  541. case GLFW_FKEY_KP_SEPARATOR: return "KP_SEPARATOR";
  542. case GLFW_FKEY_KP_LEFT: return "KP_LEFT";
  543. case GLFW_FKEY_KP_RIGHT: return "KP_RIGHT";
  544. case GLFW_FKEY_KP_UP: return "KP_UP";
  545. case GLFW_FKEY_KP_DOWN: return "KP_DOWN";
  546. case GLFW_FKEY_KP_PAGE_UP: return "KP_PAGE_UP";
  547. case GLFW_FKEY_KP_PAGE_DOWN: return "KP_PAGE_DOWN";
  548. case GLFW_FKEY_KP_HOME: return "KP_HOME";
  549. case GLFW_FKEY_KP_END: return "KP_END";
  550. case GLFW_FKEY_KP_INSERT: return "KP_INSERT";
  551. case GLFW_FKEY_KP_DELETE: return "KP_DELETE";
  552. case GLFW_FKEY_KP_BEGIN: return "KP_BEGIN";
  553. case GLFW_FKEY_MEDIA_PLAY: return "MEDIA_PLAY";
  554. case GLFW_FKEY_MEDIA_PAUSE: return "MEDIA_PAUSE";
  555. case GLFW_FKEY_MEDIA_PLAY_PAUSE: return "MEDIA_PLAY_PAUSE";
  556. case GLFW_FKEY_MEDIA_REVERSE: return "MEDIA_REVERSE";
  557. case GLFW_FKEY_MEDIA_STOP: return "MEDIA_STOP";
  558. case GLFW_FKEY_MEDIA_FAST_FORWARD: return "MEDIA_FAST_FORWARD";
  559. case GLFW_FKEY_MEDIA_REWIND: return "MEDIA_REWIND";
  560. case GLFW_FKEY_MEDIA_TRACK_NEXT: return "MEDIA_TRACK_NEXT";
  561. case GLFW_FKEY_MEDIA_TRACK_PREVIOUS: return "MEDIA_TRACK_PREVIOUS";
  562. case GLFW_FKEY_MEDIA_RECORD: return "MEDIA_RECORD";
  563. case GLFW_FKEY_LOWER_VOLUME: return "LOWER_VOLUME";
  564. case GLFW_FKEY_RAISE_VOLUME: return "RAISE_VOLUME";
  565. case GLFW_FKEY_MUTE_VOLUME: return "MUTE_VOLUME";
  566. case GLFW_FKEY_LEFT_SHIFT: return "LEFT_SHIFT";
  567. case GLFW_FKEY_LEFT_CONTROL: return "LEFT_CONTROL";
  568. case GLFW_FKEY_LEFT_ALT: return "LEFT_ALT";
  569. case GLFW_FKEY_LEFT_SUPER: return "LEFT_SUPER";
  570. case GLFW_FKEY_LEFT_HYPER: return "LEFT_HYPER";
  571. case GLFW_FKEY_LEFT_META: return "LEFT_META";
  572. case GLFW_FKEY_RIGHT_SHIFT: return "RIGHT_SHIFT";
  573. case GLFW_FKEY_RIGHT_CONTROL: return "RIGHT_CONTROL";
  574. case GLFW_FKEY_RIGHT_ALT: return "RIGHT_ALT";
  575. case GLFW_FKEY_RIGHT_SUPER: return "RIGHT_SUPER";
  576. case GLFW_FKEY_RIGHT_HYPER: return "RIGHT_HYPER";
  577. case GLFW_FKEY_RIGHT_META: return "RIGHT_META";
  578. case GLFW_FKEY_ISO_LEVEL3_SHIFT: return "ISO_LEVEL3_SHIFT";
  579. case GLFW_FKEY_ISO_LEVEL5_SHIFT: return "ISO_LEVEL5_SHIFT";
  580. /* end functional key names */
  581. case 0: return "UNKNOWN";
  582. }
  583. static char buf[16];
  584. encode_utf8(key, buf);
  585. return buf;
  586. }
  587. // Center the cursor in the content area of the specified window
  588. //
  589. void _glfwCenterCursorInContentArea(_GLFWwindow* window)
  590. {
  591. int width, height;
  592. _glfwPlatformGetWindowSize(window, &width, &height);
  593. _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
  594. }
  595. //////////////////////////////////////////////////////////////////////////
  596. ////// GLFW public API //////
  597. //////////////////////////////////////////////////////////////////////////
  598. GLFWAPI bool glfwGetIgnoreOSKeyboardProcessing(void) {
  599. return _glfw.ignoreOSKeyboardProcessing;
  600. }
  601. GLFWAPI void glfwSetIgnoreOSKeyboardProcessing(bool enabled) {
  602. _glfw.ignoreOSKeyboardProcessing = enabled;
  603. }
  604. GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
  605. {
  606. _GLFWwindow* window = (_GLFWwindow*) handle;
  607. assert(window != NULL);
  608. _GLFW_REQUIRE_INIT_OR_RETURN(0);
  609. switch (mode)
  610. {
  611. case GLFW_CURSOR:
  612. return window->cursorMode;
  613. case GLFW_STICKY_KEYS:
  614. return window->stickyKeys;
  615. case GLFW_STICKY_MOUSE_BUTTONS:
  616. return window->stickyMouseButtons;
  617. case GLFW_LOCK_KEY_MODS:
  618. return window->lockKeyMods;
  619. case GLFW_RAW_MOUSE_MOTION:
  620. return window->rawMouseMotion;
  621. }
  622. _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
  623. return 0;
  624. }
  625. GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
  626. {
  627. _GLFWwindow* window = (_GLFWwindow*) handle;
  628. assert(window != NULL);
  629. _GLFW_REQUIRE_INIT();
  630. if (mode == GLFW_CURSOR)
  631. {
  632. if (value != GLFW_CURSOR_NORMAL &&
  633. value != GLFW_CURSOR_HIDDEN &&
  634. value != GLFW_CURSOR_DISABLED)
  635. {
  636. _glfwInputError(GLFW_INVALID_ENUM,
  637. "Invalid cursor mode 0x%08X",
  638. value);
  639. return;
  640. }
  641. if (window->cursorMode == value)
  642. return;
  643. window->cursorMode = value;
  644. _glfwPlatformGetCursorPos(window,
  645. &window->virtualCursorPosX,
  646. &window->virtualCursorPosY);
  647. _glfwPlatformSetCursorMode(window, value);
  648. }
  649. else if (mode == GLFW_STICKY_KEYS)
  650. {
  651. value = value ? true : false;
  652. if (window->stickyKeys == value)
  653. return;
  654. if (!value)
  655. {
  656. // Release all sticky keys
  657. for (unsigned i = arraysz(window->activated_keys) - 1; i-- > 0;)
  658. {
  659. if (window->activated_keys[i].action == _GLFW_STICK) {
  660. if (i < arraysz(window->activated_keys) - 1) {
  661. memmove(window->activated_keys + i, window->activated_keys + i + 1, sizeof(window->activated_keys[0]) * (arraysz(window->activated_keys) - 1 - i));
  662. }
  663. memset(window->activated_keys + arraysz(window->activated_keys) - 1, 0, sizeof(window->activated_keys[0]));
  664. }
  665. }
  666. }
  667. window->stickyKeys = value;
  668. }
  669. else if (mode == GLFW_STICKY_MOUSE_BUTTONS)
  670. {
  671. value = value ? true : false;
  672. if (window->stickyMouseButtons == value)
  673. return;
  674. if (!value)
  675. {
  676. int i;
  677. // Release all sticky mouse buttons
  678. for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
  679. {
  680. if (window->mouseButtons[i] == _GLFW_STICK)
  681. window->mouseButtons[i] = GLFW_RELEASE;
  682. }
  683. }
  684. window->stickyMouseButtons = value;
  685. }
  686. else if (mode == GLFW_LOCK_KEY_MODS)
  687. {
  688. window->lockKeyMods = value ? true : false;
  689. }
  690. else if (mode == GLFW_RAW_MOUSE_MOTION)
  691. {
  692. if (!_glfwPlatformRawMouseMotionSupported())
  693. {
  694. _glfwInputError(GLFW_PLATFORM_ERROR,
  695. "Raw mouse motion is not supported on this system");
  696. return;
  697. }
  698. value = value ? true : false;
  699. if (window->rawMouseMotion == value)
  700. return;
  701. window->rawMouseMotion = value;
  702. _glfwPlatformSetRawMouseMotion(window, value);
  703. }
  704. else
  705. _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
  706. }
  707. GLFWAPI int glfwRawMouseMotionSupported(void)
  708. {
  709. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  710. return _glfwPlatformRawMouseMotionSupported();
  711. }
  712. GLFWAPI const char* glfwGetKeyName(uint32_t key, int native_key)
  713. {
  714. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  715. if (key) return _glfwGetKeyName(key);
  716. native_key = _glfwPlatformGetNativeKeyForKey(key);
  717. return _glfwPlatformGetNativeKeyName(native_key);
  718. }
  719. GLFWAPI int glfwGetNativeKeyForKey(uint32_t key)
  720. {
  721. _GLFW_REQUIRE_INIT_OR_RETURN(-1);
  722. return _glfwPlatformGetNativeKeyForKey(key);
  723. }
  724. GLFWAPI GLFWKeyAction glfwGetKey(GLFWwindow* handle, uint32_t key)
  725. {
  726. _GLFWwindow* window = (_GLFWwindow*) handle;
  727. assert(window != NULL);
  728. _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
  729. if (!key) return GLFW_RELEASE;
  730. int current_action = GLFW_RELEASE;
  731. const unsigned sz = arraysz(window->activated_keys);
  732. int idx = -1;
  733. for (unsigned i = 0; i < sz; i++) {
  734. if (window->activated_keys[i].key == key) {
  735. idx = i;
  736. current_action = window->activated_keys[i].action;
  737. break;
  738. }
  739. }
  740. if (current_action == _GLFW_STICK)
  741. {
  742. // Sticky mode: release key now
  743. GLFWkeyevent ev = {0};
  744. set_key_action(window, &ev, GLFW_RELEASE, idx);
  745. current_action = GLFW_PRESS;
  746. }
  747. return current_action;
  748. }
  749. GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
  750. {
  751. _GLFWwindow* window = (_GLFWwindow*) handle;
  752. assert(window != NULL);
  753. _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
  754. if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST)
  755. {
  756. _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button);
  757. return GLFW_RELEASE;
  758. }
  759. if (window->mouseButtons[button] == _GLFW_STICK)
  760. {
  761. // Sticky mode: release mouse button now
  762. window->mouseButtons[button] = GLFW_RELEASE;
  763. return GLFW_PRESS;
  764. }
  765. return (int) window->mouseButtons[button];
  766. }
  767. GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
  768. {
  769. _GLFWwindow* window = (_GLFWwindow*) handle;
  770. assert(window != NULL);
  771. if (xpos)
  772. *xpos = 0;
  773. if (ypos)
  774. *ypos = 0;
  775. _GLFW_REQUIRE_INIT();
  776. if (window->cursorMode == GLFW_CURSOR_DISABLED)
  777. {
  778. if (xpos)
  779. *xpos = window->virtualCursorPosX;
  780. if (ypos)
  781. *ypos = window->virtualCursorPosY;
  782. }
  783. else
  784. _glfwPlatformGetCursorPos(window, xpos, ypos);
  785. }
  786. GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
  787. {
  788. _GLFWwindow* window = (_GLFWwindow*) handle;
  789. assert(window != NULL);
  790. _GLFW_REQUIRE_INIT();
  791. if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX ||
  792. ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX)
  793. {
  794. _glfwInputError(GLFW_INVALID_VALUE,
  795. "Invalid cursor position %f %f",
  796. xpos, ypos);
  797. return;
  798. }
  799. if (!_glfwPlatformWindowFocused(window))
  800. return;
  801. if (window->cursorMode == GLFW_CURSOR_DISABLED)
  802. {
  803. // Only update the accumulated position if the cursor is disabled
  804. window->virtualCursorPosX = xpos;
  805. window->virtualCursorPosY = ypos;
  806. }
  807. else
  808. {
  809. // Update system cursor position
  810. _glfwPlatformSetCursorPos(window, xpos, ypos);
  811. }
  812. }
  813. GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot, int count)
  814. {
  815. _GLFWcursor* cursor;
  816. assert(image != NULL);
  817. assert(count > 0);
  818. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  819. cursor = calloc(1, sizeof(_GLFWcursor));
  820. cursor->next = _glfw.cursorListHead;
  821. _glfw.cursorListHead = cursor;
  822. if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot, count))
  823. {
  824. glfwDestroyCursor((GLFWcursor*) cursor);
  825. return NULL;
  826. }
  827. return (GLFWcursor*) cursor;
  828. }
  829. GLFWAPI GLFWcursor* glfwCreateStandardCursor(GLFWCursorShape shape)
  830. {
  831. _GLFWcursor* cursor;
  832. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  833. if (shape >= GLFW_INVALID_CURSOR)
  834. {
  835. _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor: %d", shape);
  836. return NULL;
  837. }
  838. cursor = calloc(1, sizeof(_GLFWcursor));
  839. cursor->next = _glfw.cursorListHead;
  840. _glfw.cursorListHead = cursor;
  841. if (!_glfwPlatformCreateStandardCursor(cursor, shape))
  842. {
  843. glfwDestroyCursor((GLFWcursor*) cursor);
  844. return NULL;
  845. }
  846. return (GLFWcursor*) cursor;
  847. }
  848. GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
  849. {
  850. _GLFWcursor* cursor = (_GLFWcursor*) handle;
  851. _GLFW_REQUIRE_INIT();
  852. if (cursor == NULL)
  853. return;
  854. // Make sure the cursor is not being used by any window
  855. {
  856. _GLFWwindow* window;
  857. for (window = _glfw.windowListHead; window; window = window->next)
  858. {
  859. if (window->cursor == cursor)
  860. glfwSetCursor((GLFWwindow*) window, NULL);
  861. }
  862. }
  863. _glfwPlatformDestroyCursor(cursor);
  864. // Unlink cursor from global linked list
  865. {
  866. _GLFWcursor** prev = &_glfw.cursorListHead;
  867. while (*prev != cursor)
  868. prev = &((*prev)->next);
  869. *prev = cursor->next;
  870. }
  871. free(cursor);
  872. }
  873. GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
  874. {
  875. _GLFWwindow* window = (_GLFWwindow*) windowHandle;
  876. _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
  877. assert(window != NULL);
  878. _GLFW_REQUIRE_INIT();
  879. window->cursor = cursor;
  880. _glfwPlatformSetCursor(window, cursor);
  881. }
  882. GLFWAPI GLFWkeyboardfun glfwSetKeyboardCallback(GLFWwindow* handle, GLFWkeyboardfun cbfun)
  883. {
  884. _GLFWwindow* window = (_GLFWwindow*) handle;
  885. assert(window != NULL);
  886. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  887. _GLFW_SWAP_POINTERS(window->callbacks.keyboard, cbfun);
  888. return cbfun;
  889. }
  890. GLFWAPI void glfwUpdateIMEState(GLFWwindow* handle, const GLFWIMEUpdateEvent *ev) {
  891. _GLFWwindow* window = (_GLFWwindow*) handle;
  892. assert(window != NULL);
  893. _GLFW_REQUIRE_INIT();
  894. #if defined(_GLFW_X11) || defined(_GLFW_WAYLAND) || defined(_GLFW_COCOA)
  895. _glfwPlatformUpdateIMEState(window, ev);
  896. #else
  897. (void)window; (void)which; (void)a; (void)b; (void)c; (void)d;
  898. #endif
  899. }
  900. GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
  901. GLFWmousebuttonfun cbfun)
  902. {
  903. _GLFWwindow* window = (_GLFWwindow*) handle;
  904. assert(window != NULL);
  905. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  906. _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun);
  907. return cbfun;
  908. }
  909. GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle,
  910. GLFWcursorposfun cbfun)
  911. {
  912. _GLFWwindow* window = (_GLFWwindow*) handle;
  913. assert(window != NULL);
  914. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  915. _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun);
  916. return cbfun;
  917. }
  918. GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle,
  919. GLFWcursorenterfun cbfun)
  920. {
  921. _GLFWwindow* window = (_GLFWwindow*) handle;
  922. assert(window != NULL);
  923. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  924. _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun);
  925. return cbfun;
  926. }
  927. GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
  928. GLFWscrollfun cbfun)
  929. {
  930. _GLFWwindow* window = (_GLFWwindow*) handle;
  931. assert(window != NULL);
  932. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  933. _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun);
  934. return cbfun;
  935. }
  936. GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
  937. {
  938. _GLFWwindow* window = (_GLFWwindow*) handle;
  939. assert(window != NULL);
  940. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  941. _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun);
  942. return cbfun;
  943. }
  944. GLFWAPI int glfwJoystickPresent(int jid)
  945. {
  946. _GLFWjoystick* js;
  947. assert(jid >= GLFW_JOYSTICK_1);
  948. assert(jid <= GLFW_JOYSTICK_LAST);
  949. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  950. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  951. {
  952. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  953. return false;
  954. }
  955. if (!initJoysticks())
  956. return false;
  957. js = _glfw.joysticks + jid;
  958. if (!js->present)
  959. return false;
  960. return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE);
  961. }
  962. GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count)
  963. {
  964. _GLFWjoystick* js;
  965. assert(jid >= GLFW_JOYSTICK_1);
  966. assert(jid <= GLFW_JOYSTICK_LAST);
  967. assert(count != NULL);
  968. *count = 0;
  969. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  970. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  971. {
  972. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  973. return NULL;
  974. }
  975. if (!initJoysticks())
  976. return NULL;
  977. js = _glfw.joysticks + jid;
  978. if (!js->present)
  979. return NULL;
  980. if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES))
  981. return NULL;
  982. *count = js->axisCount;
  983. return js->axes;
  984. }
  985. GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
  986. {
  987. _GLFWjoystick* js;
  988. assert(jid >= GLFW_JOYSTICK_1);
  989. assert(jid <= GLFW_JOYSTICK_LAST);
  990. assert(count != NULL);
  991. *count = 0;
  992. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  993. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  994. {
  995. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  996. return NULL;
  997. }
  998. if (!initJoysticks())
  999. return NULL;
  1000. js = _glfw.joysticks + jid;
  1001. if (!js->present)
  1002. return NULL;
  1003. if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS))
  1004. return NULL;
  1005. if (_glfw.hints.init.hatButtons)
  1006. *count = js->buttonCount + js->hatCount * 4;
  1007. else
  1008. *count = js->buttonCount;
  1009. return js->buttons;
  1010. }
  1011. GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
  1012. {
  1013. _GLFWjoystick* js;
  1014. assert(jid >= GLFW_JOYSTICK_1);
  1015. assert(jid <= GLFW_JOYSTICK_LAST);
  1016. assert(count != NULL);
  1017. *count = 0;
  1018. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  1019. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  1020. {
  1021. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  1022. return NULL;
  1023. }
  1024. if (!initJoysticks())
  1025. return NULL;
  1026. js = _glfw.joysticks + jid;
  1027. if (!js->present)
  1028. return NULL;
  1029. if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS))
  1030. return NULL;
  1031. *count = js->hatCount;
  1032. return js->hats;
  1033. }
  1034. GLFWAPI const char* glfwGetJoystickName(int jid)
  1035. {
  1036. _GLFWjoystick* js;
  1037. assert(jid >= GLFW_JOYSTICK_1);
  1038. assert(jid <= GLFW_JOYSTICK_LAST);
  1039. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  1040. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  1041. {
  1042. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  1043. return NULL;
  1044. }
  1045. if (!initJoysticks())
  1046. return NULL;
  1047. js = _glfw.joysticks + jid;
  1048. if (!js->present)
  1049. return NULL;
  1050. if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
  1051. return NULL;
  1052. return js->name;
  1053. }
  1054. GLFWAPI const char* glfwGetJoystickGUID(int jid)
  1055. {
  1056. _GLFWjoystick* js;
  1057. assert(jid >= GLFW_JOYSTICK_1);
  1058. assert(jid <= GLFW_JOYSTICK_LAST);
  1059. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  1060. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  1061. {
  1062. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  1063. return NULL;
  1064. }
  1065. if (!initJoysticks())
  1066. return NULL;
  1067. js = _glfw.joysticks + jid;
  1068. if (!js->present)
  1069. return NULL;
  1070. if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
  1071. return NULL;
  1072. return js->guid;
  1073. }
  1074. GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer)
  1075. {
  1076. _GLFWjoystick* js;
  1077. assert(jid >= GLFW_JOYSTICK_1);
  1078. assert(jid <= GLFW_JOYSTICK_LAST);
  1079. _GLFW_REQUIRE_INIT();
  1080. js = _glfw.joysticks + jid;
  1081. if (!js->present)
  1082. return;
  1083. js->userPointer = pointer;
  1084. }
  1085. GLFWAPI void* glfwGetJoystickUserPointer(int jid)
  1086. {
  1087. _GLFWjoystick* js;
  1088. assert(jid >= GLFW_JOYSTICK_1);
  1089. assert(jid <= GLFW_JOYSTICK_LAST);
  1090. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  1091. js = _glfw.joysticks + jid;
  1092. if (!js->present)
  1093. return NULL;
  1094. return js->userPointer;
  1095. }
  1096. GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
  1097. {
  1098. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  1099. if (!initJoysticks())
  1100. return NULL;
  1101. _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
  1102. return cbfun;
  1103. }
  1104. GLFWAPI int glfwUpdateGamepadMappings(const char* string)
  1105. {
  1106. int jid;
  1107. const char* c = string;
  1108. assert(string != NULL);
  1109. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  1110. while (*c)
  1111. {
  1112. if ((*c >= '0' && *c <= '9') ||
  1113. (*c >= 'a' && *c <= 'f') ||
  1114. (*c >= 'A' && *c <= 'F'))
  1115. {
  1116. char line[1024];
  1117. const size_t length = strcspn(c, "\r\n");
  1118. if (length < sizeof(line))
  1119. {
  1120. _GLFWmapping mapping = {{0}};
  1121. memcpy(line, c, length);
  1122. line[length] = '\0';
  1123. if (parseMapping(&mapping, line))
  1124. {
  1125. _GLFWmapping* previous = findMapping(mapping.guid);
  1126. if (previous)
  1127. *previous = mapping;
  1128. else
  1129. {
  1130. _glfw.mappingCount++;
  1131. _glfw.mappings =
  1132. realloc(_glfw.mappings,
  1133. sizeof(_GLFWmapping) * _glfw.mappingCount);
  1134. _glfw.mappings[_glfw.mappingCount - 1] = mapping;
  1135. }
  1136. }
  1137. }
  1138. c += length;
  1139. }
  1140. else
  1141. {
  1142. c += strcspn(c, "\r\n");
  1143. c += strspn(c, "\r\n");
  1144. }
  1145. }
  1146. for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
  1147. {
  1148. _GLFWjoystick* js = _glfw.joysticks + jid;
  1149. if (js->present)
  1150. js->mapping = findValidMapping(js);
  1151. }
  1152. return true;
  1153. }
  1154. GLFWAPI int glfwJoystickIsGamepad(int jid)
  1155. {
  1156. _GLFWjoystick* js;
  1157. assert(jid >= GLFW_JOYSTICK_1);
  1158. assert(jid <= GLFW_JOYSTICK_LAST);
  1159. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  1160. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  1161. {
  1162. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  1163. return false;
  1164. }
  1165. if (!initJoysticks())
  1166. return false;
  1167. js = _glfw.joysticks + jid;
  1168. if (!js->present)
  1169. return false;
  1170. if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
  1171. return false;
  1172. return js->mapping != NULL;
  1173. }
  1174. GLFWAPI const char* glfwGetGamepadName(int jid)
  1175. {
  1176. _GLFWjoystick* js;
  1177. assert(jid >= GLFW_JOYSTICK_1);
  1178. assert(jid <= GLFW_JOYSTICK_LAST);
  1179. _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
  1180. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  1181. {
  1182. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  1183. return NULL;
  1184. }
  1185. if (!initJoysticks())
  1186. return NULL;
  1187. js = _glfw.joysticks + jid;
  1188. if (!js->present)
  1189. return NULL;
  1190. if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
  1191. return NULL;
  1192. if (!js->mapping)
  1193. return NULL;
  1194. return js->mapping->name;
  1195. }
  1196. GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
  1197. {
  1198. int i;
  1199. _GLFWjoystick* js;
  1200. assert(jid >= GLFW_JOYSTICK_1);
  1201. assert(jid <= GLFW_JOYSTICK_LAST);
  1202. assert(state != NULL);
  1203. memset(state, 0, sizeof(GLFWgamepadstate));
  1204. _GLFW_REQUIRE_INIT_OR_RETURN(false);
  1205. if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
  1206. {
  1207. _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
  1208. return false;
  1209. }
  1210. if (!initJoysticks())
  1211. return false;
  1212. js = _glfw.joysticks + jid;
  1213. if (!js->present)
  1214. return false;
  1215. if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL))
  1216. return false;
  1217. if (!js->mapping)
  1218. return false;
  1219. for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
  1220. {
  1221. const _GLFWmapelement* e = js->mapping->buttons + i;
  1222. if (e->type == _GLFW_JOYSTICK_AXIS)
  1223. {
  1224. const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
  1225. // HACK: This should be baked into the value transform
  1226. // TODO: Bake into transform when implementing output modifiers
  1227. if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0))
  1228. {
  1229. if (value >= 0.f)
  1230. state->buttons[i] = GLFW_PRESS;
  1231. }
  1232. else
  1233. {
  1234. if (value <= 0.f)
  1235. state->buttons[i] = GLFW_PRESS;
  1236. }
  1237. }
  1238. else if (e->type == _GLFW_JOYSTICK_HATBIT)
  1239. {
  1240. const unsigned int hat = e->index >> 4;
  1241. const unsigned int bit = e->index & 0xf;
  1242. if (js->hats[hat] & bit)
  1243. state->buttons[i] = GLFW_PRESS;
  1244. }
  1245. else if (e->type == _GLFW_JOYSTICK_BUTTON)
  1246. state->buttons[i] = js->buttons[e->index];
  1247. }
  1248. for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++)
  1249. {
  1250. const _GLFWmapelement* e = js->mapping->axes + i;
  1251. if (e->type == _GLFW_JOYSTICK_AXIS)
  1252. {
  1253. const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
  1254. state->axes[i] = fminf(fmaxf(value, -1.f), 1.f);
  1255. }
  1256. else if (e->type == _GLFW_JOYSTICK_HATBIT)
  1257. {
  1258. const unsigned int hat = e->index >> 4;
  1259. const unsigned int bit = e->index & 0xf;
  1260. if (js->hats[hat] & bit)
  1261. state->axes[i] = 1.f;
  1262. else
  1263. state->axes[i] = -1.f;
  1264. }
  1265. else if (e->type == _GLFW_JOYSTICK_BUTTON)
  1266. state->axes[i] = js->buttons[e->index] * 2.f - 1.f;
  1267. }
  1268. return true;
  1269. }
  1270. void _glfw_free_clipboard_data(_GLFWClipboardData *cd) {
  1271. if (cd->mime_types) {
  1272. for (size_t i = 0; i < cd->num_mime_types; i++) free((void*)cd->mime_types[i]);
  1273. free((void*)cd->mime_types);
  1274. }
  1275. memset(cd, 0, sizeof(cd[0]));
  1276. }
  1277. GLFWAPI void glfwGetClipboard(GLFWClipboardType clipboard_type, const char* mime_type, GLFWclipboardwritedatafun write_data, void *object) {
  1278. _GLFW_REQUIRE_INIT();
  1279. _glfwPlatformGetClipboard(clipboard_type, mime_type, write_data, object);
  1280. }
  1281. GLFWAPI void glfwSetClipboardDataTypes(GLFWClipboardType clipboard_type, const char* const *mime_types, size_t num_mime_types, GLFWclipboarditerfun get_data) {
  1282. assert(mime_types != NULL);
  1283. assert(get_data != NULL);
  1284. _GLFW_REQUIRE_INIT();
  1285. _GLFWClipboardData *cd = NULL;
  1286. switch(clipboard_type) {
  1287. case GLFW_CLIPBOARD: cd = &_glfw.clipboard; break;
  1288. case GLFW_PRIMARY_SELECTION: cd = &_glfw.primary; break;
  1289. }
  1290. _glfw_free_clipboard_data(cd);
  1291. cd->get_data = get_data;
  1292. cd->mime_types = calloc(num_mime_types, sizeof(char*));
  1293. cd->num_mime_types = 0;
  1294. cd->ctype = clipboard_type;
  1295. for (size_t i = 0; i < num_mime_types; i++) {
  1296. if (mime_types[i]) {
  1297. cd->mime_types[cd->num_mime_types++] = _glfw_strdup(mime_types[i]);
  1298. }
  1299. }
  1300. _glfwPlatformSetClipboard(clipboard_type);
  1301. }
  1302. GLFWAPI monotonic_t glfwGetTime(void)
  1303. {
  1304. _GLFW_REQUIRE_INIT_OR_RETURN(0);
  1305. return monotonic();
  1306. }