mirror of
https://github.com/glfw/glfw.git
synced 2024-11-26 22:34:35 +00:00
4a2883b4e2
You can use this feature when you need to manage the drawing of the preedit candidates on the application side.
1243 lines
41 KiB
Markdown
1243 lines
41 KiB
Markdown
# Input guide {#input_guide}
|
||
|
||
[TOC]
|
||
|
||
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, many provide both callbacks and
|
||
polling. Callbacks are more work to use than polling but is less CPU intensive
|
||
and guarantees that you do not miss state changes.
|
||
|
||
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 registers every callback supported by GLFW and prints
|
||
out all arguments provided for every event, along with time and sequence
|
||
information.
|
||
|
||
|
||
## Event processing {#events}
|
||
|
||
GLFW needs to poll the window system for events both to provide input to the
|
||
application and to prove to the window system that the application hasn't locked
|
||
up. Event processing 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 and joystick connection
|
||
events.
|
||
|
||
There are three functions for processing pending events. @ref glfwPollEvents,
|
||
processes only those events that have already been received and then returns
|
||
immediately.
|
||
|
||
```c
|
||
glfwPollEvents();
|
||
```
|
||
|
||
This is the best choice when rendering continuously, 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.
|
||
|
||
```c
|
||
glfwWaitEvents();
|
||
```
|
||
|
||
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.
|
||
|
||
If you want to wait for events but have UI elements or other tasks that need
|
||
periodic updates, @ref glfwWaitEventsTimeout lets you specify a timeout.
|
||
|
||
```c
|
||
glfwWaitEventsTimeout(0.7);
|
||
```
|
||
|
||
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.
|
||
|
||
```c
|
||
glfwPostEmptyEvent();
|
||
```
|
||
|
||
Do not assume that callbacks will _only_ be called in response to the above
|
||
functions. While it is necessary to process events in one or more of the ways
|
||
above, window systems that require GLFW to register callbacks of its own can
|
||
pass events to GLFW in response to many window system function calls. GLFW will
|
||
pass those events on to the application callbacks before returning.
|
||
|
||
For example, on Windows the system function that @ref glfwSetWindowSize is
|
||
implemented with will send window size events directly to the event callback
|
||
that every window has and that GLFW implements for its windows. If you have set
|
||
a [window size callback](@ref window_size) GLFW will call it in turn with the
|
||
new size before everything returns back out of the @ref glfwSetWindowSize call.
|
||
|
||
|
||
## Keyboard input {#input_keyboard}
|
||
|
||
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 text that is 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.
|
||
|
||
|
||
### Key input {#input_key}
|
||
|
||
If you wish to be notified when a physical key is pressed or released or when it
|
||
repeats, set a key callback.
|
||
|
||
```c
|
||
glfwSetKeyCallback(window, key_callback);
|
||
```
|
||
|
||
The callback function receives the [keyboard key](@ref keys), platform-specific
|
||
scancode, key action and [modifier bits](@ref mods).
|
||
|
||
```c
|
||
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||
{
|
||
if (key == GLFW_KEY_E && action == GLFW_PRESS)
|
||
activate_airship();
|
||
}
|
||
```
|
||
|
||
The action is one of `GLFW_PRESS`, `GLFW_REPEAT` or `GLFW_RELEASE`. Events with
|
||
`GLFW_PRESS` and `GLFW_RELEASE` actions are emitted for every key press. Most
|
||
keys will also emit events with `GLFW_REPEAT` actions while a key is held down.
|
||
|
||
Note that many keyboards have a limit on how many keys being simultaneous held
|
||
down that they can detect. This limit is called
|
||
[key rollover](https://en.wikipedia.org/wiki/Key_rollover).
|
||
|
||
Key events with `GLFW_REPEAT` actions are intended for text input. They are
|
||
emitted at the rate set in the user's keyboard settings. At most one key is
|
||
repeated even if several keys are held down. `GLFW_REPEAT` actions should not
|
||
be relied on to know which keys are being held down or to drive animation.
|
||
Instead you should either save the state of relevant keys based on `GLFW_PRESS`
|
||
and `GLFW_RELEASE` actions, or call @ref glfwGetKey, which provides basic cached
|
||
key state.
|
||
|
||
The key will be one of the existing [key tokens](@ref keys), or
|
||
`GLFW_KEY_UNKNOWN` if GLFW lacks a 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.
|
||
You can query the scancode for any [key token](@ref keys) supported on the
|
||
current platform with @ref glfwGetKeyScancode.
|
||
|
||
```c
|
||
const int scancode = glfwGetKeyScancode(GLFW_KEY_X);
|
||
set_key_mapping(scancode, swap_weapons);
|
||
```
|
||
|
||
The last reported state for every physical key with a [key token](@ref keys) is
|
||
also saved in per-window state arrays that can be polled with @ref glfwGetKey.
|
||
|
||
```c
|
||
int state = glfwGetKey(window, GLFW_KEY_E);
|
||
if (state == GLFW_PRESS)
|
||
{
|
||
activate_airship();
|
||
}
|
||
```
|
||
|
||
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 physical key. It also does not provide any
|
||
key repeat information.
|
||
|
||
@anchor GLFW_STICKY_KEYS
|
||
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.
|
||
|
||
```c
|
||
glfwSetInputMode(window, GLFW_STICKY_KEYS, GLFW_TRUE);
|
||
```
|
||
|
||
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`.
|
||
|
||
@anchor GLFW_LOCK_KEY_MODS
|
||
If you wish to know what the state of the Caps Lock and Num Lock keys was when
|
||
input events were generated, set the `GLFW_LOCK_KEY_MODS` input mode.
|
||
|
||
```c
|
||
glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, GLFW_TRUE);
|
||
```
|
||
|
||
When this input mode is enabled, any callback that receives
|
||
[modifier bits](@ref mods) will have the @ref GLFW_MOD_CAPS_LOCK bit set if Caps
|
||
Lock was on when the event occurred and the @ref GLFW_MOD_NUM_LOCK bit set if
|
||
Num Lock was on.
|
||
|
||
The `GLFW_KEY_LAST` constant holds the highest value of any
|
||
[key token](@ref keys).
|
||
|
||
|
||
### Text input {#input_char}
|
||
|
||
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 is affected by
|
||
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 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.
|
||
|
||
If you wish to offer regular text input, set a character callback.
|
||
|
||
```c
|
||
glfwSetCharCallback(window, character_callback);
|
||
```
|
||
|
||
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.
|
||
|
||
```c
|
||
void character_callback(GLFWwindow* window, unsigned int codepoint)
|
||
{
|
||
}
|
||
```
|
||
|
||
|
||
### Key names {#input_key_name}
|
||
|
||
If you wish to refer to keys by name, you can query the keyboard layout
|
||
dependent name of printable keys with @ref glfwGetKeyName.
|
||
|
||
```c
|
||
const char* key_name = glfwGetKeyName(GLFW_KEY_W, 0);
|
||
show_tutorial_hint("Press %s to move forward", key_name);
|
||
```
|
||
|
||
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.
|
||
|
||
|
||
@section ime_support IME support
|
||
|
||
IME (Input Method Editor/Engine) is used to input characters not mapped with
|
||
physical keys. It is popular among East Asian people.
|
||
|
||
|
||
@subsection ime_style IME styles
|
||
|
||
GLFW supports the following two styles of IME.
|
||
|
||
- On-the-spot
|
||
- Over-the-spot
|
||
|
||
On-the-spot style is supported on Windows, macOS and Wayland. On these platforms,
|
||
applications need to draw preedit text directly in their UI by using the preedit
|
||
callback (See [Preedit input](@ref input_preedit)).
|
||
|
||
Over-the-spot style is supported on X11. On this platform, the IME displays preedit
|
||
text, and applications don't need to draw it. So the preedit callback doesn't work
|
||
on X11.
|
||
|
||
In both styles, applications should manage the position of the candidate window.
|
||
See [Candidate window](@ref candidate_window) for details.
|
||
|
||
@note
|
||
@x11 You can use on-the-spot style also on X11 by using @ref GLFW_X11_ONTHESPOT_hint.
|
||
In this case, the preedit callback also works on X11. However, on-the-spot style on
|
||
X11 is unstable, so it is not recommended.
|
||
|
||
|
||
@subsection input_preedit Preedit input
|
||
|
||
When inputting text with IME, the text is temporarily inputted, then conversion
|
||
and other processing are performed and finally committed. The committed text is
|
||
inputted in the same way as input without IME (See [Text input](@ref input_char)).
|
||
|
||
This temporary input is called "preedit" or "pre-edit".
|
||
|
||
On Windows, macOS and Wayland, that use on-the-spot sytle, applications need to
|
||
take preedit information and draw it in their UI.
|
||
|
||
You can register the preedit callback as follows.
|
||
|
||
@code
|
||
glfwSetPreeditCallback(window, preedit_callback);
|
||
@endcode
|
||
|
||
The callback receives the following information.
|
||
|
||
@code
|
||
void preedit_callback(GLFWwindow* window,
|
||
int preedit_count,
|
||
unsigned int* preedit_string,
|
||
int block_count,
|
||
int* block_sizes,
|
||
int focused_block,
|
||
int caret)
|
||
{
|
||
}
|
||
@endcode
|
||
|
||
"preedit_count" and "preedit_string" parameter represent the whole preedit text.
|
||
Each character of the preedit string is a native endian UTF-32 like @ref input_char.
|
||
|
||
If you want to type the text "寿司(sushi)", Usually the callback is called several
|
||
times like the following sequence:
|
||
|
||
-# key event: s
|
||
-# preedit: [preedit_string: "s", block_sizes: [1], focused_block: 0]
|
||
-# key event: u
|
||
-# preedit: [preedit_string: "す", block_sizes: [1], focused_block: 0]
|
||
-# key event: s
|
||
-# preedit: [preedit_string: "すs", block_sizes: [2], focused_block: 0]
|
||
-# key event: h
|
||
-# preedit: [preedit_string: "すsh", block_sizes: [3], focused_block: 0]
|
||
-# key event: i
|
||
-# preedit: [preedit_string: "すし", block_sizes: [2], focused_block: 0]
|
||
-# key event: ' '
|
||
-# preedit: [preedit_string: "寿司", block_sizes: [2], focused_block: 0]
|
||
-# char: '寿'
|
||
-# char: '司'
|
||
-# preedit: [preedit_string: "", block_sizes: [], focused_block: 0]
|
||
|
||
If preedit text includes several semantic blocks, the callback returns several blocks:
|
||
|
||
-# preedit: [preedit_string: "わたしはすしをたべます", block_sizes: [11], focused_block: 0]
|
||
-# preedit: [preedit_string: "私は寿司を食べます", block_sizes: [2, 7], focused_block: 1]
|
||
|
||
"block_sizes" is a list of the sizes of each block. The above case, it contains the following
|
||
blocks and the second block is focused.
|
||
|
||
- 私は
|
||
- [寿司を食べます]
|
||
|
||
The application side should draw a focused block and unfocused blocks
|
||
in different styles.
|
||
|
||
You can use the "caret" parameter to draw the caret of the preedit text.
|
||
The specification of this parameter depends on the specification of the input method.
|
||
The following is an example on Win32.
|
||
|
||
- "あいうえお|" (caret: 5)
|
||
- key event: arrow-left
|
||
- "あいうえ|お" (caret: 4)
|
||
- ...
|
||
- "|あいうえお" (caret: 0)
|
||
|
||
|
||
@subsection candidate_window Candidate window
|
||
|
||
The application has to manage the position of the candidate window that shows
|
||
the preedit candidate list. To do this, the application has to manage the area
|
||
of the preedit text cursor by the following functions. The IME displays the
|
||
candidate window in the appropriate position based on the area of the preedit
|
||
text cursor.
|
||
|
||
@code
|
||
glfwSetPreeditCursorRectangle(window, x, y, w, h);
|
||
glfwGetPreeditCursorRectangle(window, &x, &y, &w, &h);
|
||
@endcode
|
||
|
||
|
||
@subsection ime_status IME status
|
||
|
||
Sometimes, IME task needs to be interrupted by a user or an application. There
|
||
are several functions to support these situations.
|
||
|
||
@note
|
||
@x11 @wayland This feature is not supported.
|
||
|
||
You can receive notification about IME status change(on/off) by using the following
|
||
function:
|
||
|
||
@code
|
||
glfwSetIMEStatusCallback(window, imestatus_callback);
|
||
@endcode
|
||
|
||
The callback has a simple signature like this:
|
||
|
||
@code
|
||
void imestatus_callback(GLFWwindow* window)
|
||
{
|
||
}
|
||
@endcode
|
||
|
||
@anchor GLFW_IME
|
||
You can get the current IME status by the following function:
|
||
|
||
@code
|
||
glfwGetInputMode(window, GLFW_IME);
|
||
@endcode
|
||
|
||
If you get GLFW_TRUE, it means the IME is on, and GLFW_FALSE means the IME is off.
|
||
|
||
You can also change the IME status by the following function:
|
||
|
||
@code
|
||
glfwSetInputMode(window, GLFW_IME, GLFW_TRUE);
|
||
glfwSetInputMode(window, GLFW_IME, GLFW_FALSE);
|
||
@endcode
|
||
|
||
You can use the following function to clear the current preedit.
|
||
|
||
@code
|
||
glfwResetPreeditText(window);
|
||
@endcode
|
||
|
||
|
||
@subsection manage_preedit_candidate Manage preedit candidate
|
||
|
||
By default, the IME manages the drawing of the preedit candidates, but
|
||
sometimes you need to do that on the application side for some reason. In such
|
||
a case, you can use
|
||
[GLFW_MANAGE_PREEDIT_CANDIDATE](@ref GLFW_MANAGE_PREEDIT_CANDIDATE_hint) init hint.
|
||
By setting this to `GLFW_TRUE`, the IME stops managing the drawing of the
|
||
candidates and the application needs to manage it by using the following
|
||
functions.
|
||
|
||
@note
|
||
@win32 Only the OS currently supports this hint.
|
||
|
||
You can register the candidate callback as follows.
|
||
|
||
@code
|
||
glfwSetPreeditCandidateCallback(window, candidate_callback);
|
||
@endcode
|
||
|
||
The callback receives the following information.
|
||
|
||
@code
|
||
void candidate_callback(GLFWwindow* window,
|
||
int candidates_count,
|
||
int selected_index,
|
||
int page_start,
|
||
int page_size)
|
||
{
|
||
}
|
||
@endcode
|
||
|
||
`candidates_count` is the number of total candidates. `selected_index` is the
|
||
index of the currently selected candidate. Normally all candidates should not
|
||
be displayed at once, but divided into pages. You can use `page_start` and
|
||
`page_size` to manage the pages. `page_start` is the index of the first
|
||
candidate on the current page. `page_size` is the number of the candidates on
|
||
the current page.
|
||
|
||
You can get the text of the candidate on the specific index as follows. Each
|
||
character of the returned text is a native endian UTF-32.
|
||
|
||
@code
|
||
int text_count;
|
||
unsigned int* text = glfwGetPreeditCandidate(window, index, &text_count);
|
||
@endcode
|
||
|
||
A sample code to get all candidate texts on the current page is as follows.
|
||
|
||
@code
|
||
void candidate_callback(GLFWwindow* window, int candidates_count,
|
||
int selected_index, int page_start, int page_size)
|
||
{
|
||
int i, j;
|
||
for (i = 0; i < page_size; ++i)
|
||
{
|
||
int index = i + page_start;
|
||
int text_count;
|
||
unsigned int* text = glfwGetPreeditCandidate(window, index, &text_count);
|
||
if (index == selected_index)
|
||
printf("> ");
|
||
for (j = 0; j < text_count; ++j)
|
||
{
|
||
char encoded[5] = "";
|
||
encode_utf8(encoded, text[j]); // Some kind of encoding process
|
||
printf("%s", encoded);
|
||
}
|
||
printf("\n");
|
||
}
|
||
}
|
||
|
||
glfwSetPreeditCandidateCallback(window, candidate_callback);
|
||
@endcode
|
||
|
||
|
||
## Mouse input {#input_mouse}
|
||
|
||
Mouse input comes in many forms, including mouse 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.
|
||
|
||
|
||
### Cursor position {#cursor_pos}
|
||
|
||
If you wish to be notified when the cursor moves over the window, set a cursor
|
||
position callback.
|
||
|
||
```c
|
||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||
```
|
||
|
||
The callback functions receives the cursor position, measured in screen
|
||
coordinates but relative to the top-left corner of the window content area. On
|
||
platforms that provide it, the full sub-pixel cursor position is passed on.
|
||
|
||
```c
|
||
static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
|
||
{
|
||
}
|
||
```
|
||
|
||
The cursor position is also saved per-window and can be polled with @ref
|
||
glfwGetCursorPos.
|
||
|
||
```c
|
||
double xpos, ypos;
|
||
glfwGetCursorPos(window, &xpos, &ypos);
|
||
```
|
||
|
||
|
||
### Cursor mode {#cursor_mode}
|
||
|
||
@anchor GLFW_CURSOR
|
||
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`.
|
||
|
||
```c
|
||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||
```
|
||
|
||
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 only wish the cursor to become hidden when it is over a window but still
|
||
want it to behave normally, set the cursor mode to `GLFW_CURSOR_HIDDEN`.
|
||
|
||
```c
|
||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||
```
|
||
|
||
This mode puts no limit on the motion of the cursor.
|
||
|
||
If you wish the cursor to be visible but confined to the content area of the
|
||
window, set the cursor mode to `GLFW_CURSOR_CAPTURED`.
|
||
|
||
```c
|
||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED);
|
||
```
|
||
|
||
The cursor will behave normally inside the content area but will not be able to
|
||
leave unless the window loses focus.
|
||
|
||
To exit out of either of these special modes, restore the `GLFW_CURSOR_NORMAL`
|
||
cursor mode.
|
||
|
||
```c
|
||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||
```
|
||
|
||
If the cursor was disabled, this will move it back to its last visible position.
|
||
|
||
|
||
@anchor GLFW_RAW_MOUSE_MOTION
|
||
### Raw mouse motion {#raw_mouse_motion}
|
||
|
||
When the cursor is disabled, raw (unscaled and unaccelerated) mouse motion can
|
||
be enabled if available.
|
||
|
||
Raw mouse motion is closer to the actual motion of the mouse across a surface.
|
||
It is not affected by the scaling and acceleration applied to the motion of the
|
||
desktop cursor. That processing is suitable for a cursor while raw motion is
|
||
better for controlling for example a 3D camera. Because of this, raw mouse
|
||
motion is only provided when the cursor is disabled.
|
||
|
||
Call @ref glfwRawMouseMotionSupported to check if the current machine provides
|
||
raw motion and set the `GLFW_RAW_MOUSE_MOTION` input mode to enable it. It is
|
||
disabled by default.
|
||
|
||
```c
|
||
if (glfwRawMouseMotionSupported())
|
||
glfwSetInputMode(window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE);
|
||
```
|
||
|
||
If supported, raw mouse motion can be enabled or disabled per-window and at any
|
||
time but it will only be provided when the cursor is disabled.
|
||
|
||
|
||
### Cursor objects {#cursor_object}
|
||
|
||
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.
|
||
|
||
|
||
#### Custom cursor creation {#cursor_custom}
|
||
|
||
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:
|
||
|
||
```c
|
||
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);
|
||
```
|
||
|
||
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 with the red channel first. The pixels are arranged canonically as
|
||
sequential rows, starting from the top-left corner.
|
||
|
||
|
||
#### Standard cursor creation {#cursor_standard}
|
||
|
||
A cursor with a [standard shape](@ref shapes) from the current system cursor
|
||
theme can be created with @ref glfwCreateStandardCursor.
|
||
|
||
```c
|
||
GLFWcursor* url_cursor = glfwCreateStandardCursor(GLFW_POINTING_HAND_CURSOR);
|
||
```
|
||
|
||
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.
|
||
|
||
A few of these shapes are not available everywhere. If a shape is unavailable,
|
||
`NULL` is returned. See @ref glfwCreateStandardCursor for details.
|
||
|
||
|
||
#### Cursor destruction {#cursor_destruction}
|
||
|
||
When a cursor is no longer needed, destroy it with @ref glfwDestroyCursor.
|
||
|
||
```c
|
||
glfwDestroyCursor(cursor);
|
||
```
|
||
|
||
Cursor destruction always succeeds. If the cursor is current for any window,
|
||
that window will revert to the default cursor. This does not affect the cursor
|
||
mode. All remaining cursors are destroyed when @ref glfwTerminate is called.
|
||
|
||
|
||
#### Cursor setting {#cursor_set}
|
||
|
||
A cursor can be set as current for a window with @ref glfwSetCursor.
|
||
|
||
```c
|
||
glfwSetCursor(window, cursor);
|
||
```
|
||
|
||
Once set, the cursor image will be used as long as the system cursor is over the
|
||
content 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 revert to the default cursor, set the cursor of that window to `NULL`.
|
||
|
||
```c
|
||
glfwSetCursor(window, NULL);
|
||
```
|
||
|
||
When a cursor is destroyed, any window that has it set will revert to the
|
||
default cursor. This does not affect the cursor mode.
|
||
|
||
|
||
### Cursor enter/leave events {#cursor_enter}
|
||
|
||
If you wish to be notified when the cursor enters or leaves the content area of
|
||
a window, set a cursor enter/leave callback.
|
||
|
||
```c
|
||
glfwSetCursorEnterCallback(window, cursor_enter_callback);
|
||
```
|
||
|
||
The callback function receives the new classification of the cursor.
|
||
|
||
```c
|
||
void cursor_enter_callback(GLFWwindow* window, int entered)
|
||
{
|
||
if (entered)
|
||
{
|
||
// The cursor entered the content area of the window
|
||
}
|
||
else
|
||
{
|
||
// The cursor left the content area of the window
|
||
}
|
||
}
|
||
```
|
||
|
||
You can query whether the cursor is currently inside the content area of the
|
||
window with the [GLFW_HOVERED](@ref GLFW_HOVERED_attrib) window attribute.
|
||
|
||
```c
|
||
if (glfwGetWindowAttrib(window, GLFW_HOVERED))
|
||
{
|
||
highlight_interface();
|
||
}
|
||
```
|
||
|
||
|
||
### Mouse button input {#input_mouse_button}
|
||
|
||
If you wish to be notified when a mouse button is pressed or released, set
|
||
a mouse button callback.
|
||
|
||
```c
|
||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||
```
|
||
|
||
@anchor GLFW_UNLIMITED_MOUSE_BUTTONS
|
||
To handle all mouse buttons in the callback, instead of only ones with associated
|
||
[button tokens](@ref buttons), set the @ref GLFW_UNLIMITED_MOUSE_BUTTONS
|
||
input mode.
|
||
|
||
```c
|
||
glfwSetInputMode(window, GLFW_UNLIMITED_MOUSE_BUTTONS, GLFW_TRUE);
|
||
```
|
||
|
||
When this input mode is enabled, GLFW doesn't limit the reported mouse buttons
|
||
to only those that have an associated button token, for compatibility with
|
||
earlier versions of GLFW, which never reported any buttons over
|
||
@ref GLFW_MOUSE_BUTTON_LAST, on which users could have relied on.
|
||
|
||
The callback function receives the [mouse button](@ref buttons), button action
|
||
and [modifier bits](@ref mods).
|
||
|
||
```c
|
||
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
|
||
{
|
||
if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
|
||
popup_menu();
|
||
}
|
||
```
|
||
|
||
The mouse button is an integer that can be one of the
|
||
[mouse button tokens](@ref buttons) or, if the
|
||
@ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode is set, any other positive value.
|
||
|
||
The action is one of `GLFW_PRESS` or `GLFW_RELEASE`.
|
||
|
||
The last reported state for every [mouse button token](@ref buttons) is also
|
||
saved in per-window state arrays that can be polled with @ref
|
||
glfwGetMouseButton. This is not effected by the @ref GLFW_UNLIMITED_MOUSE_BUTTONS
|
||
input mode.
|
||
|
||
```c
|
||
int state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
|
||
if (state == GLFW_PRESS)
|
||
{
|
||
upgrade_cow();
|
||
}
|
||
```
|
||
|
||
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.
|
||
|
||
@anchor GLFW_STICKY_MOUSE_BUTTONS
|
||
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.
|
||
|
||
```c
|
||
glfwSetInputMode(window, GLFW_STICKY_MOUSE_BUTTONS, GLFW_TRUE);
|
||
```
|
||
|
||
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
|
||
[mouse button token](@ref buttons).
|
||
|
||
|
||
### Scroll input {#scrolling}
|
||
|
||
If you wish to be notified when the user scrolls, whether with a mouse wheel or
|
||
touchpad gesture, set a scroll callback.
|
||
|
||
```c
|
||
glfwSetScrollCallback(window, scroll_callback);
|
||
```
|
||
|
||
The callback function receives two-dimensional scroll offsets.
|
||
|
||
```c
|
||
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
|
||
{
|
||
}
|
||
```
|
||
|
||
A normal mouse wheel, being vertical, provides offsets along the Y-axis.
|
||
|
||
|
||
## Joystick input {#joystick}
|
||
|
||
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 and including `GLFW_JOYSTICK_16` or
|
||
`GLFW_JOYSTICK_LAST`. You can test whether a [joystick](@ref joysticks) is
|
||
present with @ref glfwJoystickPresent.
|
||
|
||
```c
|
||
int present = glfwJoystickPresent(GLFW_JOYSTICK_1);
|
||
```
|
||
|
||
Each joystick has zero or more axes, zero or more buttons, zero or more hats,
|
||
a human-readable name, a user pointer and an SDL compatible GUID.
|
||
|
||
Detected joysticks are added to the beginning of the array. Once a joystick is
|
||
detected, it keeps its assigned ID until it is disconnected or the library is
|
||
terminated, so as joysticks are connected and disconnected, there may appear
|
||
gaps in the IDs.
|
||
|
||
Joystick axis, button and hat state is updated when polled and does not require
|
||
a window to be created or events to be processed. However, if you want joystick
|
||
connection and disconnection events reliably delivered to the
|
||
[joystick callback](@ref joystick_event) then you must
|
||
[process events](@ref events).
|
||
|
||
To see all the properties of all connected joysticks in real-time, run the
|
||
`joysticks` test program.
|
||
|
||
|
||
### Joystick axis states {#joystick_axis}
|
||
|
||
The positions of all axes of a joystick are returned by @ref
|
||
glfwGetJoystickAxes. See the reference documentation for the lifetime of the
|
||
returned array.
|
||
|
||
```c
|
||
int count;
|
||
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_5, &count);
|
||
```
|
||
|
||
Each element in the returned array is a value between -1.0 and 1.0.
|
||
|
||
|
||
### Joystick button states {#joystick_button}
|
||
|
||
The states of all buttons of a joystick are returned by @ref
|
||
glfwGetJoystickButtons. See the reference documentation for the lifetime of the
|
||
returned array.
|
||
|
||
```c
|
||
int count;
|
||
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_3, &count);
|
||
```
|
||
|
||
Each element in the returned array is either `GLFW_PRESS` or `GLFW_RELEASE`.
|
||
|
||
For backward compatibility with earlier versions that did not have @ref
|
||
glfwGetJoystickHats, the button array by default also includes all hats. See
|
||
the reference documentation for @ref glfwGetJoystickButtons for details.
|
||
|
||
|
||
### Joystick hat states {#joystick_hat}
|
||
|
||
The states of all hats are returned by @ref glfwGetJoystickHats. See the
|
||
reference documentation for the lifetime of the returned array.
|
||
|
||
```c
|
||
int count;
|
||
const unsigned char* hats = glfwGetJoystickHats(GLFW_JOYSTICK_7, &count);
|
||
```
|
||
|
||
Each element in the returned array is one of the following:
|
||
|
||
Name | Value
|
||
---- | -----
|
||
`GLFW_HAT_CENTERED` | 0
|
||
`GLFW_HAT_UP` | 1
|
||
`GLFW_HAT_RIGHT` | 2
|
||
`GLFW_HAT_DOWN` | 4
|
||
`GLFW_HAT_LEFT` | 8
|
||
`GLFW_HAT_RIGHT_UP` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_UP`
|
||
`GLFW_HAT_RIGHT_DOWN` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_DOWN`
|
||
`GLFW_HAT_LEFT_UP` | `GLFW_HAT_LEFT` \| `GLFW_HAT_UP`
|
||
`GLFW_HAT_LEFT_DOWN` | `GLFW_HAT_LEFT` \| `GLFW_HAT_DOWN`
|
||
|
||
The diagonal directions are bitwise combinations of the primary (up, right, down
|
||
and left) directions and you can test for these individually by ANDing it with
|
||
the corresponding direction.
|
||
|
||
```c
|
||
if (hats[2] & GLFW_HAT_RIGHT)
|
||
{
|
||
// State of hat 2 could be right-up, right or right-down
|
||
}
|
||
```
|
||
|
||
For backward compatibility with earlier versions that did not have @ref
|
||
glfwGetJoystickHats, all hats are by default also included in the button array.
|
||
See the reference documentation for @ref glfwGetJoystickButtons for details.
|
||
|
||
|
||
### 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.
|
||
|
||
```c
|
||
const char* name = glfwGetJoystickName(GLFW_JOYSTICK_4);
|
||
```
|
||
|
||
Joystick names are not guaranteed to be unique. Two joysticks of the same model
|
||
and make may have the same name. Only the [joystick ID](@ref joysticks) is
|
||
guaranteed to be unique, and only until that joystick is disconnected.
|
||
|
||
|
||
### Joystick user pointer {#joystick_userptr}
|
||
|
||
Each joystick has a user pointer that can be set with @ref
|
||
glfwSetJoystickUserPointer and queried with @ref glfwGetJoystickUserPointer.
|
||
This can be used for any purpose you need and will not be modified by GLFW. The
|
||
value will be kept until the joystick is disconnected or until the library is
|
||
terminated.
|
||
|
||
The initial value of the pointer is `NULL`.
|
||
|
||
|
||
### Joystick configuration changes {#joystick_event}
|
||
|
||
If you wish to be notified when a joystick is connected or disconnected, set
|
||
a joystick callback.
|
||
|
||
```c
|
||
glfwSetJoystickCallback(joystick_callback);
|
||
```
|
||
|
||
The callback function receives the ID of the joystick that has been connected
|
||
and disconnected and the event that occurred.
|
||
|
||
```c
|
||
void joystick_callback(int jid, int event)
|
||
{
|
||
if (event == GLFW_CONNECTED)
|
||
{
|
||
// The joystick was connected
|
||
}
|
||
else if (event == GLFW_DISCONNECTED)
|
||
{
|
||
// The joystick was disconnected
|
||
}
|
||
}
|
||
```
|
||
|
||
For joystick connection and disconnection events to be delivered on all
|
||
platforms, you need to call one of the [event processing](@ref events)
|
||
functions. Joystick disconnection may also be detected and the callback
|
||
called by joystick functions. The function will then return whatever it
|
||
returns for a disconnected joystick.
|
||
|
||
Only @ref glfwGetJoystickName and @ref glfwGetJoystickUserPointer will return
|
||
useful values for a disconnected joystick and only before the monitor callback
|
||
returns.
|
||
|
||
|
||
### Gamepad input {#gamepad}
|
||
|
||
The joystick functions provide unlabeled axes, buttons and hats, with no
|
||
indication of where they are located on the device. Their order may also vary
|
||
between platforms even with the same device.
|
||
|
||
To solve this problem the SDL community crowdsourced the
|
||
[SDL_GameControllerDB][] project, a database of mappings from many different
|
||
devices to an Xbox-like gamepad.
|
||
|
||
[SDL_GameControllerDB]: https://github.com/gabomdq/SDL_GameControllerDB
|
||
|
||
GLFW supports this mapping format and contains a copy of the mappings
|
||
available at the time of release. See @ref gamepad_mapping for how to update
|
||
this at runtime. Mappings will be assigned to joysticks automatically any time
|
||
a joystick is connected or the mappings are updated.
|
||
|
||
You can check whether a joystick is both present and has a gamepad mapping with
|
||
@ref glfwJoystickIsGamepad.
|
||
|
||
```c
|
||
if (glfwJoystickIsGamepad(GLFW_JOYSTICK_2))
|
||
{
|
||
// Use as gamepad
|
||
}
|
||
```
|
||
|
||
If you are only interested in gamepad input you can use this function instead of
|
||
@ref glfwJoystickPresent.
|
||
|
||
You can query the human-readable name provided by the gamepad mapping with @ref
|
||
glfwGetGamepadName. This may or may not be the same as the
|
||
[joystick name](@ref joystick_name).
|
||
|
||
```c
|
||
const char* name = glfwGetGamepadName(GLFW_JOYSTICK_7);
|
||
```
|
||
|
||
To retrieve the gamepad state of a joystick, call @ref glfwGetGamepadState.
|
||
|
||
```c
|
||
GLFWgamepadstate state;
|
||
|
||
if (glfwGetGamepadState(GLFW_JOYSTICK_3, &state))
|
||
{
|
||
if (state.buttons[GLFW_GAMEPAD_BUTTON_A])
|
||
{
|
||
input_jump();
|
||
}
|
||
|
||
input_speed(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER]);
|
||
}
|
||
```
|
||
|
||
The @ref GLFWgamepadstate struct has two arrays; one for button states and one
|
||
for axis states. The values for each button and axis are the same as for the
|
||
@ref glfwGetJoystickButtons and @ref glfwGetJoystickAxes functions, i.e.
|
||
`GLFW_PRESS` or `GLFW_RELEASE` for buttons and -1.0 to 1.0 inclusive for axes.
|
||
|
||
The sizes of the arrays and the positions within each array are fixed.
|
||
|
||
The [button indices](@ref gamepad_buttons) are `GLFW_GAMEPAD_BUTTON_A`,
|
||
`GLFW_GAMEPAD_BUTTON_B`, `GLFW_GAMEPAD_BUTTON_X`, `GLFW_GAMEPAD_BUTTON_Y`,
|
||
`GLFW_GAMEPAD_BUTTON_LEFT_BUMPER`, `GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER`,
|
||
`GLFW_GAMEPAD_BUTTON_BACK`, `GLFW_GAMEPAD_BUTTON_START`,
|
||
`GLFW_GAMEPAD_BUTTON_GUIDE`, `GLFW_GAMEPAD_BUTTON_LEFT_THUMB`,
|
||
`GLFW_GAMEPAD_BUTTON_RIGHT_THUMB`, `GLFW_GAMEPAD_BUTTON_DPAD_UP`,
|
||
`GLFW_GAMEPAD_BUTTON_DPAD_RIGHT`, `GLFW_GAMEPAD_BUTTON_DPAD_DOWN` and
|
||
`GLFW_GAMEPAD_BUTTON_DPAD_LEFT`.
|
||
|
||
For those who prefer, there are also the `GLFW_GAMEPAD_BUTTON_CROSS`,
|
||
`GLFW_GAMEPAD_BUTTON_CIRCLE`, `GLFW_GAMEPAD_BUTTON_SQUARE` and
|
||
`GLFW_GAMEPAD_BUTTON_TRIANGLE` aliases for the A, B, X and Y button indices.
|
||
|
||
The [axis indices](@ref gamepad_axes) are `GLFW_GAMEPAD_AXIS_LEFT_X`,
|
||
`GLFW_GAMEPAD_AXIS_LEFT_Y`, `GLFW_GAMEPAD_AXIS_RIGHT_X`,
|
||
`GLFW_GAMEPAD_AXIS_RIGHT_Y`, `GLFW_GAMEPAD_AXIS_LEFT_TRIGGER` and
|
||
`GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER`.
|
||
|
||
The `GLFW_GAMEPAD_BUTTON_LAST` and `GLFW_GAMEPAD_AXIS_LAST` constants equal
|
||
the largest available index for each array.
|
||
|
||
|
||
### Gamepad mappings {#gamepad_mapping}
|
||
|
||
GLFW contains a copy of the mappings available in [SDL_GameControllerDB][] at
|
||
the time of release. Newer ones can be added at runtime with @ref
|
||
glfwUpdateGamepadMappings.
|
||
|
||
```c
|
||
const char* mappings = load_file_contents("game/data/gamecontrollerdb.txt");
|
||
|
||
glfwUpdateGamepadMappings(mappings);
|
||
```
|
||
|
||
This function supports everything from single lines up to and including the
|
||
unmodified contents of the whole `gamecontrollerdb.txt` file.
|
||
|
||
If you are compiling GLFW from source with CMake you can update the built-in mappings by
|
||
building the _update_mappings_ target. This runs the `GenerateMappings.cmake` CMake
|
||
script, which downloads `gamecontrollerdb.txt` and regenerates the `mappings.h` header
|
||
file.
|
||
|
||
Below is a description of the mapping format. Please keep in mind that __this
|
||
description is not authoritative__. The format is defined by the SDL and
|
||
SDL_GameControllerDB projects and their documentation and code takes precedence.
|
||
|
||
Each mapping is a single line of comma-separated values describing the GUID,
|
||
name and layout of the gamepad. Lines that do not begin with a hexadecimal
|
||
digit are ignored.
|
||
|
||
The first value is always the gamepad GUID, a 32 character long hexadecimal
|
||
string that typically identifies its make, model, revision and the type of
|
||
connection to the computer. When this information is not available, the GUID is
|
||
generated using the gamepad name. GLFW uses the SDL 2.0.5+ GUID format but can
|
||
convert from the older formats.
|
||
|
||
The second value is always the human-readable name of the gamepad.
|
||
|
||
All subsequent values are in the form `<field>:<value>` and describe the layout
|
||
of the mapping. These fields may not all be present and may occur in any order.
|
||
|
||
The button fields are `a`, `b`, `x`, `y`, `back`, `start`, `guide`, `dpup`,
|
||
`dpright`, `dpdown`, `dpleft`, `leftshoulder`, `rightshoulder`, `leftstick` and
|
||
`rightstick`.
|
||
|
||
The axis fields are `leftx`, `lefty`, `rightx`, `righty`, `lefttrigger` and
|
||
`righttrigger`.
|
||
|
||
The value of an axis or button field can be a joystick button, a joystick axis,
|
||
a hat bitmask or empty. Joystick buttons are specified as `bN`, for example
|
||
`b2` for the third button. Joystick axes are specified as `aN`, for example
|
||
`a7` for the eighth button. Joystick hat bit masks are specified as `hN.N`, for
|
||
example `h0.8` for left on the first hat. More than one bit may be set in the
|
||
mask.
|
||
|
||
Before an axis there may be a `+` or `-` range modifier, for example `+a3` for
|
||
the positive half of the fourth axis. This restricts input to only the positive
|
||
or negative halves of the joystick axis. After an axis or half-axis there may
|
||
be the `~` inversion modifier, for example `a2~` or `-a7~`. This negates the
|
||
values of the gamepad axis.
|
||
|
||
The hat bit mask match the [hat states](@ref hat_state) in the joystick
|
||
functions.
|
||
|
||
There is also the special `platform` field that specifies which platform the
|
||
mapping is valid for. Possible values are `Windows`, `Mac OS X` and `Linux`.
|
||
|
||
Below is an example of what a gamepad mapping might look like. It is the
|
||
one built into GLFW for Xbox controllers accessed via the XInput API on Windows.
|
||
This example has been broken into several lines to fit on the page, but real
|
||
gamepad mappings must be a single line.
|
||
|
||
```
|
||
78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,
|
||
b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,
|
||
rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,
|
||
righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
|
||
```
|
||
|
||
@note GLFW does not yet support the output range and modifiers `+` and `-` that
|
||
were recently added to SDL. The input modifiers `+`, `-` and `~` are supported
|
||
and described above.
|
||
|
||
|
||
## Time input {#time}
|
||
|
||
GLFW provides high-resolution time input, in seconds, with @ref glfwGetTime.
|
||
|
||
```c
|
||
double seconds = glfwGetTime();
|
||
```
|
||
|
||
It returns the number of seconds since the library was initialized with @ref
|
||
glfwInit. The platform-specific time sources used typically have micro- or
|
||
nanosecond resolution.
|
||
|
||
You can modify the base time with @ref glfwSetTime.
|
||
|
||
```c
|
||
glfwSetTime(4.0);
|
||
```
|
||
|
||
This sets the time to the specified time, in seconds, and it continues to count
|
||
from there.
|
||
|
||
You can also access the raw timer used to implement the functions above,
|
||
with @ref glfwGetTimerValue.
|
||
|
||
```c
|
||
uint64_t value = glfwGetTimerValue();
|
||
```
|
||
|
||
This value is in 1 / frequency seconds. The frequency of the raw
|
||
timer varies depending on the operating system and hardware. You can query the
|
||
frequency, in Hz, with @ref glfwGetTimerFrequency.
|
||
|
||
```c
|
||
uint64_t frequency = glfwGetTimerFrequency();
|
||
```
|
||
|
||
|
||
## Clipboard input and output {#clipboard}
|
||
|
||
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.
|
||
|
||
```c
|
||
const char* text = glfwGetClipboardString(NULL);
|
||
if (text)
|
||
{
|
||
insert_text(text);
|
||
}
|
||
```
|
||
|
||
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.
|
||
|
||
```c
|
||
glfwSetClipboardString(NULL, "A string with words in it");
|
||
```
|
||
|
||
|
||
## Path drop input {#path_drop}
|
||
|
||
If you wish to receive the paths of files and/or directories dropped on
|
||
a window, set a file drop callback.
|
||
|
||
```c
|
||
glfwSetDropCallback(window, drop_callback);
|
||
```
|
||
|
||
The callback function receives an array of paths encoded as UTF-8.
|
||
|
||
```c
|
||
void drop_callback(GLFWwindow* window, int count, const char** paths)
|
||
{
|
||
int i;
|
||
for (i = 0; i < count; i++)
|
||
handle_dropped_file(paths[i]);
|
||
}
|
||
```
|
||
|
||
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.
|
||
|