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

Actions/locks xkb extension v2 #485

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
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
3 changes: 2 additions & 1 deletion bench/key-proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ main(void)
ctx = test_get_context(0);
assert(ctx);

keymap = test_compile_rules(ctx, "evdev", "pc104", "us,ru,il,de",
keymap = test_compile_rules(ctx, XKB_KEYMAP_FORMAT_TEXT_V1,
"evdev", "pc104", "us,ru,il,de",
",,,neo", "grp:menu_toggle");
assert(keymap);

Expand Down
3 changes: 2 additions & 1 deletion bench/rulescomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ main(int argc, char *argv[])

bench_start(&bench);
for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
keymap = test_compile_rules(ctx, "evdev", "evdev", "us", "", "");
keymap = test_compile_rules(ctx, XKB_KEYMAP_FORMAT_TEXT_V1,
"evdev", "evdev", "us", "", "");
assert(keymap);
xkb_keymap_unref(keymap);
}
Expand Down
12 changes: 11 additions & 1 deletion doc/message-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ NOTE: This file has been generated automatically by “update-message-registry.p
-->

This page lists the warnings and errors generated by xkbcommon.
There are currently 55 entries.
There are currently 56 entries.

@todo The documentation of the log messages is a work in progress.

Expand Down Expand Up @@ -53,6 +53,7 @@ There are currently 55 entries.
| [XKB-623] | `invalid-real-modifier` | Invalid _real_ modifier | Error |
| [XKB-645] | `unknown-char-escape-sequence` | Warn on unknown escape sequence in string literal | Warning |
| [XKB-661] | `invalid-included-file` | The target file of an include statement could not be processed | Error |
| [XKB-689] | `incompatible-keymap-export-format` | The keymap has features that cannot be exported in the target format | Error |
| [XKB-700] | `multiple-groups-at-once` | Warn if a key defines multiple groups at once | Warning |
| [XKB-711] | `unsupported-symbols-field` | A legacy X11 symbol field is not supported | Warning |
| [XKB-769] | `invalid-syntax` | The syntax is invalid and the file cannot be parsed | Error |
Expand Down Expand Up @@ -550,6 +551,14 @@ xkbcommon support the following escape sequences in string literals:
<dt>Summary</dt><dd>The target file of an include statement could not be processed</dd>
</dl>

### XKB-689 – Incompatible keymap export format {#XKB-689}

<dl>
<dt>Since</dt><dd>1.8.0</dd>
<dt>Type</dt><dd>Error</dd>
<dt>Summary</dt><dd>The keymap has features that cannot be exported in the target format</dd>
</dl>

### XKB-700 – Multiple groups at once {#XKB-700}

<dl>
Expand Down Expand Up @@ -724,6 +733,7 @@ The modifiers used in `map` or `preserve` entries should be declared using the e
[XKB-623]: @ref XKB-623
[XKB-645]: @ref XKB-645
[XKB-661]: @ref XKB-661
[XKB-689]: @ref XKB-689
[XKB-700]: @ref XKB-700
[XKB-711]: @ref XKB-711
[XKB-769]: @ref XKB-769
Expand Down
5 changes: 5 additions & 0 deletions doc/message-registry.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,11 @@
added: ALWAYS
type: error
description: "The target file of an include statement could not be processed"
- id: "incompatible-keymap-export-format"
code: 689
added: 1.8.0
type: error
description: "The keymap has features that cannot be exported in the target format"
- id: "multiple-groups-at-once"
code: 700
added: ALWAYS
Expand Down
62 changes: 56 additions & 6 deletions include/xkbcommon/xkbcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#define _XKBCOMMON_H_

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

Expand Down Expand Up @@ -866,6 +867,38 @@ enum xkb_keymap_compile_flags {
XKB_KEYMAP_COMPILE_NO_FLAGS = 0
};

/** The possible keymap formats. */
enum xkb_keymap_format {
/** The current/classic XKB text format, as generated by xkbcomp -xkb. */
XKB_KEYMAP_FORMAT_TEXT_V1 = 1,
/** Extension that introduces the options `lockOnRelease` and
* `unlockOnPress`. */
XKB_KEYMAP_FORMAT_TEXT_V1_1 = 2
};

/**
* Provide an array of the supported keymap formats, sorted in ascending order
* (newest last).
*
* @param[out] formats An array of the supported keymap formats.
*
* @returns The size of the array.
*
* @memberof xkb_keymap
*/
size_t
xkb_keymap_supported_formats(const enum xkb_keymap_format **formats);

/**
* Check if the given keymap format is supported.
*
* @param[in] format A keymap format to test.
*
* @memberof xkb_keymap
*/
bool
xkb_keymap_is_supported_format(enum xkb_keymap_format format);

