mirror of
https://github.com/gwm17/glfw.git
synced 2024-11-29 21:48:52 -05:00
2a1375e97c
This function allows the creation of cursor objects using one of several standard cursor shapes from the current system cursor theme.
594 lines
18 KiB
Plaintext
594 lines
18 KiB
Plaintext
/*!
|
|
|
|
@page input Input guide
|
|
|
|
@tableofcontents
|
|
|
|
This guide introduces the input related functions of GLFW. There are also
|
|
guides for the other areas of GLFW.
|
|
|
|
- @ref intro
|
|
- @ref window
|
|
- @ref context
|
|
- @ref monitor
|
|
|
|
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 input_event 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 visible windows and is normally
|
|
done each frame after [buffer swapping](@ref window_swap).
|
|
|
|
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 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. These keys still
|
|
have unique, if platform-specific scancodes.
|
|
|
|
The scancode is unique for every key but is platform-specific, so a scancode
|
|
will map to different keys on different platforms.
|
|
|
|
The key will be `GLFW_KEY_UNKNOWN` for special keys like _E-mail_ or _Play_ that
|
|
don't have a key token. Those keys will still have unique, if platform-specific
|
|
scancodes.
|
|
|
|
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
|
|
glfwSetCharCallback(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
|
|
|
|
|
|
@section input_mouse Mouse input
|
|
|
|
Mouse input comes in many forms, including of mouse motion and button presses,
|
|
system cursor appearance and behavior, and two-dimensional scrolling. All of
|
|
these are supported by GLFW.
|
|
|
|
|
|
@subsection input_cursor_pos Cursor position
|
|
|
|
If you wish to be notified when the system cursor moves over the window, set
|
|
a cursor position callback.
|
|
|
|
@code
|
|
glfwSetCursorPosCallback(window, cursor_pos_callback);
|
|
@endcode
|
|
|
|
The callback functions receives the cursor position. 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
|
|
|
|
This function only returns cached cursor positions. It does not poll the
|
|
system for the current position. Whenever you poll state, you risk missing the
|
|
state change you are looking for.
|
|
|
|
|
|
@subsection input_cursor_mode Cursor modes
|
|
|
|
The `GLFW_CURSOR` input mode provides several cursor modes for special forms of
|
|
mouse motion input. By default, the `GLFW_CURSOR_NORMAL` cursor mode is used,
|
|
meaning the regular arrow cursor or a [custom cursor](@ref input_cursor) 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, both via the cursor position callback and via position
|
|
polling.
|
|
|
|
@note You should not implement your own version of this functionality using
|
|
other features of GLFW. It will not work as robustly as `GLFW_CURSOR_DISABLED`,
|
|
as those features are not intended for this purpose.
|
|
|
|
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 input_cursor Cursor objects
|
|
|
|
GLFW supports creating custom system cursor images, encapsulated as @ref
|
|
GLFWcursor objects. They are created with @ref glfwCreateCursor and destroyed
|
|
with @ref glfwDestroyCursor (or @ref glfwTerminate, if any remain).
|
|
|
|
|
|
@subsubsection input_cursor_creation Cursor creation
|
|
|
|
A 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 RGBA, i.e. eight bits per channel. The pixels are
|
|
arranged canonically as sequental rows, starting from the top-left corner.
|
|
|
|
|
|
@subsubsection input_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 input_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 input_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.
|
|
|
|
|
|
@subsubsection input_cursor_standard Standard cursor shapes
|
|
|
|
Cursor objects with platform-specific variants of the
|
|
[standard shapes](@ref shapes) 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 platform provides the cursor image data.
|
|
|
|
|
|
@subsection input_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 input_scroll 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 input_joy 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 input_joy_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 input_joy_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 input_joy_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.
|
|
|
|
|
|
@section input_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.
|
|
|
|
|
|
@section input_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* clipboard = glfwGetClipboardString(window);
|
|
@endcode
|
|
|
|
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 input_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.
|
|
|
|
*/
|