You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
676 lines
21 KiB
676 lines
21 KiB
/*! |
|
|
|
@page input_guide Input guide |
|
|
|
@tableofcontents |
|
|
|
This guide introduces the input related functions of GLFW. For details on |
|
a specific function in this category, see the @ref input. There are also guides |
|
for the other areas of GLFW. |
|
|
|
- @ref intro_guide |
|
- @ref window_guide |
|
- @ref context_guide |
|
- @ref vulkan_guide |
|
- @ref monitor_guide |
|
|
|
GLFW provides many kinds of input. While some can only be polled, like time, or |
|
only received via callbacks, like scrolling, there are those that provide both |
|
callbacks and polling. Where a callback is provided, that is the recommended |
|
way to receive that kind of input. The more you can use callbacks the less time |
|
your users' machines will need to spend polling. |
|
|
|
All input callbacks receive a window handle. By using the |
|
[window user pointer](@ref window_userptr), you can access non-global structures |
|
or objects from your callbacks. |
|
|
|
To get a better feel for how the various events callbacks behave, run the |
|
`events` test program. It register every callback supported by GLFW and prints |
|
out all arguments provided for every event, along with time and sequence |
|
information. |
|
|
|
|
|
@section events Event processing |
|
|
|
GLFW needs to communicate regularly with the window system both in order to |
|
receive events and to show that the application hasn't locked up. Event |
|
processing must be done regularly while you have any windows and is normally |
|
done each frame after [buffer swapping](@ref buffer_swap). Even when you have |
|
no windows, event polling needs to be done in order to receive monitor |
|
connection events. |
|
|
|
There are two functions for processing pending events. @ref glfwPollEvents, |
|
processes only those events that have already been received and then returns |
|
immediately. |
|
|
|
@code |
|
glfwPollEvents(); |
|
@endcode |
|
|
|
This is the best choice when rendering continually, like most games do. |
|
|
|
If you only need to update the contents of the window when you receive new |
|
input, @ref glfwWaitEvents is a better choice. |
|
|
|
@code |
|
glfwWaitEvents(); |
|
@endcode |
|
|
|
It puts the thread to sleep until at least one event has been received and then |
|
processes all received events. This saves a great deal of CPU cycles and is |
|
useful for, for example, editing tools. There must be at least one GLFW window |
|
for this function to sleep. |
|
|
|
If you want to wait for events but have UI elements that need periodic updates, |
|
call @ref glfwWaitEventsTimeout. |
|
|
|
@code |
|
glfwWaitEventsTimeout(0.7); |
|
@endcode |
|
|
|
It puts the thread to sleep until at least one event has been received, or until |
|
the specified number of seconds have elapsed. It then processes any received |
|
events. |
|
|
|
If the main thread is sleeping in @ref glfwWaitEvents, you can wake it from |
|
another thread by posting an empty event to the event queue with @ref |
|
glfwPostEmptyEvent. |
|
|
|
@code |
|
glfwPostEmptyEvent(); |
|
@endcode |
|
|
|
Do not assume that callbacks will _only_ be called through either of the above |
|
functions. While it is necessary to process events in the event queue, some |
|
window systems will send some events directly to the application, which in turn |
|
causes callbacks to be called outside of regular event processing. |
|
|
|
|
|
@section input_keyboard Keyboard input |
|
|
|
GLFW divides keyboard input into two categories; key events and character |
|
events. Key events relate to actual physical keyboard keys, whereas character |
|
events relate to the Unicode code points generated by pressing some of them. |
|
|
|
Keys and characters do not map 1:1. A single key press may produce several |
|
characters, and a single character may require several keys to produce. This |
|
may not be the case on your machine, but your users are likely not all using the |
|
same keyboard layout, input method or even operating system as you. |
|
|
|
|
|
@subsection input_key Key input |
|
|
|
If you wish to be notified when a physical key is pressed or released or when it |
|
repeats, set a key callback. |
|
|
|
@code |
|
glfwSetKeyCallback(window, key_callback); |
|
@endcode |
|
|
|
The callback function receives the [keyboard key](@ref keys), platform-specific |
|
scancode, key action and [modifier bits](@ref mods). |
|
|
|
@code |
|
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) |
|
{ |
|
if (key == GLFW_KEY_E && action == GLFW_PRESS) |
|
activate_airship(); |
|
} |
|
@endcode |
|
|
|
The action is one of `GLFW_PRESS`, `GLFW_REPEAT` or `GLFW_RELEASE`. The key |
|
will be `GLFW_KEY_UNKNOWN` if GLFW lacks a key token for it, for example |
|
_E-mail_ and _Play_ keys. |
|
|
|
The scancode is unique for every key, regardless of whether it has a key token. |
|
Scancodes are platform-specific but consistent over time, so keys will have |
|
different scancodes depending on the platform but they are safe to save to disk. |
|
|
|
Key states for [named keys](@ref keys) are also saved in per-window state arrays |
|
that can be polled with @ref glfwGetKey. |
|
|
|
@code |
|
int state = glfwGetKey(window, GLFW_KEY_E); |
|
if (state == GLFW_PRESS) |
|
activate_airship(); |
|
@endcode |
|
|
|
The returned state is one of `GLFW_PRESS` or `GLFW_RELEASE`. |
|
|
|
This function only returns cached key event state. It does not poll the |
|
system for the current state of the key. |
|
|
|
Whenever you poll state, you risk missing the state change you are looking for. |
|
If a pressed key is released again before you poll its state, you will have |
|
missed the key press. The recommended solution for this is to use a |
|
key callback, but there is also the `GLFW_STICKY_KEYS` input mode. |
|
|
|
@code |
|
glfwSetInputMode(window, GLFW_STICKY_KEYS, 1); |
|
@endcode |
|
|
|
When sticky keys mode is enabled, the pollable state of a key will remain |
|
`GLFW_PRESS` until the state of that key is polled with @ref glfwGetKey. Once |
|
it has been polled, if a key release event had been processed in the meantime, |
|
the state will reset to `GLFW_RELEASE`, otherwise it will remain `GLFW_PRESS`. |
|
|
|
The `GLFW_KEY_LAST` constant holds the highest value of any |
|
[named key](@ref keys). |
|
|
|
|
|
@subsection input_char Text input |
|
|
|
GLFW supports text input in the form of a stream of |
|
[Unicode code points](https://en.wikipedia.org/wiki/Unicode), as produced by the |
|
operating system text input system. Unlike key input, text input obeys keyboard |
|
layouts and modifier keys and supports composing characters using |
|
[dead keys](https://en.wikipedia.org/wiki/Dead_key). Once received, you can |
|
encode the code points into |
|
[UTF-8](https://en.wikipedia.org/wiki/UTF-8) or any other encoding you prefer. |
|
|
|
Because an `unsigned int` is 32 bits long on all platforms supported by GLFW, |
|
you can treat the code point argument as native endian |
|
[UTF-32](https://en.wikipedia.org/wiki/UTF-32). |
|
|
|
There are two callbacks for receiving Unicode code points. If you wish to |
|
offer regular text input, set a character callback. |
|
|
|
@code |
|
glfwSetCharCallback(window, character_callback); |
|
@endcode |
|
|
|
The callback function receives Unicode code points for key events that would |
|
have led to regular text input and generally behaves as a standard text field on |
|
that platform. |
|
|
|
@code |
|
void character_callback(GLFWwindow* window, unsigned int codepoint) |
|
{ |
|
} |
|
@endcode |
|
|
|
If you wish to receive even those Unicode code points generated with modifier |
|
key combinations that a plain text field would ignore, or just want to know |
|
exactly what modifier keys were used, set a character with modifiers callback. |
|
|
|
@code |
|
glfwSetCharModsCallback(window, charmods_callback); |
|
@endcode |
|
|
|
The callback function receives Unicode code points and |
|
[modifier bits](@ref mods). |
|
|
|
@code |
|
void charmods_callback(GLFWwindow* window, unsigned int codepoint, int mods) |
|
{ |
|
} |
|
@endcode |
|
|
|
|
|
@subsection input_key_name Key names |
|
|
|
If you wish to refer to keys by name, you can query the keyboard layout |
|
dependent name of printable keys with @ref glfwGetKeyName. |
|
|
|
@code |
|
const char* key_name = glfwGetKeyName(GLFW_KEY_W, 0); |
|
show_tutorial_hint("Press %s to move forward", key_name); |
|
@endcode |
|
|
|
This function can handle both [keys and scancodes](@ref input_key). If the |
|
specified key is `GLFW_KEY_UNKNOWN` then the scancode is used, otherwise it is |
|
ignored. This matches the behavior of the key callback, meaning the callback |
|
arguments can always be passed unmodified to this function. |
|
|
|
|
|
@subsection input_key_scancode Key scancodes |
|
|
|
If you need the platform dependent scancode for a [named key](@ref keys), you |
|
can query it with @ref glfwGetKeyScancode. |
|
|
|
@code |
|
const int scancode = glfwGetKeyScancode(GLFW_KEY_X); |
|
set_key_mapping(scancode, swap_weapons); |
|
@endcode |
|
|
|
|
|
@section input_mouse Mouse input |
|
|
|
Mouse input comes in many forms, including cursor motion, button presses and |
|
scrolling offsets. The cursor appearance can also be changed, either to |
|
a custom image or a standard cursor shape from the system theme. |
|
|
|
|
|
@subsection cursor_pos Cursor position |
|
|
|
If you wish to be notified when the cursor moves over the window, set a cursor |
|
position callback. |
|
|
|
@code |
|
glfwSetCursorPosCallback(window, cursor_pos_callback); |
|
@endcode |
|
|
|
The callback functions receives the cursor position, measured in screen |
|
coordinates but relative to the top-left corner of the window client area. On |
|
platforms that provide it, the full sub-pixel cursor position is passed on. |
|
|
|
@code |
|
static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) |
|
{ |
|
} |
|
@endcode |
|
|
|
The cursor position is also saved per-window and can be polled with @ref |
|
glfwGetCursorPos. |
|
|
|
@code |
|
double xpos, ypos; |
|
glfwGetCursorPos(window, &xpos, &ypos); |
|
@endcode |
|
|
|
|
|
@subsection cursor_mode Cursor modes |
|
|
|
The `GLFW_CURSOR` input mode provides several cursor modes for special forms of |
|
mouse motion input. By default, the cursor mode is `GLFW_CURSOR_NORMAL`, |
|
meaning the regular arrow cursor (or another cursor set with @ref glfwSetCursor) |
|
is used and cursor motion is not limited. |
|
|
|
If you wish to implement mouse motion based camera controls or other input |
|
schemes that require unlimited mouse movement, set the cursor mode to |
|
`GLFW_CURSOR_DISABLED`. |
|
|
|
@code |
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); |
|
@endcode |
|
|
|
This will hide the cursor and lock it to the specified window. GLFW will then |
|
take care of all the details of cursor re-centering and offset calculation and |
|
providing the application with a virtual cursor position. This virtual position |
|
is provided normally via both the cursor position callback and through polling. |
|
|
|
@note You should not implement your own version of this functionality using |
|
other features of GLFW. It is not supported and will not work as robustly as |
|
`GLFW_CURSOR_DISABLED`. |
|
|
|
If you just wish the cursor to become hidden when it is over a window, set |
|
the cursor mode to `GLFW_CURSOR_HIDDEN`. |
|
|
|
@code |
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); |
|
@endcode |
|
|
|
This mode puts no limit on the motion of the cursor. |
|
|
|
To exit out of either of these special modes, restore the `GLFW_CURSOR_NORMAL` |
|
cursor mode. |
|
|
|
@code |
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); |
|
@endcode |
|
|
|
|
|
@subsection cursor_object Cursor objects |
|
|
|
GLFW supports creating both custom and system theme cursor images, encapsulated |
|
as @ref GLFWcursor objects. They are created with @ref glfwCreateCursor or @ref |
|
glfwCreateStandardCursor and destroyed with @ref glfwDestroyCursor, or @ref |
|
glfwTerminate, if any remain. |
|
|
|
|
|
@subsubsection cursor_custom Custom cursor creation |
|
|
|
A custom cursor is created with @ref glfwCreateCursor, which returns a handle to |
|
the created cursor object. For example, this creates a 16x16 white square |
|
cursor with the hot-spot in the upper-left corner: |
|
|
|
@code |
|
unsigned char pixels[16 * 16 * 4]; |
|
memset(pixels, 0xff, sizeof(pixels)); |
|
|
|
GLFWimage image; |
|
image.width = 16; |
|
image.height = 16; |
|
image.pixels = pixels; |
|
|
|
GLFWcursor* cursor = glfwCreateCursor(&image, 0, 0); |
|
@endcode |
|
|
|
If cursor creation fails, `NULL` will be returned, so it is necessary to check |
|
the return value. |
|
|
|
The image data is 32-bit, little-endian, non-premultiplied RGBA, i.e. eight bits |
|
per channel. The pixels are arranged canonically as sequential rows, starting |
|
from the top-left corner. |
|
|
|
|
|
@subsubsection cursor_standard Standard cursor creation |
|
|
|
A cursor with a [standard shape](@ref shapes) from the current system cursor |
|
theme can be can be created with @ref glfwCreateStandardCursor. |
|
|
|
@code |
|
GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); |
|
@endcode |
|
|
|
These cursor objects behave in the exact same way as those created with @ref |
|
glfwCreateCursor except that the system cursor theme provides the actual image. |
|
|
|
|
|
@subsubsection cursor_destruction Cursor destruction |
|
|
|
When a cursor is no longer needed, destroy it with @ref glfwDestroyCursor. |
|
|
|
@code |
|
glfwDestroyCursor(cursor); |
|
@endcode |
|
|
|
Cursor destruction always succeeds. All cursors remaining when @ref |
|
glfwTerminate is called are destroyed as well. |
|
|
|
|
|
@subsubsection cursor_set Cursor setting |
|
|
|
A cursor can be set as current for a window with @ref glfwSetCursor. |
|
|
|
@code |
|
glfwSetCursor(window, cursor); |
|
@endcode |
|
|
|
Once set, the cursor image will be used as long as the system cursor is over the |
|
client area of the window and the [cursor mode](@ref cursor_mode) is set |
|
to `GLFW_CURSOR_NORMAL`. |
|
|
|
A single cursor may be set for any number of windows. |
|
|
|
To remove a cursor from a window, set the cursor of that window to `NULL`. |
|
|
|
@code |
|
glfwSetCursor(window, NULL); |
|
@endcode |
|
|
|
When a cursor is destroyed, it is removed from any window where it is set. This |
|
does not affect the cursor modes of those windows. |
|
|
|
|
|
@subsection cursor_enter Cursor enter/leave events |
|
|
|
If you wish to be notified when the cursor enters or leaves the client area of |
|
a window, set a cursor enter/leave callback. |
|
|
|
@code |
|
glfwSetCursorEnterCallback(window, cursor_enter_callback); |
|
@endcode |
|
|
|
The callback function receives the new classification of the cursor. |
|
|
|
@code |
|
void cursor_enter_callback(GLFWwindow* window, int entered) |
|
{ |
|
if (entered) |
|
{ |
|
// The cursor entered the client area of the window |
|
} |
|
else |
|
{ |
|
// The cursor left the client area of the window |
|
} |
|
} |
|
@endcode |
|
|
|
|
|
@subsection input_mouse_button Mouse button input |
|
|
|
If you wish to be notified when a mouse button is pressed or released, set |
|
a mouse button callback. |
|
|
|
@code |
|
glfwSetMouseButtonCallback(window, mouse_button_callback); |
|
@endcode |
|
|
|
The callback function receives the [mouse button](@ref buttons), button action |
|
and [modifier bits](@ref mods). |
|
|
|
@code |
|
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) |
|
{ |
|
if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) |
|
popup_menu(); |
|
} |
|
@endcode |
|
|
|
The action is one of `GLFW_PRESS` or `GLFW_RELEASE`. |
|
|
|
Mouse button states for [named buttons](@ref buttons) are also saved in |
|
per-window state arrays that can be polled with @ref glfwGetMouseButton. |
|
|
|
@code |
|
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT); |
|
if (state == GLFW_PRESS) |
|
upgrade_cow(); |
|
@endcode |
|
|
|
The returned state is one of `GLFW_PRESS` or `GLFW_RELEASE`. |
|
|
|
This function only returns cached mouse button event state. It does not poll |
|
the system for the current state of the mouse button. |
|
|
|
Whenever you poll state, you risk missing the state change you are looking for. |
|
If a pressed mouse button is released again before you poll its state, you will have |
|
missed the button press. The recommended solution for this is to use a |
|
mouse button callback, but there is also the `GLFW_STICKY_MOUSE_BUTTONS` |
|
input mode. |
|
|
|
@code |
|
glfwSetInputMode(window, GLFW_STICKY_MOUSE_BUTTONS, 1); |
|
@endcode |
|
|
|
When sticky mouse buttons mode is enabled, the pollable state of a mouse button |
|
will remain `GLFW_PRESS` until the state of that button is polled with @ref |
|
glfwGetMouseButton. Once it has been polled, if a mouse button release event |
|
had been processed in the meantime, the state will reset to `GLFW_RELEASE`, |
|
otherwise it will remain `GLFW_PRESS`. |
|
|
|
The `GLFW_MOUSE_BUTTON_LAST` constant holds the highest value of any |
|
[named button](@ref buttons). |
|
|
|
|
|
@subsection scrolling Scroll input |
|
|
|
If you wish to be notified when the user scrolls, whether with a mouse wheel or |
|
touchpad gesture, set a scroll callback. |
|
|
|
@code |
|
glfwSetScrollCallback(window, scroll_callback); |
|
@endcode |
|
|
|
The callback function receives two-dimensional scroll offsets. |
|
|
|
@code |
|
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) |
|
{ |
|
} |
|
@endcode |
|
|
|
A simple mouse wheel, being vertical, provides offsets along the Y-axis. |
|
|
|
|
|
@section joystick Joystick input |
|
|
|
The joystick functions expose connected joysticks and controllers, with both |
|
referred to as joysticks. It supports up to sixteen joysticks, ranging from |
|
`GLFW_JOYSTICK_1`, `GLFW_JOYSTICK_2` up to `GLFW_JOYSTICK_LAST`. You can test |
|
whether a [joystick](@ref joysticks) is present with @ref glfwJoystickPresent. |
|
|
|
@code |
|
int present = glfwJoystickPresent(GLFW_JOYSTICK_1); |
|
@endcode |
|
|
|
When GLFW is initialized, detected joysticks are added to to the beginning of |
|
the array, starting with `GLFW_JOYSTICK_1`. Once a joystick is detected, it |
|
keeps its assigned index until it is disconnected, so as joysticks are connected |
|
and disconnected, they will become spread out. |
|
|
|
Joystick state is updated as needed when a joystick function is called and does |
|
not require a window to be created or @ref glfwPollEvents or @ref glfwWaitEvents |
|
to be called. |
|
|
|
|
|
@subsection joystick_axis Joystick axis states |
|
|
|
The positions of all axes of a joystick are returned by @ref |
|
glfwGetJoystickAxes. See the reference documentation for the lifetime of the |
|
returned array. |
|
|
|
@code |
|
int count; |
|
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &count); |
|
@endcode |
|
|
|
Each element in the returned array is a value between -1.0 and 1.0. |
|
|
|
|
|
@subsection joystick_button Joystick button states |
|
|
|
The states of all buttons of a joystick are returned by @ref |
|
glfwGetJoystickButtons. See the reference documentation for the lifetime of the |
|
returned array. |
|
|
|
@code |
|
int count; |
|
const unsigned char* axes = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &count); |
|
@endcode |
|
|
|
Each element in the returned array is either `GLFW_PRESS` or `GLFW_RELEASE`. |
|
|
|
|
|
@subsection joystick_name Joystick name |
|
|
|
The human-readable, UTF-8 encoded name of a joystick is returned by @ref |
|
glfwGetJoystickName. See the reference documentation for the lifetime of the |
|
returned string. |
|
|
|
@code |
|
const char* name = glfwGetJoystickName(GLFW_JOYSTICK_1); |
|
@endcode |
|
|
|
Joystick names are not guaranteed to be unique. Two joysticks of the same model |
|
and make may have the same name. Only the [joystick token](@ref joysticks) is |
|
guaranteed to be unique, and only until that joystick is disconnected. |
|
|
|
|
|
@subsection joystick_event Joystick configuration changes |
|
|
|
If you wish to be notified when a joystick is connected or disconnected, set |
|
a joystick callback. |
|
|
|
@code |
|
glfwSetJoystickCallback(joystick_callback); |
|
@endcode |
|
|
|
The callback function receives the ID of the joystick that has been connected |
|
and disconnected and the event that occurred. |
|
|
|
@code |
|
void joystick_callback(int joy, int event) |
|
{ |
|
if (event == GLFW_CONNECTED) |
|
{ |
|
// The joystick was connected |
|
} |
|
else if (event == GLFW_DISCONNECTED) |
|
{ |
|
// The joystick was disconnected |
|
} |
|
} |
|
@endcode |
|
|
|
|
|
@section time Time input |
|
|
|
GLFW provides high-resolution time input, in seconds, with @ref glfwGetTime. |
|
|
|
@code |
|
double seconds = glfwGetTime(); |
|
@endcode |
|
|
|
It returns the number of seconds since the timer was started when the library |
|
was initialized with @ref glfwInit. The platform-specific time sources used |
|
usually have micro- or nanosecond resolution. |
|
|
|
You can modify the reference time with @ref glfwSetTime. |
|
|
|
@code |
|
glfwSetTime(4.0); |
|
@endcode |
|
|
|
This sets the timer to the specified time, in seconds. |
|
|
|
You can also access the raw timer value, measured in 1 / frequency |
|
seconds, with @ref glfwGetTimerValue. |
|
|
|
@code |
|
uint64_t value = glfwGetTimerValue(); |
|
@endcode |
|
|
|
The frequency of the raw timer varies depending on what time sources are |
|
available on the machine. You can query its frequency, in Hz, with @ref |
|
glfwGetTimerFrequency. |
|
|
|
@code |
|
uint64_t freqency = glfwGetTimerFrequency(); |
|
@endcode |
|
|
|
|
|
@section clipboard Clipboard input and output |
|
|
|
If the system clipboard contains a UTF-8 encoded string or if it can be |
|
converted to one, you can retrieve it with @ref glfwGetClipboardString. See the |
|
reference documentation for the lifetime of the returned string. |
|
|
|
@code |
|
const char* text = glfwGetClipboardString(window); |
|
if (text) |
|
insert_text(text); |
|
@endcode |
|
|
|
If the clipboard is empty or if its contents could not be converted, `NULL` is |
|
returned. |
|
|
|
The contents of the system clipboard can be set to a UTF-8 encoded string with |
|
@ref glfwSetClipboardString. |
|
|
|
@code |
|
glfwSetClipboardString(window, "A string with words in it"); |
|
@endcode |
|
|
|
The clipboard functions take a window handle argument because some window |
|
systems require a window to communicate with the system clipboard. Any valid |
|
window may be used. |
|
|
|
|
|
@section path_drop Path drop input |
|
|
|
If you wish to receive the paths of files and/or directories dropped on |
|
a window, set a file drop callback. |
|
|
|
@code |
|
glfwSetDropCallback(window, drop_callback); |
|
@endcode |
|
|
|
The callback function receives an array of paths encoded as UTF-8. |
|
|
|
@code |
|
void drop_callback(GLFWwindow* window, int count, const char** paths) |
|
{ |
|
int i; |
|
for (i = 0; i < count; i++) |
|
handle_dropped_file(paths[i]); |
|
} |
|
@endcode |
|
|
|
The path array and its strings are only valid until the file drop callback |
|
returns, as they may have been generated specifically for that event. You need |
|
to make a deep copy of the array if you want to keep the paths. |
|
|
|
*/
|
|
|