Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

state: add API for updating latched and locked mods & layout in server state #314

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions include/xkbcommon/xkbcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@
#ifndef _XKBCOMMON_H_
#define _XKBCOMMON_H_

#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>

#include <xkbcommon/xkbcommon-names.h>
#include <xkbcommon/xkbcommon-keysyms.h>
Expand Down Expand Up @@ -1441,12 +1442,68 @@ enum xkb_state_component
xkb_state_update_key(struct xkb_state *state, xkb_keycode_t key,
enum xkb_key_direction direction);

/**
* Update the keyboard state to change the latched and locked state of
* the modifiers and layout.
*
* This entry point is intended for *server* applications and should not be used
* by *client* applications; see @ref server-client-state for details.
*
* Use this function to update the latched and locked state according to
* "out of band" (non-device) inputs, such as UI layout switchers.
*
* @par Layout out of range
* @parblock
*
* If the effective layout, after taking into account the depressed, latched and
* locked layout, is out of range (negative or greater than the maximum layout),
* it is brought into range. Currently, the layout is wrapped using integer
* modulus (with negative values wrapping from the end). The wrapping behavior
* may be made configurable in the future.
*
* @endparblock
*
* @param affect_latched_mods
* @param latched_mods
* Modifiers to set as latched or unlatched. Only modifiers in
* `affect_latched_mods` are considered.
* @param affect_latched_layout
* @param latched_layout
* Layout to latch. Only considered if `affect_latched_layout` is true.
* Maybe be out of range (including negative) -- see note above.
* @param affect_locked_mods
* @param locked_mods
* Modifiers to set as locked or unlocked. Only modifiers in
* `affect_locked_mods` are considered.
* @param affect_locked_layout
* @param locked_layout
* Layout to lock. Only considered if `affect_locked_layout` is true.
* Maybe be out of range (including negative) -- see note above.
*
* @returns A mask of state components that have changed as a result of
* the update. If nothing in the state has changed, returns 0.
*
* @memberof xkb_state
*
* @sa xkb_state_update_mask()
*/
enum xkb_state_component
xkb_state_update_latched_locked(struct xkb_state *state,
xkb_mod_mask_t affect_latched_mods,
xkb_mod_mask_t latched_mods,
bool affect_latched_layout,
int32_t latched_layout,
xkb_mod_mask_t affect_locked_mods,
xkb_mod_mask_t locked_mods,
bool affect_locked_layout,
int32_t locked_layout);

/**
* Update a keyboard state from a set of explicit masks.
*
* This entry point is intended for *client* applications; see @ref
* server-client-state for details. *Server* applications should use
* xkb_state_update_key() instead.
* xkb_state_update_key() and xkb_state_update_latched_locked() instead.
*
* All parameters must always be passed, or the resulting state may be
* incoherent.
Expand Down
86 changes: 86 additions & 0 deletions src/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include "keymap.h"
#include "keysym.h"
#include "utf8.h"
#include "xkbcommon/xkbcommon.h"

struct xkb_filter {
union xkb_action action;
Expand Down Expand Up @@ -781,6 +782,91 @@ xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
return get_state_component_changes(&prev_components, &state->components);
}

// XXX transcription from xserver
static void
XkbLatchModifiers(struct xkb_state *state, xkb_mod_mask_t mask, xkb_mod_mask_t latches)
{
const struct xkb_key *key = XkbKey(state->keymap, SYNTHETIC_KEYCODE);

xkb_mod_mask_t clear = mask & (~latches);
state->components.latched_mods &= ~clear;
union xkb_action none = {
.type = ACTION_TYPE_NONE,
};
/* Clear any pending latch to locks. */
xkb_filter_apply_all(state, key, XKB_KEY_DOWN);

union xkb_action latch_mods = {
.mods = {
.type = ACTION_TYPE_MOD_LATCH,
.mods = {
.mask = mask & latches,
},
.flags = 0,
},
};
struct xkb_filter *filter = xkb_filter_new(state);
filter->key = key;
filter->func = filter_action_funcs[latch_mods.type].func;
filter->action = latch_mods;
xkb_filter_mod_latch_new(state, filter);
xkb_filter_mod_latch_func(state, filter, key, XKB_KEY_DOWN);
xkb_filter_mod_latch_func(state, filter, key, XKB_KEY_UP);
}

// XXX transcription from xserver
static int
XkbLatchGroup(struct xkb_state *state, int32_t group)
{
const struct xkb_key *key = XkbKey(state->keymap, SYNTHETIC_KEYCODE);

union xkb_action latch_group = {
.group = {
.type = ACTION_TYPE_GROUP_LATCH,
.flags = 0,
.group = group,
},
};
struct xkb_filter *filter = xkb_filter_new(state);
filter->key = key;
filter->func = filter_action_funcs[latch_group.type].func;
filter->action = latch_group;
xkb_filter_group_latch_new(state, filter);
xkb_filter_group_latch_func(state, filter, key, XKB_KEY_DOWN);
xkb_filter_group_latch_func(state, filter, key, XKB_KEY_UP);
}

XKB_EXPORT enum xkb_state_component
xkb_state_update_latched_locked(struct xkb_state *state,
xkb_mod_mask_t affect_latched_mods,
xkb_mod_mask_t latched_mods,
bool affect_latched_layout,
int32_t latched_layout,
xkb_mod_mask_t affect_locked_mods,
xkb_mod_mask_t locked_mods,
bool affect_locked_layout,
int32_t locked_layout)
{
struct state_components prev_components = state->components;

state->components.locked_mods &= ~affect_locked_mods;
state->components.locked_mods |= locked_mods & affect_locked_mods;

if (affect_locked_layout) {
state->components.locked_group = locked_layout;
}

XkbLatchModifiers(state, affect_latched_mods, latched_mods);

if (affect_latched_layout) {
XkbLatchGroup(state, latched_layout);
}

xkb_state_update_derived(state);

return get_state_component_changes(&prev_components, &state->components);
}

/**
* Updates the state from a set of explicit masks as gained from
* xkb_state_serialize_mods and xkb_state_serialize_groups. As noted in the
Expand Down