/**
* Create a keymap from RMLVO names.
*
Expand All @@ -879,19 +912,36 @@ enum xkb_keymap_compile_flags {
* @returns A keymap compiled according to the RMLVO names, or NULL if
* the compilation failed.
*
* @sa xkb_rule_names
* @sa xkb_rule_names xkb_keymap_new_from_names2
* @memberof xkb_keymap
*/
struct xkb_keymap *
xkb_keymap_new_from_names(struct xkb_context *context,
const struct xkb_rule_names *names,
enum xkb_keymap_compile_flags flags);

/** The possible keymap formats. */
enum xkb_keymap_format {
/** The current/classic XKB text format, as generated by xkbcomp -xkb. */
XKB_KEYMAP_FORMAT_TEXT_V1 = 1
};
/**
* Create a keymap from RMLVO names using a specific keymap format.
*
* The primary keymap entry point: creates a new XKB keymap from a set of
* RMLVO (Rules + Model + Layouts + Variants + Options) names.
*
* @param context The context in which to create the keymap.
* @param names The RMLVO names to use. See xkb_rule_names.
* @param format The text format of the keymap file to compile.
* @param flags Optional flags for the keymap, or 0.
*
* @returns A keymap compiled according to the RMLVO names, or NULL if
* the compilation failed.
*
* @sa xkb_rule_names xkb_keymap_new_from_names
* @memberof xkb_keymap
*/
struct xkb_keymap *
xkb_keymap_new_from_names2(struct xkb_context *context,
const struct xkb_rule_names *names,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags);

/**
* Create a keymap from a keymap file.
Expand Down
46 changes: 41 additions & 5 deletions src/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ get_keymap_format_ops(enum xkb_keymap_format format)
{
static const struct xkb_keymap_format_ops *keymap_format_ops[] = {
[XKB_KEYMAP_FORMAT_TEXT_V1] = &text_v1_keymap_format_ops,
[XKB_KEYMAP_FORMAT_TEXT_V1_1] = &text_v1_keymap_format_ops,
};

if ((int) format < 0 || (int) format >= (int) ARRAY_SIZE(keymap_format_ops))
Expand All @@ -116,14 +117,40 @@ get_keymap_format_ops(enum xkb_keymap_format format)
return keymap_format_ops[(int) format];
}

/* Warning: must be in ascending order */
static const enum xkb_keymap_format supported_keymap_formats[] = {
XKB_KEYMAP_FORMAT_TEXT_V1,
XKB_KEYMAP_FORMAT_TEXT_V1_1
};

XKB_EXPORT size_t
xkb_keymap_supported_formats(const enum xkb_keymap_format **formats)
{
*formats = supported_keymap_formats;
return ARRAY_SIZE(supported_keymap_formats);
}

XKB_EXPORT bool
xkb_keymap_is_supported_format(enum xkb_keymap_format format)
{
for (size_t k = 0; k < ARRAY_SIZE(supported_keymap_formats); k++) {
if (supported_keymap_formats[k] == format)
return true;
/* Short-circuit because array is sorted */
if (supported_keymap_formats[k] > format)
return false;
}
return false;
}

