st/oxr: properly enable binding to /x and /y

Store Thumbstick, Trackpad etc. data internally in a vec2f.
The knowledge that a binding path ../x and ../y refers to the x and y components of this vec2f
is stored as an INPUT_REDIRECT_VEC2_X_TO_VEC1 or INPUT_REDIRECT_VEC2_Y_TO_VEC enum.

Actions now also store the index of the binding paths it matched to,
e.g. when an action binds ../trackpad/y to an input that provides bindings [../trackpad, ../trackpad/x, ../trackpad/y],
the index 2 is stored.

v2: Clarify preferred binding path index variable
This commit is contained in:
Christoph Haag 2020-04-29 05:27:20 +02:00 committed by Jakob Bornecrantz
parent a6b88595d7
commit d62c2d2011
7 changed files with 207 additions and 84 deletions

View file

@ -86,8 +86,7 @@ enum vive_controller_input_index
VIVE_CONTROLLER_INDEX_SYSTEM_CLICK,
VIVE_CONTROLLER_INDEX_TRIGGER_CLICK,
VIVE_CONTROLLER_INDEX_TRIGGER_VALUE,
VIVE_CONTROLLER_INDEX_TRACKPAD_X,
VIVE_CONTROLLER_INDEX_TRACKPAD_Y,
VIVE_CONTROLLER_INDEX_TRACKPAD,
VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH,
// Vive Wand specific inputs
@ -96,8 +95,7 @@ enum vive_controller_input_index
VIVE_CONTROLLER_INDEX_TRACKPAD_CLICK,
// Valve Index specific inputs
VIVE_CONTROLLER_INDEX_THUMBSTICK_X,
VIVE_CONTROLLER_INDEX_THUMBSTICK_Y,
VIVE_CONTROLLER_INDEX_THUMBSTICK,
VIVE_CONTROLLER_INDEX_A_CLICK,
VIVE_CONTROLLER_INDEX_B_CLICK,
VIVE_CONTROLLER_INDEX_THUMBSTICK_CLICK,
@ -268,23 +266,15 @@ vive_controller_device_update_wand_inputs(struct xrt_device *xdev)
}
}
if (d->state.trackpad.x != 0) {
if (d->state.trackpad.x != 0 || d->state.trackpad.y != 0) {
struct xrt_input *input =
&d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_X];
&d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD];
input->timestamp = now;
input->value.vec1.x = d->state.trackpad.x;
}
if (d->state.trackpad.y != 0) {
struct xrt_input *input =
&d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_Y];
input->timestamp = now;
input->value.vec1.x = d->state.trackpad.y;
}
if (d->state.trackpad.x != 0 || d->state.trackpad.y != 0)
input->value.vec2.x = d->state.trackpad.x;
input->value.vec2.y = d->state.trackpad.y;
VIVE_CONTROLLER_DEBUG(d, "Trackpad: %f, %f",
d->state.trackpad.x, d->state.trackpad.y);
}
if (d->state.trigger != 0) {
struct xrt_input *input =
@ -348,33 +338,18 @@ vive_controller_device_update_index_inputs(struct xrt_device *xdev)
* report trackpad position when trackpad has been touched last, and
* thumbstick position when trackpad touch has been released
*/
if (d->state.trackpad.x != 0) {
struct xrt_input *input;
if (d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH]
.value.boolean)
input =
&d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_X];
else
input =
&d->base.inputs[VIVE_CONTROLLER_INDEX_THUMBSTICK_X];
input->timestamp = now;
input->value.vec1.x = d->state.trackpad.x;
}
if (d->state.trackpad.y != 0) {
struct xrt_input *input;
if (d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH]
.value.boolean)
input =
&d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_X];
else
input =
&d->base.inputs[VIVE_CONTROLLER_INDEX_THUMBSTICK_X];
input->timestamp = now;
input->value.vec1.x = d->state.trackpad.y;
}
if (d->state.trackpad.x != 0 || d->state.trackpad.y != 0) {
struct xrt_input *input;
if (d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH]
.value.boolean)
input = &d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD];
else
input =
&d->base.inputs[VIVE_CONTROLLER_INDEX_THUMBSTICK];
input->timestamp = now;
input->value.vec2.x = d->state.trackpad.x;
input->value.vec2.y = d->state.trackpad.y;
const char *component =
d->base.inputs[VIVE_CONTROLLER_INDEX_TRACKPAD_TOUCH]
.value.boolean
@ -1159,8 +1134,7 @@ vive_controller_found(struct xrt_prober *xp,
SET_WAND_INPUT(MENU_CLICK, MENU_CLICK);
SET_WAND_INPUT(TRIGGER_CLICK, TRIGGER_CLICK);
SET_WAND_INPUT(TRIGGER_VALUE, TRIGGER_VALUE);
SET_WAND_INPUT(TRACKPAD_X, TRACKPAD_X);
SET_WAND_INPUT(TRACKPAD_Y, TRACKPAD_Y);
SET_WAND_INPUT(TRACKPAD, TRACKPAD);
SET_WAND_INPUT(TRACKPAD_CLICK, TRACKPAD_CLICK);
SET_WAND_INPUT(TRACKPAD_TOUCH, TRACKPAD_TOUCH);
@ -1180,11 +1154,9 @@ vive_controller_found(struct xrt_prober *xp,
SET_INDEX_INPUT(B_CLICK, B_CLICK);
SET_INDEX_INPUT(TRIGGER_CLICK, TRIGGER_CLICK);
SET_INDEX_INPUT(TRIGGER_VALUE, TRIGGER_VALUE);
SET_INDEX_INPUT(TRACKPAD_X, TRACKPAD_X);
SET_INDEX_INPUT(TRACKPAD_Y, TRACKPAD_Y);
SET_INDEX_INPUT(TRACKPAD, TRACKPAD);
SET_INDEX_INPUT(TRACKPAD_TOUCH, TRACKPAD_TOUCH);
SET_INDEX_INPUT(THUMBSTICK_X, THUMBSTICK_X);
SET_INDEX_INPUT(THUMBSTICK_Y, THUMBSTICK_Y);
SET_INDEX_INPUT(THUMBSTICK, THUMBSTICK);
SET_INDEX_INPUT(THUMBSTICK_CLICK, THUMBSTICK_CLICK);
SET_INDEX_INPUT(AIM_POSE, AIM_POSE);

View file

@ -469,12 +469,10 @@ enum xrt_input_name
XRT_INPUT_INDEX_TRIGGER_CLICK = XRT_INPUT_NAME(0x0058, BOOLEAN),
XRT_INPUT_INDEX_TRIGGER_VALUE = XRT_INPUT_NAME(0x0059, VEC1_ZERO_TO_ONE),
XRT_INPUT_INDEX_TRIGGER_TOUCH = XRT_INPUT_NAME(0x005A, BOOLEAN),
XRT_INPUT_INDEX_THUMBSTICK_X = XRT_INPUT_NAME(0x005B, VEC1_ZERO_TO_ONE),
XRT_INPUT_INDEX_THUMBSTICK_Y = XRT_INPUT_NAME(0x005C, VEC1_ZERO_TO_ONE),
XRT_INPUT_INDEX_THUMBSTICK = XRT_INPUT_NAME(0x005B, VEC2_MINUS_ONE_TO_ONE),
XRT_INPUT_INDEX_THUMBSTICK_CLICK = XRT_INPUT_NAME(0x005D, BOOLEAN),
XRT_INPUT_INDEX_THUMBSTICK_TOUCH = XRT_INPUT_NAME(0x005E, BOOLEAN),
XRT_INPUT_INDEX_TRACKPAD_X = XRT_INPUT_NAME(0x005F, VEC1_ZERO_TO_ONE),
XRT_INPUT_INDEX_TRACKPAD_Y = XRT_INPUT_NAME(0x0060, VEC1_ZERO_TO_ONE),
XRT_INPUT_INDEX_TRACKPAD = XRT_INPUT_NAME(0x005F, VEC2_MINUS_ONE_TO_ONE),
XRT_INPUT_INDEX_TRACKPAD_FORCE = XRT_INPUT_NAME(0x0061, VEC1_ZERO_TO_ONE),
XRT_INPUT_INDEX_TRACKPAD_TOUCH = XRT_INPUT_NAME(0x0062, BOOLEAN),
XRT_INPUT_INDEX_GRIP_POSE = XRT_INPUT_NAME(0x0063, POSE),
@ -485,8 +483,7 @@ enum xrt_input_name
XRT_INPUT_VIVE_MENU_CLICK = XRT_INPUT_NAME(0x0072, BOOLEAN),
XRT_INPUT_VIVE_TRIGGER_CLICK = XRT_INPUT_NAME(0x0073, BOOLEAN),
XRT_INPUT_VIVE_TRIGGER_VALUE = XRT_INPUT_NAME(0x0074, VEC1_ZERO_TO_ONE),
XRT_INPUT_VIVE_TRACKPAD_X = XRT_INPUT_NAME(0x0075, VEC1_ZERO_TO_ONE),
XRT_INPUT_VIVE_TRACKPAD_Y = XRT_INPUT_NAME(0x0076, VEC1_ZERO_TO_ONE),
XRT_INPUT_VIVE_TRACKPAD = XRT_INPUT_NAME(0x0076, VEC2_MINUS_ONE_TO_ONE),
XRT_INPUT_VIVE_TRACKPAD_CLICK = XRT_INPUT_NAME(0x0077, BOOLEAN),
XRT_INPUT_VIVE_TRACKPAD_TOUCH = XRT_INPUT_NAME(0x0077, BOOLEAN),
XRT_INPUT_VIVE_GRIP_POSE = XRT_INPUT_NAME(0x0078, POSE),

View file

@ -189,6 +189,13 @@ struct xrt_input
union xrt_input_value value;
};
enum xrt_source_value_redirect
{
INPUT_REDIRECT_DEFAULT = 0,
INPUT_REDIRECT_VEC2_X_TO_VEC1,
INPUT_REDIRECT_VEC2_Y_TO_VEC1
};
struct xrt_output
{
enum xrt_output_name name;

View file

@ -195,7 +195,8 @@ static void
add_key_to_matching_bindings(struct oxr_binding *bindings,
size_t num_bindings,
XrPath path,
uint32_t key)
uint32_t key,
uint32_t *preferred_binding_path)
{
for (size_t x = 0; x < num_bindings; x++) {
struct oxr_binding *b = &bindings[x];
@ -204,6 +205,7 @@ add_key_to_matching_bindings(struct oxr_binding *bindings,
for (size_t y = 0; y < b->num_paths; y++) {
if (b->paths[y] == path) {
found = true;
*preferred_binding_path = y;
break;
}
}
@ -391,8 +393,9 @@ oxr_action_suggest_interaction_profile_bindings(
fprintf(stderr, "\t\t%s %i -> %s\n", act->name, act->key, str);
#endif
add_key_to_matching_bindings(bindings, num_bindings, s->binding,
act->key);
add_key_to_matching_bindings(
bindings, num_bindings, s->binding, act->key,
&act->preferred_binding_path_index);
}
return XR_SUCCESS;

View file

@ -826,6 +826,69 @@ static struct binding_template mnd_ball_on_stick_controller_bindings[26] = {
}, \
},
// creates an input that can not be "downgraded" to the top level path.
// e.g. don't bind ../trackpad/click, ../trackpad/touch with just ../trackpad
#define MAKE_INPUT_SUFFIX_ONLY(COMPONENT, SUFFIX, INPUT) \
{ \
.sub_path = OXR_SUB_ACTION_PATH_LEFT, \
.paths = \
{ \
"/user/hand/left/input/" #COMPONENT "/" #SUFFIX, \
NULL, \
}, \
.inputs = \
{ \
INPUT, \
(enum xrt_input_name)0, \
}, \
}, \
{ \
.sub_path = OXR_SUB_ACTION_PATH_RIGHT, \
.paths = \
{ \
"/user/hand/right/input/" #COMPONENT "/" #SUFFIX, \
NULL, \
}, \
.inputs = \
{ \
INPUT, \
(enum xrt_input_name)0, \
}, \
},
// creates an input with a top level path and /x and /y sub paths
#define MAKE_INPUT_VEC2F(COMPONENT, INPUT) \
{ \
.sub_path = OXR_SUB_ACTION_PATH_LEFT, \
.paths = \
{ \
"/user/hand/left/input/" #COMPONENT, \
"/user/hand/left/input/" #COMPONENT "/x", \
"/user/hand/left/input/" #COMPONENT "/y", \
NULL, \
}, \
.inputs = \
{ \
INPUT, \
(enum xrt_input_name)0, \
}, \
}, \
{ \
.sub_path = OXR_SUB_ACTION_PATH_RIGHT, \
.paths = \
{ \
"/user/hand/right/input/" #COMPONENT, \
"/user/hand/right/input/" #COMPONENT "/x", \
"/user/hand/right/input/" #COMPONENT "/y", \
NULL, \
}, \
.inputs = \
{ \
INPUT, \
(enum xrt_input_name)0, \
}, \
},
#define MAKE_OUTPUT(COMPONENT, SUFFIX, OUTPUT) \
{ \
.sub_path = OXR_SUB_ACTION_PATH_LEFT, \
@ -869,14 +932,12 @@ static struct binding_template valve_index_controller_bindings[44] = {
MAKE_INPUT(trigger, click, XRT_INPUT_INDEX_TRIGGER_CLICK)
MAKE_INPUT(trigger, value, XRT_INPUT_INDEX_TRIGGER_VALUE)
MAKE_INPUT(trigger, touch, XRT_INPUT_INDEX_TRIGGER_TOUCH)
MAKE_INPUT(thumbstick, x, XRT_INPUT_INDEX_THUMBSTICK_X)
MAKE_INPUT(thumbstick, y, XRT_INPUT_INDEX_THUMBSTICK_Y)
MAKE_INPUT(thumbstick, click, XRT_INPUT_INDEX_THUMBSTICK_CLICK)
MAKE_INPUT(thumbstick, touch, XRT_INPUT_INDEX_THUMBSTICK_TOUCH)
MAKE_INPUT(trackpad, x, XRT_INPUT_INDEX_TRACKPAD_X)
MAKE_INPUT(trackpad, y, XRT_INPUT_INDEX_TRACKPAD_Y)
MAKE_INPUT(trackpad, force, XRT_INPUT_INDEX_TRACKPAD_FORCE)
MAKE_INPUT(trackpad, touch, XRT_INPUT_INDEX_TRACKPAD_TOUCH)
MAKE_INPUT_VEC2F(thumbstick, XRT_INPUT_INDEX_THUMBSTICK)
MAKE_INPUT_SUFFIX_ONLY(thumbstick, click, XRT_INPUT_INDEX_THUMBSTICK_CLICK)
MAKE_INPUT_SUFFIX_ONLY(thumbstick, touch, XRT_INPUT_INDEX_THUMBSTICK_TOUCH)
MAKE_INPUT_VEC2F(trackpad, XRT_INPUT_INDEX_TRACKPAD)
MAKE_INPUT_SUFFIX_ONLY(trackpad, force, XRT_INPUT_INDEX_TRACKPAD_FORCE)
MAKE_INPUT_SUFFIX_ONLY(trackpad, touch, XRT_INPUT_INDEX_TRACKPAD_TOUCH)
MAKE_INPUT(grip, pose, XRT_INPUT_INDEX_GRIP_POSE)
MAKE_INPUT(aim, pose, XRT_INPUT_INDEX_AIM_POSE)
@ -891,10 +952,9 @@ static struct binding_template htc_vive_controller_bindings[24] = {
MAKE_INPUT(menu, click, XRT_INPUT_VIVE_MENU_CLICK)
MAKE_INPUT(trigger, click, XRT_INPUT_VIVE_TRIGGER_CLICK)
MAKE_INPUT(trigger, value, XRT_INPUT_VIVE_TRIGGER_VALUE)
MAKE_INPUT(trackpad, x, XRT_INPUT_VIVE_TRACKPAD_X)
MAKE_INPUT(trackpad, y, XRT_INPUT_VIVE_TRACKPAD_Y)
MAKE_INPUT(trackpad, click, XRT_INPUT_VIVE_TRACKPAD_CLICK)
MAKE_INPUT(trackpad, touch, XRT_INPUT_VIVE_TRACKPAD_TOUCH)
MAKE_INPUT_VEC2F(trackpad, XRT_INPUT_VIVE_TRACKPAD)
MAKE_INPUT_SUFFIX_ONLY(trackpad, click, XRT_INPUT_VIVE_TRACKPAD_CLICK)
MAKE_INPUT_SUFFIX_ONLY(trackpad, touch, XRT_INPUT_VIVE_TRACKPAD_TOUCH)
MAKE_INPUT(grip, pose, XRT_INPUT_VIVE_GRIP_POSE)
MAKE_INPUT(aim, pose, XRT_INPUT_VIVE_AIM_POSE)

View file

@ -327,6 +327,54 @@ do_io_bindings(struct oxr_binding *b,
return found;
}
static bool
ends_with(const char *str, const char *suffix)
{
int len = strlen(str);
int suffix_len = strlen(suffix);
return (len >= suffix_len) &&
(0 == strcmp(str + (len - suffix_len), suffix));
}
static void
oxr_source_cache_determine_redirect(struct oxr_logger *log,
struct oxr_session *sess,
struct oxr_action *act,
struct oxr_source_cache *cache,
XrPath bound_path)
{
cache->redirect = INPUT_REDIRECT_DEFAULT;
struct oxr_source_input *input = &cache->inputs[0];
if (input == NULL)
return;
const char *str;
size_t length;
oxr_path_get_string(log, sess->sys->inst, bound_path, &str, &length);
enum xrt_input_type t = XRT_GET_INPUT_TYPE(input->input->name);
// trackpad/thumbstick data is kept in vec2f values.
// When a float action binds to ../trackpad/x or ../thumbstick/y, store
// the information which vec2f component to read.
if (act->action_type == XR_ACTION_TYPE_FLOAT_INPUT &&
t == XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE) {
if (ends_with(str, "/x")) {
cache->redirect = INPUT_REDIRECT_VEC2_X_TO_VEC1;
} else if (ends_with(str, "/y")) {
cache->redirect = INPUT_REDIRECT_VEC2_Y_TO_VEC1;
} else {
oxr_log(log,
"No rule to get float from vec2f for action "
"%s, binding %s\n",
act->name, str);
}
}
}
static void
get_binding(struct oxr_logger *log,
struct oxr_sink_logger *slog,
@ -337,7 +385,8 @@ get_binding(struct oxr_logger *log,
struct oxr_source_input inputs[16],
uint32_t *num_inputs,
struct oxr_source_output outputs[16],
uint32_t *num_outputs)
uint32_t *num_outputs,
XrPath *bound_path)
{
struct xrt_device *xdev = NULL;
struct oxr_binding *bindings[32];
@ -400,8 +449,15 @@ get_binding(struct oxr_logger *log,
const char *str = NULL;
struct oxr_binding *b = bindings[i];
// Just pick the first path.
oxr_path_get_string(log, sess->sys->inst, b->paths[0], &str,
// pick the path that the action prefers.
// e.g. an action bound to /user/hand/*/trackpad will prefer
// index 0 of those bindings, an action bound to
// /user/hand/*/trackpad will prefer index 1
// [/user/hand/*/trackpad, /user/hand/*/trackpad/x]
XrPath preferred_path =
b->paths[act->preferred_binding_path_index];
oxr_path_get_string(log, sess->sys->inst, preferred_path, &str,
&length);
oxr_slog(slog, "\t\t\tBinding: %s\n", str);
@ -414,6 +470,7 @@ get_binding(struct oxr_logger *log,
outputs, num_outputs);
if (found) {
*bound_path = preferred_path;
oxr_slog(slog, "\t\t\t\tBound!\n");
} else {
oxr_slog(slog, "\t\t\t\tRejected! (NO XDEV MAPPING)\n");
@ -812,8 +869,9 @@ oxr_source_bind_inputs(struct oxr_logger *log,
struct oxr_source_output outputs[16] = {0};
uint32_t num_outputs = 0;
XrPath bound_path;
get_binding(log, slog, sess, act, profile, sub_path, inputs,
&num_inputs, outputs, &num_outputs);
&num_inputs, outputs, &num_outputs, &bound_path);
cache->current.active = false;
@ -836,6 +894,8 @@ oxr_source_bind_inputs(struct oxr_logger *log,
}
cache->num_outputs = num_outputs;
}
oxr_source_cache_determine_redirect(log, sess, act, cache, bound_path);
}
@ -1018,7 +1078,8 @@ oxr_action_sync_data(struct oxr_logger *log,
static void
get_state_from_state_bool(struct oxr_source_state *state,
XrActionStateBoolean *data)
XrActionStateBoolean *data,
enum xrt_source_value_redirect redirect)
{
data->currentState = state->boolean;
data->lastChangeTime = state->timestamp;
@ -1028,9 +1089,20 @@ get_state_from_state_bool(struct oxr_source_state *state,
static void
get_state_from_state_vec1(struct oxr_source_state *state,
XrActionStateFloat *data)
XrActionStateFloat *data,
enum xrt_source_value_redirect redirect)
{
data->currentState = state->vec1.x;
switch (redirect) {
case INPUT_REDIRECT_VEC2_X_TO_VEC1:
data->currentState = state->vec2.x;
break;
case INPUT_REDIRECT_VEC2_Y_TO_VEC1:
data->currentState = state->vec2.y;
break;
case INPUT_REDIRECT_DEFAULT:
default: data->currentState = state->vec1.x; break;
}
data->lastChangeTime = state->timestamp;
data->changedSinceLastSync = state->changed;
data->isActive = XR_TRUE;
@ -1038,7 +1110,8 @@ get_state_from_state_vec1(struct oxr_source_state *state,
static void
get_state_from_state_vec2(struct oxr_source_state *state,
XrActionStateVector2f *data)
XrActionStateVector2f *data,
enum xrt_source_value_redirect redirect)
{
data->currentState.x = state->vec2.x;
data->currentState.y = state->vec2.y;
@ -1049,22 +1122,28 @@ get_state_from_state_vec2(struct oxr_source_state *state,
#define OXR_ACTION_GET_FILLER(TYPE) \
if (sub_paths.any && src->any_state.active) { \
get_state_from_state_##TYPE(&src->any_state, data); \
get_state_from_state_##TYPE(&src->any_state, data, \
INPUT_REDIRECT_DEFAULT); \
} \
if (sub_paths.user && src->user.current.active) { \
get_state_from_state_##TYPE(&src->user.current, data); \
get_state_from_state_##TYPE(&src->user.current, data, \
src->user.redirect); \
} \
if (sub_paths.head && src->head.current.active) { \
get_state_from_state_##TYPE(&src->head.current, data); \
get_state_from_state_##TYPE(&src->head.current, data, \
src->head.redirect); \
} \
if (sub_paths.left && src->left.current.active) { \
get_state_from_state_##TYPE(&src->left.current, data); \
get_state_from_state_##TYPE(&src->left.current, data, \
src->left.redirect); \
} \
if (sub_paths.right && src->right.current.active) { \
get_state_from_state_##TYPE(&src->right.current, data); \
get_state_from_state_##TYPE(&src->right.current, data, \
src->right.redirect); \
} \
if (sub_paths.gamepad && src->gamepad.current.active) { \
get_state_from_state_##TYPE(&src->gamepad.current, data); \
get_state_from_state_##TYPE(&src->gamepad.current, data, \
src->gamepad.redirect); \
}

View file

@ -1194,6 +1194,8 @@ struct oxr_source_cache
int64_t stop_output_time;
size_t num_outputs;
struct oxr_source_output *outputs;
enum xrt_source_value_redirect redirect;
};
/*!
@ -1335,6 +1337,9 @@ struct oxr_action
//! Which sub action paths that this action was created with.
struct oxr_sub_paths sub_paths;
//! Which of the paths in oxr_binding.paths matches this action.
uint32_t preferred_binding_path_index;
};
/*!