lovr-mouse.lua 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. local ffi = require 'ffi'
  2. local C = ffi.os == 'Windows' and ffi.load('glfw3') or ffi.C
  3. ffi.cdef [[
  4. enum {
  5. GLFW_CURSOR = 0x00033001,
  6. GLFW_CURSOR_NORMAL = 0x00034001,
  7. GLFW_CURSOR_HIDDEN = 0x00034002,
  8. GLFW_CURSOR_DISABLED = 0x00034003,
  9. GLFW_ARROW_CURSOR = 0x00036001,
  10. GLFW_IBEAM_CURSOR = 0x00036002,
  11. GLFW_CROSSHAIR_CURSOR = 0x00036003,
  12. GLFW_HAND_CURSOR = 0x00036004,
  13. GLFW_HRESIZE_CURSOR = 0x00036005,
  14. GLFW_VRESIZE_CURSOR = 0x00036006
  15. };
  16. typedef struct {
  17. int width;
  18. int height;
  19. unsigned char* pixels;
  20. } GLFWimage;
  21. typedef struct GLFWcursor GLFWcursor;
  22. typedef struct GLFWwindow GLFWwindow;
  23. typedef void(*GLFWmousebuttonfun)(GLFWwindow*, int, int, int);
  24. typedef void(*GLFWcursorposfun)(GLFWwindow*, double, double);
  25. typedef void(*GLFWscrollfun)(GLFWwindow*, double, double);
  26. GLFWwindow* os_get_glfw_window(void);
  27. void glfwGetInputMode(GLFWwindow* window, int mode);
  28. void glfwSetInputMode(GLFWwindow* window, int mode, int value);
  29. void glfwGetCursorPos(GLFWwindow* window, double* x, double* y);
  30. void glfwSetCursorPos(GLFWwindow* window, double x, double y);
  31. GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot);
  32. GLFWcursor* glfwCreateStandardCursor(int kind);
  33. void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
  34. int glfwGetMouseButton(GLFWwindow* window, int button);
  35. void glfwGetWindowSize(GLFWwindow* window, int* width, int* height);
  36. GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun callback);
  37. GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun callback);
  38. GLFWcursorposfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback);
  39. ]]
  40. local window = ffi.C.os_get_glfw_window()
  41. local mouse = {}
  42. -- LÖVR uses framebuffer scale for everything, but glfw uses window scale for events.
  43. -- It is necessary to convert between the two at all boundaries.
  44. function mouse.getScale()
  45. local x, _ = ffi.new('int[1]'), ffi.new('int[1]')
  46. C.glfwGetWindowSize(window, x, _)
  47. return lovr.system.getWindowWidth() / x[0]
  48. end
  49. function mouse.getX()
  50. local x = ffi.new('double[1]')
  51. C.glfwGetCursorPos(window, x, nil)
  52. return x[0] * mouse.getScale()
  53. end
  54. function mouse.getY()
  55. local y = ffi.new('double[1]')
  56. C.glfwGetCursorPos(window, nil, y)
  57. return y[0] * mouse.getScale()
  58. end
  59. function mouse.getPosition()
  60. local x, y = ffi.new('double[1]'), ffi.new('double[1]')
  61. local scale = mouse.getScale()
  62. C.glfwGetCursorPos(window, x, y)
  63. return x[0] * scale, y[0] * scale
  64. end
  65. function mouse.setX(x)
  66. local y = mouse.getY()
  67. local scale = mouse.getScale()
  68. C.glfwSetCursorPos(window, x / scale, y / scale)
  69. end
  70. function mouse.setY(y)
  71. local x = mouse.getX()
  72. local scale = mouse.getScale()
  73. C.glfwSetCursorPos(window, x / scale, y / scale)
  74. end
  75. function mouse.setPosition(x, y)
  76. local scale = mouse.getScale()
  77. C.glfwSetCursorPos(window, x / scale, y / scale)
  78. end
  79. function mouse.isDown(button, ...)
  80. if not button then return false end
  81. return C.glfwGetMouseButton(window, button - 1) > 0 or mouse.isDown(...)
  82. end
  83. function mouse.getRelativeMode()
  84. return C.glfwGetInputMode(window, C.GLFW_CURSOR) == C.GLFW_CURSOR_DISABLED
  85. end
  86. function mouse.setRelativeMode(enable)
  87. C.glfwSetInputMode(window, C.GLFW_CURSOR, enable and C.GLFW_CURSOR_DISABLED or C.GLFW_CURSOR_NORMAL)
  88. end
  89. function mouse.newCursor(source, hotx, hoty)
  90. if type(source) == 'string' or tostring(source) == 'Blob' then
  91. source = lovr.data.newImage(source, false)
  92. else
  93. assert(tostring(source) == 'Image', 'Bad argument #1 to newCursor (Image expected)')
  94. end
  95. local image = ffi.new('GLFWimage', source:getWidth(), source:getHeight(), source:getPointer())
  96. return C.glfwCreateCursor(image, hotx or 0, hoty or 0)
  97. end
  98. function mouse.getSystemCursor(kind)
  99. local kinds = {
  100. arrow = C.GLFW_ARROW_CURSOR,
  101. ibeam = C.GLFW_IBEAM_CURSOR,
  102. crosshair = C.GLFW_CROSSHAIR_CURSOR,
  103. hand = C.GLFW_HAND_CURSOR,
  104. sizewe = C.GLFW_HRESIZE_CURSOR,
  105. sizens = C.GLFW_VRESIZE_CURSOR
  106. }
  107. assert(kinds[kind], string.format('Unknown cursor %q', tostring(kind)))
  108. return C.glfwCreateStandardCursor(kinds[kind])
  109. end
  110. function mouse.setCursor(cursor)
  111. C.glfwSetCursor(window, cursor)
  112. end
  113. C.glfwSetMouseButtonCallback(window, function(target, button, action, mods)
  114. if target == window then
  115. local x, y = mouse.getPosition()
  116. lovr.event.push(action > 0 and 'mousepressed' or 'mousereleased', x, y, button + 1, false)
  117. end
  118. end)
  119. local px, py = mouse.getPosition()
  120. C.glfwSetCursorPosCallback(window, function(target, x, y)
  121. if target == window then
  122. local scale = mouse.getScale()
  123. x = x * scale
  124. y = y * scale
  125. lovr.event.push('mousemoved', x, y, x - px, y - py, false)
  126. px, py = x, y
  127. end
  128. end)
  129. C.glfwSetScrollCallback(window, function(target, x, y)
  130. if target == window then
  131. local scale = mouse.getScale()
  132. lovr.event.push('wheelmoved', x * scale, y * scale)
  133. end
  134. end)
  135. return mouse