XKB_EXPORT struct xkb_keymap *
xkb_keymap_new_from_names(struct xkb_context *ctx,
const struct xkb_rule_names *rmlvo_in,
enum xkb_keymap_compile_flags flags)
xkb_keymap_new_from_names2(struct xkb_context *ctx,
const struct xkb_rule_names *rmlvo_in,
enum xkb_keymap_format format,
enum xkb_keymap_compile_flags flags)
{
struct xkb_keymap *keymap;
struct xkb_rule_names rmlvo;
const enum xkb_keymap_format format = XKB_KEYMAP_FORMAT_TEXT_V1;
const struct xkb_keymap_format_ops *ops;

ops = get_keymap_format_ops(format);
Expand Down Expand Up @@ -155,6 +182,15 @@ xkb_keymap_new_from_names(struct xkb_context *ctx,
return keymap;
}

XKB_EXPORT struct xkb_keymap *
xkb_keymap_new_from_names(struct xkb_context *ctx,
const struct xkb_rule_names *rmlvo_in,
enum xkb_keymap_compile_flags flags)
{
return xkb_keymap_new_from_names2(ctx, rmlvo_in,
XKB_KEYMAP_FORMAT_TEXT_V1, flags);
}

XKB_EXPORT struct xkb_keymap *
xkb_keymap_new_from_string(struct xkb_context *ctx,
const char *string,
Expand Down Expand Up @@ -258,7 +294,7 @@ xkb_keymap_get_as_string(struct xkb_keymap *keymap,
return NULL;
}

return ops->keymap_get_as_string(keymap);
return ops->keymap_get_as_string(keymap, format);
}

/**
Expand Down
5 changes: 4 additions & 1 deletion src/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ enum xkb_action_flags {
ACTION_ABSOLUTE_Y = (1 << 7),
ACTION_ACCEL = (1 << 8),
ACTION_SAME_SCREEN = (1 << 9),
ACTION_LOCK_ON_RELEASE = (1 << 10),
ACTION_UNLOCK_ON_PRESS = (1 << 11),
};

enum xkb_action_controls {
Expand Down Expand Up @@ -488,7 +490,8 @@ struct xkb_keymap_format_ops {
bool (*keymap_new_from_string)(struct xkb_keymap *keymap,
const char *string, size_t length);
bool (*keymap_new_from_file)(struct xkb_keymap *keymap, FILE *file);
char *(*keymap_get_as_string)(struct xkb_keymap *keymap);
char *(*keymap_get_as_string)(struct xkb_keymap *keymap,
enum xkb_keymap_format format);
};

extern const struct xkb_keymap_format_ops text_v1_keymap_format_ops;
Expand Down
2 changes: 2 additions & 0 deletions src/messages-codes.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ enum xkb_message_code {
XKB_WARNING_UNKNOWN_CHAR_ESCAPE_SEQUENCE = 645,
/** The target file of an include statement could not be processed */
XKB_ERROR_INVALID_INCLUDED_FILE = 661,
/** The keymap has features that cannot be exported in the target format */
XKB_ERROR_INCOMPATIBLE_KEYMAP_EXPORT_FORMAT = 689,
/** Warn if a key defines multiple groups at once */
XKB_WARNING_MULTIPLE_GROUPS_AT_ONCE = 700,
/** A legacy X11 symbol field is not supported */
Expand Down
36 changes: 32 additions & 4 deletions src/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ xkb_filter_group_set_func(struct xkb_state *state,
static void
xkb_filter_group_lock_new(struct xkb_state *state, struct xkb_filter *filter)
{
/* XKB extension: lock on release
* Do nothing on press */
if (filter->action.group.flags & ACTION_LOCK_ON_RELEASE)
return;

if (filter->action.group.flags & ACTION_ABSOLUTE_SWITCH)
state->components.locked_group = filter->action.group.group;
else
Expand All @@ -323,8 +328,15 @@ xkb_filter_group_lock_func(struct xkb_state *state,
const struct xkb_key *key,
enum xkb_key_direction direction)
{
if (key != filter->key)
if (key != filter->key) {
if (filter->action.group.flags & ACTION_LOCK_ON_RELEASE &&
direction == XKB_KEY_DOWN) {
/* XKB extension: lock on release
* Another key has been pressed: cancel group change on release */
filter->action.group.flags &= ~ACTION_LOCK_ON_RELEASE;
}
return XKB_FILTER_CONTINUE;
}

if (direction == XKB_KEY_DOWN) {
filter->refcnt++;
Expand All @@ -333,6 +345,14 @@ xkb_filter_group_lock_func(struct xkb_state *state,
if (--filter->refcnt > 0)
return XKB_FILTER_CONSUME;

if (filter->action.group.flags & ACTION_LOCK_ON_RELEASE) {
/* XKB extension: lock on release */
if (filter->action.group.flags & ACTION_ABSOLUTE_SWITCH)
state->components.locked_group = filter->action.group.group;
else
state->components.locked_group += filter->action.group.group;
}

filter->func = NULL;
return XKB_FILTER_CONTINUE;
}
Expand Down Expand Up @@ -375,9 +395,17 @@ xkb_filter_mod_lock_new(struct xkb_state *state, struct xkb_filter *filter)
{
filter->priv = (state->components.locked_mods &
filter->action.mods.mods.mask);
state->set_mods |= filter->action.mods.mods.mask;
if (!(filter->action.mods.flags & ACTION_LOCK_NO_LOCK))
state->components.locked_mods |= filter->action.mods.mods.mask;
if (filter->priv && (filter->action.mods.flags & ACTION_UNLOCK_ON_PRESS)) {
/* XKB extension: Unlock on second press */
state->clear_mods |= filter->action.mods.mods.mask;
if (!(filter->action.mods.flags & ACTION_LOCK_NO_UNLOCK))
state->components.locked_mods &= ~filter->priv;
filter->priv = 0;
} else {
state->set_mods |= filter->action.mods.mods.mask;
if (!(filter->action.mods.flags & ACTION_LOCK_NO_LOCK))
state->components.locked_mods |= filter->action.mods.mods.mask;
}
}

static bool
Expand Down
Loading
Loading