Merge branch 'global-hotkeys'
commit
6c535513b5
|
@ -69,8 +69,23 @@ elseif(APPLE)
|
|||
mark_as_advanced(COCOA)
|
||||
include_directories(${COCOA})
|
||||
|
||||
find_library(APPKIT AppKit)
|
||||
mark_as_advanced(APPKIT)
|
||||
include_directories(${APPKIT})
|
||||
|
||||
find_library(IOKIT IOKit)
|
||||
mark_as_advanced(IOKIT)
|
||||
include_directories(${IOKIT})
|
||||
|
||||
find_library(CARBON Carbon)
|
||||
mark_as_advanced(CARBON)
|
||||
include_directories(${CARBON})
|
||||
|
||||
set(libobs_PLATFORM_DEPS
|
||||
${COCOA})
|
||||
${COCOA}
|
||||
${APPKIT}
|
||||
${IOKIT}
|
||||
${CARBON})
|
||||
elseif(UNIX)
|
||||
set(libobs_PLATFORM_SOURCES
|
||||
obs-nix.c
|
||||
|
@ -216,6 +231,8 @@ set(libobs_libobs_SOURCES
|
|||
obs.c
|
||||
obs-properties.c
|
||||
obs-data.c
|
||||
obs-hotkey.c
|
||||
obs-hotkey-name-map.c
|
||||
obs-module.c
|
||||
obs-display.c
|
||||
obs-view.c
|
||||
|
@ -233,6 +250,8 @@ set(libobs_libobs_HEADERS
|
|||
obs-properties.h
|
||||
obs-data.h
|
||||
obs-interaction.h
|
||||
obs-hotkey.h
|
||||
obs-hotkeys.h
|
||||
obs-module.h
|
||||
obs-scene.h
|
||||
obs-source.h
|
||||
|
|
1141
libobs/obs-cocoa.c
1141
libobs/obs-cocoa.c
File diff suppressed because it is too large
Load Diff
|
@ -37,12 +37,13 @@ const char *obs_encoder_get_display_name(const char *id)
|
|||
}
|
||||
|
||||
static bool init_encoder(struct obs_encoder *encoder, const char *name,
|
||||
obs_data_t *settings)
|
||||
obs_data_t *settings, obs_data_t *hotkey_data)
|
||||
{
|
||||
pthread_mutex_init_value(&encoder->callbacks_mutex);
|
||||
pthread_mutex_init_value(&encoder->outputs_mutex);
|
||||
|
||||
if (!obs_context_data_init(&encoder->context, settings, name))
|
||||
if (!obs_context_data_init(&encoder->context, settings, name,
|
||||
hotkey_data))
|
||||
return false;
|
||||
if (pthread_mutex_init(&encoder->callbacks_mutex, NULL) != 0)
|
||||
return false;
|
||||
|
@ -57,7 +58,7 @@ static bool init_encoder(struct obs_encoder *encoder, const char *name,
|
|||
|
||||
static struct obs_encoder *create_encoder(const char *id,
|
||||
enum obs_encoder_type type, const char *name,
|
||||
obs_data_t *settings, size_t mixer_idx)
|
||||
obs_data_t *settings, size_t mixer_idx, obs_data_t *hotkey_data)
|
||||
{
|
||||
struct obs_encoder *encoder;
|
||||
struct obs_encoder_info *ei = find_encoder(id);
|
||||
|
@ -70,7 +71,7 @@ static struct obs_encoder *create_encoder(const char *id,
|
|||
encoder->info = *ei;
|
||||
encoder->mixer_idx = mixer_idx;
|
||||
|
||||
success = init_encoder(encoder, name, settings);
|
||||
success = init_encoder(encoder, name, settings, hotkey_data);
|
||||
if (!success) {
|
||||
obs_encoder_destroy(encoder);
|
||||
encoder = NULL;
|
||||
|
@ -88,17 +89,19 @@ static struct obs_encoder *create_encoder(const char *id,
|
|||
}
|
||||
|
||||
obs_encoder_t *obs_video_encoder_create(const char *id, const char *name,
|
||||
obs_data_t *settings)
|
||||
obs_data_t *settings, obs_data_t *hotkey_data)
|
||||
{
|
||||
if (!name || !id) return NULL;
|
||||
return create_encoder(id, OBS_ENCODER_VIDEO, name, settings, 0);
|
||||
return create_encoder(id, OBS_ENCODER_VIDEO, name, settings, 0,
|
||||
hotkey_data);
|
||||
}
|
||||
|
||||
obs_encoder_t *obs_audio_encoder_create(const char *id, const char *name,
|
||||
obs_data_t *settings, size_t mixer_idx)
|
||||
obs_data_t *settings, size_t mixer_idx, obs_data_t *hotkey_data)
|
||||
{
|
||||
if (!name || !id) return NULL;
|
||||
return create_encoder(id, OBS_ENCODER_AUDIO, name, settings, mixer_idx);
|
||||
return create_encoder(id, OBS_ENCODER_AUDIO, name, settings, mixer_idx,
|
||||
hotkey_data);
|
||||
}
|
||||
|
||||
static void receive_video(void *param, struct video_data *frame);
|
||||
|
|
|
@ -0,0 +1,411 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2014 by Ruwen Hahn <palana@stunned.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <util/bmem.h>
|
||||
#include <util/c99defs.h>
|
||||
#include <util/darray.h>
|
||||
|
||||
#include "obs-internal.h"
|
||||
|
||||
struct obs_hotkey_name_map_edge;
|
||||
struct obs_hotkey_name_map_node;
|
||||
struct obs_hotkey_name_map;
|
||||
|
||||
typedef struct obs_hotkey_name_map_edge obs_hotkey_name_map_edge_t;
|
||||
typedef struct obs_hotkey_name_map_node obs_hotkey_name_map_node_t;
|
||||
typedef struct obs_hotkey_name_map obs_hotkey_name_map_t;
|
||||
|
||||
struct obs_hotkey_name_map_node {
|
||||
bool is_leaf;
|
||||
union {
|
||||
int val;
|
||||
DARRAY(obs_hotkey_name_map_edge_t) children;
|
||||
};
|
||||
};
|
||||
|
||||
struct obs_hotkey_name_map {
|
||||
obs_hotkey_name_map_node_t root;
|
||||
obs_hotkey_name_map_node_t *leaves;
|
||||
size_t num_leaves;
|
||||
size_t next_leaf;
|
||||
};
|
||||
|
||||
struct obs_hotkey_name_map_edge_prefix {
|
||||
uint8_t prefix_len;
|
||||
char *prefix;
|
||||
};
|
||||
|
||||
#define NAME_MAP_COMPRESS_LENGTH \
|
||||
(sizeof(struct obs_hotkey_name_map_edge_prefix) - sizeof(uint8_t))
|
||||
|
||||
struct obs_hotkey_name_map_edge {
|
||||
union {
|
||||
struct {
|
||||
uint8_t prefix_len;
|
||||
char *prefix;
|
||||
};
|
||||
struct {
|
||||
uint8_t compressed_len;
|
||||
char compressed_prefix[NAME_MAP_COMPRESS_LENGTH];
|
||||
};
|
||||
};
|
||||
struct obs_hotkey_name_map_node *node;
|
||||
};
|
||||
|
||||
|
||||
static inline obs_hotkey_name_map_node_t *new_node(void)
|
||||
{
|
||||
return bzalloc(sizeof(obs_hotkey_name_map_node_t));
|
||||
}
|
||||
|
||||
static inline obs_hotkey_name_map_node_t *new_leaf(void)
|
||||
{
|
||||
obs_hotkey_name_map_t *name_map = obs->hotkeys.name_map;
|
||||
obs_hotkey_name_map_node_t *node =
|
||||
&name_map->leaves[name_map->next_leaf];
|
||||
name_map->next_leaf += 1;
|
||||
|
||||
node->is_leaf = true;
|
||||
return node;
|
||||
}
|
||||
|
||||
static inline char *get_prefix(obs_hotkey_name_map_edge_t *e)
|
||||
{
|
||||
return e->prefix_len >= NAME_MAP_COMPRESS_LENGTH ?
|
||||
e->prefix : e->compressed_prefix;
|
||||
}
|
||||
|
||||
static void set_prefix(obs_hotkey_name_map_edge_t *e, const char *prefix,
|
||||
size_t l)
|
||||
{
|
||||
assert(e->prefix_len == 0);
|
||||
|
||||
e->compressed_len = (uint8_t)l;
|
||||
if (l < NAME_MAP_COMPRESS_LENGTH)
|
||||
strncpy(e->compressed_prefix, prefix, l);
|
||||
else
|
||||
e->prefix = bstrdup_n(prefix, l);
|
||||
}
|
||||
|
||||
static obs_hotkey_name_map_edge_t *add_leaf(obs_hotkey_name_map_node_t *node,
|
||||
const char *key, size_t l, int v)
|
||||
{
|
||||
obs_hotkey_name_map_edge_t *e = da_push_back_new(node->children);
|
||||
|
||||
set_prefix(e, key, l);
|
||||
|
||||
e->node = new_leaf();
|
||||
e->node->val = v;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
static void shrink_prefix(obs_hotkey_name_map_edge_t *e, size_t l)
|
||||
{
|
||||
bool old_comp = e->prefix_len < NAME_MAP_COMPRESS_LENGTH;
|
||||
bool new_comp = l < NAME_MAP_COMPRESS_LENGTH;
|
||||
|
||||
char *str = get_prefix(e);
|
||||
|
||||
e->prefix_len = (uint8_t)l;
|
||||
if (get_prefix(e) != str)
|
||||
strncpy(get_prefix(e), str, l);
|
||||
else
|
||||
str[l] = 0;
|
||||
|
||||
if (!old_comp && new_comp)
|
||||
bfree(str);
|
||||
}
|
||||
|
||||
static void connect(obs_hotkey_name_map_edge_t *e,
|
||||
obs_hotkey_name_map_node_t *n)
|
||||
{
|
||||
e->node = n;
|
||||
}
|
||||
|
||||
static void reduce_edge(obs_hotkey_name_map_edge_t *e, const char *key,
|
||||
size_t l, int v)
|
||||
{
|
||||
const char *str = get_prefix(e), *str_ = key;
|
||||
size_t common_length = 0;
|
||||
while (*str == *str_) {
|
||||
common_length += 1;
|
||||
str += 1;
|
||||
str_ += 1;
|
||||
}
|
||||
|
||||
obs_hotkey_name_map_node_t *new_node_ = new_node();
|
||||
obs_hotkey_name_map_edge_t *tail =
|
||||
da_push_back_new(new_node_->children);
|
||||
|
||||
connect(tail, e->node);
|
||||
set_prefix(tail, str, e->prefix_len - common_length);
|
||||
|
||||
add_leaf(new_node_, str_, l - common_length, v);
|
||||
|
||||
connect(e, new_node_);
|
||||
shrink_prefix(e, common_length);
|
||||
}
|
||||
|
||||
enum obs_hotkey_name_map_edge_compare_result {
|
||||
RES_MATCHES,
|
||||
RES_NO_MATCH,
|
||||
RES_COMMON_PREFIX,
|
||||
RES_PREFIX_MATCHES,
|
||||
};
|
||||
|
||||
static enum obs_hotkey_name_map_edge_compare_result compare_prefix(
|
||||
obs_hotkey_name_map_edge_t *edge, const char *key, size_t l)
|
||||
{
|
||||
uint8_t pref_len = edge->prefix_len;
|
||||
const char *str = get_prefix(edge);
|
||||
size_t i = 0;
|
||||
|
||||
for (; i < l && i < pref_len; i++)
|
||||
if (str[i] != key[i])
|
||||
break;
|
||||
|
||||
|
||||
if (i != 0 && pref_len == i)
|
||||
return l == i ? RES_MATCHES : RES_PREFIX_MATCHES;
|
||||
if (i != 0)
|
||||
return pref_len == i ? RES_PREFIX_MATCHES : RES_COMMON_PREFIX;
|
||||
return RES_NO_MATCH;
|
||||
}
|
||||
|
||||
static void insert(obs_hotkey_name_map_edge_t *edge,
|
||||
obs_hotkey_name_map_node_t *node,
|
||||
const char *key, size_t l, int v)
|
||||
{
|
||||
if (node->is_leaf && l > 0) {
|
||||
obs_hotkey_name_map_node_t *new_node_ = new_node();
|
||||
connect(edge, new_node_);
|
||||
|
||||
obs_hotkey_name_map_edge_t *edge =
|
||||
da_push_back_new(new_node_->children);
|
||||
connect(edge, node);
|
||||
add_leaf(new_node_, key, l, v);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->is_leaf && l == 0) {
|
||||
node->val = v;
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node->children.num; i++) {
|
||||
obs_hotkey_name_map_edge_t *e = &node->children.array[i];
|
||||
|
||||
switch (compare_prefix(e, key, l)) {
|
||||
case RES_NO_MATCH:
|
||||
continue;
|
||||
|
||||
case RES_MATCHES:
|
||||
case RES_PREFIX_MATCHES:
|
||||
insert(e, e->node, key + e->prefix_len,
|
||||
l - e->prefix_len, v);
|
||||
return;
|
||||
|
||||
case RES_COMMON_PREFIX:
|
||||
reduce_edge(e, key, l, v);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
add_leaf(node, key, l, v);
|
||||
}
|
||||
|
||||
static void obs_hotkey_name_map_insert(obs_hotkey_name_map_t *trie,
|
||||
const char *key, int v)
|
||||
{
|
||||
if (!trie || !key)
|
||||
return;
|
||||
|
||||
insert(NULL, &trie->root, key, strlen(key), v);
|
||||
}
|
||||
|
||||
static bool obs_hotkey_name_map_lookup(obs_hotkey_name_map_t *trie,
|
||||
const char *key, int *v)
|
||||
{
|
||||
if (!trie || !key)
|
||||
return false;
|
||||
|
||||
size_t len = strlen(key);
|
||||
obs_hotkey_name_map_node_t *n = &trie->root;
|
||||
|
||||
size_t i = 0;
|
||||
for (; i < n->children.num;) {
|
||||
obs_hotkey_name_map_edge_t *e = &n->children.array[i];
|
||||
|
||||
switch (compare_prefix(e, key, len)) {
|
||||
case RES_NO_MATCH:
|
||||
i++;
|
||||
continue;
|
||||
|
||||
case RES_COMMON_PREFIX:
|
||||
return false;
|
||||
|
||||
case RES_PREFIX_MATCHES:
|
||||
key += e->prefix_len;
|
||||
len -= e->prefix_len;
|
||||
n = e->node;
|
||||
i = 0;
|
||||
continue;
|
||||
|
||||
case RES_MATCHES:
|
||||
n = e->node;
|
||||
if (!n->is_leaf) {
|
||||
for (size_t j = 0; j < n->children.num; j++) {
|
||||
if (n->children.array[j].prefix_len)
|
||||
continue;
|
||||
|
||||
if (v) *v =
|
||||
n->children.array[j].node->val;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (v) *v = n->val;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void show_node(obs_hotkey_name_map_node_t *node, int in)
|
||||
{
|
||||
if (node->is_leaf) {
|
||||
printf(": % 3d\n", node->val);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
for (int i = 0; i < in; i += 2)
|
||||
printf("| ");
|
||||
printf("%zu:\n", node->children.num);
|
||||
|
||||
for (size_t i = 0; i < node->children.num; i++) {
|
||||
for (int i = 0; i < in; i += 2)
|
||||
printf("| ");
|
||||
printf("\\ ");
|
||||
|
||||
obs_hotkey_name_map_edge_t *e = &node->children.array[i];
|
||||
printf("%s", get_prefix(e));
|
||||
show_node(e->node, in+2);
|
||||
}
|
||||
}
|
||||
|
||||
void trie_print_size(obs_hotkey_name_map_t *trie)
|
||||
{
|
||||
show_node(&trie->root, 0);
|
||||
}
|
||||
|
||||
static const char* obs_key_names[] = {
|
||||
#define OBS_HOTKEY(x) #x,
|
||||
#include "obs-hotkeys.h"
|
||||
#undef OBS_HOTKEY
|
||||
};
|
||||
|
||||
const char* obs_key_to_name(obs_key_t key)
|
||||
{
|
||||
if (key >= OBS_KEY_LAST_VALUE) {
|
||||
blog(LOG_ERROR, "obs-hotkey.c: queried unknown key "
|
||||
"with code %d", (int)key);
|
||||
return "";
|
||||
}
|
||||
|
||||
return obs_key_names[key];
|
||||
}
|
||||
|
||||
static obs_key_t obs_key_from_name_fallback(const char *name)
|
||||
{
|
||||
#define OBS_HOTKEY(x) if (strcmp(#x, name) == 0) return x;
|
||||
#include "obs-hotkeys.h"
|
||||
#undef OBS_HOTKEY
|
||||
return OBS_KEY_NONE;
|
||||
}
|
||||
|
||||
static void init_name_map(void)
|
||||
{
|
||||
obs->hotkeys.name_map = bzalloc(sizeof(struct obs_hotkey_name_map));
|
||||
obs_hotkey_name_map_t *name_map = obs->hotkeys.name_map;
|
||||
|
||||
#define OBS_HOTKEY(x) name_map->num_leaves += 1;
|
||||
#include "obs-hotkeys.h"
|
||||
#undef OBS_HOTKEY
|
||||
|
||||
size_t size = sizeof(obs_hotkey_name_map_node_t) * name_map->num_leaves;
|
||||
name_map->leaves = bzalloc(size);
|
||||
|
||||
#define OBS_HOTKEY(x) obs_hotkey_name_map_insert(name_map, #x, x);
|
||||
#include "obs-hotkeys.h"
|
||||
#undef OBS_HOTKEY
|
||||
}
|
||||
|
||||
obs_key_t obs_key_from_name(const char *name)
|
||||
{
|
||||
if (!obs)
|
||||
return obs_key_from_name_fallback(name);
|
||||
|
||||
if (pthread_once(&obs->hotkeys.name_map_init_token, init_name_map))
|
||||
return obs_key_from_name_fallback(name);
|
||||
|
||||
int v = 0;
|
||||
if (obs_hotkey_name_map_lookup(obs->hotkeys.name_map, name, &v))
|
||||
return v;
|
||||
|
||||
return OBS_KEY_NONE;
|
||||
}
|
||||
|
||||
static void free_node(obs_hotkey_name_map_node_t *node, bool release);
|
||||
|
||||
static void free_edge(obs_hotkey_name_map_edge_t *edge)
|
||||
{
|
||||
free_node(edge->node, true);
|
||||
|
||||
if (edge->prefix_len < NAME_MAP_COMPRESS_LENGTH)
|
||||
return;
|
||||
|
||||
bfree(get_prefix(edge));
|
||||
}
|
||||
|
||||
static void free_node(obs_hotkey_name_map_node_t *node, bool release)
|
||||
{
|
||||
if (!node->is_leaf) {
|
||||
for (size_t i = 0; i < node->children.num; i++)
|
||||
free_edge(&node->children.array[i]);
|
||||
|
||||
da_free(node->children);
|
||||
}
|
||||
|
||||
if (release && !node->is_leaf) bfree(node);
|
||||
}
|
||||
|
||||
void obs_hotkey_name_map_free(void)
|
||||
{
|
||||
if (!obs || !obs->hotkeys.name_map)
|
||||
return;
|
||||
|
||||
free_node(&obs->hotkeys.name_map->root, false);
|
||||
bfree(obs->hotkeys.name_map->leaves);
|
||||
bfree(obs->hotkeys.name_map);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,287 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2014-2015 by Ruwen Hahn <palana@stunned.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef size_t obs_hotkey_id;
|
||||
#define OBS_INVALID_HOTKEY_ID (~(obs_hotkey_id)0)
|
||||
typedef size_t obs_hotkey_pair_id;
|
||||
#define OBS_INVALID_HOTKEY_PAIR_ID (~(obs_hotkey_pair_id)0)
|
||||
|
||||
enum obs_key {
|
||||
#define OBS_HOTKEY(x) x,
|
||||
#include "obs-hotkeys.h"
|
||||
#undef OBS_HOTKEY
|
||||
OBS_KEY_LAST_VALUE //not an actual key
|
||||
};
|
||||
typedef enum obs_key obs_key_t;
|
||||
|
||||
struct obs_key_combination {
|
||||
uint32_t modifiers;
|
||||
obs_key_t key;
|
||||
};
|
||||
typedef struct obs_key_combination obs_key_combination_t;
|
||||
|
||||
typedef struct obs_hotkey obs_hotkey_t;
|
||||
typedef struct obs_hotkey_binding obs_hotkey_binding_t;
|
||||
|
||||
enum obs_hotkey_registerer_type {
|
||||
OBS_HOTKEY_REGISTERER_FRONTEND,
|
||||
OBS_HOTKEY_REGISTERER_SOURCE,
|
||||
OBS_HOTKEY_REGISTERER_OUTPUT,
|
||||
OBS_HOTKEY_REGISTERER_ENCODER,
|
||||
OBS_HOTKEY_REGISTERER_SERVICE,
|
||||
};
|
||||
typedef enum obs_hotkey_registerer_type obs_hotkey_registerer_t;
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_get_id(const obs_hotkey_t *key);
|
||||
EXPORT const char *obs_hotkey_get_name(const obs_hotkey_t *key);
|
||||
EXPORT const char *obs_hotkey_get_description(const obs_hotkey_t *key);
|
||||
EXPORT obs_hotkey_registerer_t obs_hotkey_get_registerer_type(
|
||||
const obs_hotkey_t *key);
|
||||
EXPORT void *obs_hotkey_get_registerer(const obs_hotkey_t *key);
|
||||
EXPORT obs_hotkey_id obs_hotkey_get_pair_partner_id(const obs_hotkey_t *key);
|
||||
|
||||
|
||||
EXPORT obs_key_combination_t obs_hotkey_binding_get_key_combination(
|
||||
obs_hotkey_binding_t *binding);
|
||||
EXPORT obs_hotkey_id obs_hotkey_binding_get_hotkey_id(
|
||||
obs_hotkey_binding_t *binding);
|
||||
EXPORT obs_hotkey_t *obs_hotkey_binding_get_hotkey(
|
||||
obs_hotkey_binding_t *binding);
|
||||
|
||||
struct obs_hotkeys_translations {
|
||||
const char *insert;
|
||||
const char *del;
|
||||
const char *home;
|
||||
const char *end;
|
||||
const char *page_up;
|
||||
const char *page_down;
|
||||
const char *num_lock;
|
||||
const char *scroll_lock;
|
||||
const char *caps_lock;
|
||||
const char *backspace;
|
||||
const char *tab;
|
||||
const char *print;
|
||||
const char *pause;
|
||||
const char *left;
|
||||
const char *right;
|
||||
const char *up;
|
||||
const char *down;
|
||||
const char *shift;
|
||||
const char *alt;
|
||||
const char *control;
|
||||
const char *meta; /* windows/super key */
|
||||
const char *menu;
|
||||
const char *space;
|
||||
const char *numpad_num; /* For example, "Numpad %1" */
|
||||
const char *numpad_divide;
|
||||
const char *numpad_multiply;
|
||||
const char *numpad_minus;
|
||||
const char *numpad_plus;
|
||||
const char *numpad_decimal;
|
||||
const char *apple_keypad_num; /* For example, "%1 (Keypad)" */
|
||||
const char *apple_keypad_divide;
|
||||
const char *apple_keypad_multiply;
|
||||
const char *apple_keypad_minus;
|
||||
const char *apple_keypad_plus;
|
||||
const char *apple_keypad_decimal;
|
||||
const char *apple_keypad_equal;
|
||||
const char *mouse_num; /* For example, "Mouse %1" */
|
||||
};
|
||||
|
||||
/* This function is an optional way to provide translations for specific keys
|
||||
* that may not have translations. If the operating system can provide
|
||||
* translations for these keys, it will use the operating system's translation
|
||||
* over these translations. If no translations are specified, it will use
|
||||
* the default english translations for that specific operating system. */
|
||||
EXPORT void obs_hotkeys_set_translations_s(
|
||||
struct obs_hotkeys_translations *translations, size_t size);
|
||||
|
||||
#define obs_hotkeys_set_translations(translations) \
|
||||
obs_hotkeys_set_translations_s(translations, \
|
||||
sizeof(struct obs_hotkeys_translations))
|
||||
|
||||
EXPORT void obs_hotkeys_set_audio_hotkeys_translations(
|
||||
const char *mute, const char *unmute,
|
||||
const char *push_to_mute, const char *push_to_talk);
|
||||
|
||||
EXPORT void obs_hotkeys_set_sceneitem_hotkeys_translations(
|
||||
const char *show, const char *hide);
|
||||
|
||||
/* registering hotkeys (giving hotkeys a name and a function) */
|
||||
|
||||
typedef void (*obs_hotkey_func)(void *data,
|
||||
obs_hotkey_id id, obs_hotkey_t *hotkey, bool pressed);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_frontend(const char *name,
|
||||
const char *description, obs_hotkey_func func, void *data);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_encoder(obs_encoder_t *encoder,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_output(obs_output_t *output,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_service(obs_service_t *service,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data);
|
||||
|
||||
EXPORT obs_hotkey_id obs_hotkey_register_source(obs_source_t *source,
|
||||
const char *name, const char *description,
|
||||
obs_hotkey_func func, void *data);
|
||||
|
||||
typedef bool (*obs_hotkey_active_func)(void *data,
|
||||
obs_hotkey_pair_id id, obs_hotkey_t *hotkey, bool pressed);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_frontend(
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_encoder(
|
||||
obs_encoder_t *encoder,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_output(
|
||||
obs_output_t *output,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_service(
|
||||
obs_service_t *service,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
|
||||
EXPORT obs_hotkey_pair_id obs_hotkey_pair_register_source(
|
||||
obs_source_t *source,
|
||||
const char *name0, const char *description0,
|
||||
const char *name1, const char *description1,
|
||||
obs_hotkey_active_func func0, obs_hotkey_active_func func1,
|
||||
void *data0, void *data1);
|
||||
|
||||
EXPORT void obs_hotkey_unregister(obs_hotkey_id id);
|
||||
|
||||
EXPORT void obs_hotkey_pair_unregister(obs_hotkey_pair_id id);
|
||||
|
||||
/* loading hotkeys (associating a hotkey with a physical key and modifiers) */
|
||||
|
||||
EXPORT void obs_hotkey_load_bindings(obs_hotkey_id id,
|
||||
obs_key_combination_t *combinations, size_t num);
|
||||
|
||||
EXPORT void obs_hotkey_load(obs_hotkey_id id, obs_data_array_t *data);
|
||||
|
||||
EXPORT void obs_hotkeys_load_encoder(obs_encoder_t *encoder,
|
||||
obs_data_t *hotkeys);
|
||||
|
||||
EXPORT void obs_hotkeys_load_output(obs_output_t *output, obs_data_t *hotkeys);
|
||||
|
||||
EXPORT void obs_hotkeys_load_service(obs_service_t *service,
|
||||
obs_data_t *hotkeys);
|
||||
|
||||
EXPORT void obs_hotkeys_load_source(obs_source_t *source, obs_data_t *hotkeys);
|
||||
|
||||
EXPORT void obs_hotkey_pair_load(obs_hotkey_pair_id id, obs_data_array_t *data0,
|
||||
obs_data_array_t *data1);
|
||||
|
||||
|
||||
EXPORT obs_data_array_t *obs_hotkey_save(obs_hotkey_id id);
|
||||
|
||||
EXPORT obs_data_t *obs_hotkeys_save_encoder(obs_encoder_t *encoder);
|
||||
|
||||
EXPORT obs_data_t *obs_hotkeys_save_output(obs_output_t *output);
|
||||
|
||||
EXPORT obs_data_t *obs_hotkeys_save_service(obs_service_t *service);
|
||||
|
||||
EXPORT obs_data_t *obs_hotkeys_save_source(obs_source_t *source);
|
||||
|
||||
/* enumerating hotkeys */
|
||||
|
||||
typedef bool (*obs_hotkey_enum_func)(void *data,
|
||||
obs_hotkey_id id, obs_hotkey_t *key);
|
||||
|
||||
EXPORT void obs_enum_hotkeys(obs_hotkey_enum_func func, void *data);
|
||||
|
||||
/* enumerating bindings */
|
||||
|
||||
typedef bool (*obs_hotkey_binding_enum_func)(void *data,
|
||||
size_t idx, obs_hotkey_binding_t* binding);
|
||||
|
||||
EXPORT void obs_enum_hotkey_bindings(obs_hotkey_binding_enum_func func,
|
||||
void *data);
|
||||
|
||||
/* hotkey event control */
|
||||
|
||||
EXPORT void obs_hotkey_inject_event(obs_key_combination_t hotkey, bool pressed);
|
||||
|
||||
EXPORT void obs_hotkey_enable_background_press(bool enable);
|
||||
|
||||
EXPORT void obs_hotkey_enable_strict_modifiers(bool enable);
|
||||
|
||||
/* hotkey callback routing (trigger callbacks through e.g. a UI thread) */
|
||||
|
||||
typedef void (*obs_hotkey_callback_router_func)(void *data,
|
||||
obs_hotkey_id id, bool pressed);
|
||||
|
||||
EXPORT void obs_hotkey_set_callback_routing_func(obs_hotkey_callback_router_func
|
||||
func, void *data);
|
||||
|
||||
EXPORT void obs_hotkey_trigger_routed_callback(obs_hotkey_id id, bool pressed);
|
||||
|
||||
/* hotkey callbacks won't be processed if callback rerouting is enabled and no
|
||||
* router func is set */
|
||||
EXPORT void obs_hotkey_enable_callback_rerouting(bool enable);
|
||||
|
||||
/* misc */
|
||||
|
||||
typedef void (*obs_hotkey_atomic_update_func)(void *);
|
||||
EXPORT void obs_hotkey_update_atomic(obs_hotkey_atomic_update_func func,
|
||||
void *data);
|
||||
|
||||
struct dstr;
|
||||
EXPORT void obs_key_to_str(obs_key_t key, struct dstr *str);
|
||||
EXPORT void obs_key_combination_to_str(obs_key_combination_t key,
|
||||
struct dstr *str);
|
||||
|
||||
EXPORT obs_key_t obs_key_from_virtual_key(int code);
|
||||
EXPORT int obs_key_to_virtual_key(obs_key_t key);
|
||||
|
||||
EXPORT const char *obs_key_to_name(obs_key_t key);
|
||||
EXPORT obs_key_t obs_key_from_name(const char *name);
|
||||
|
||||
inline bool obs_key_combination_is_empty(obs_key_combination_t combo)
|
||||
{
|
||||
return !combo.modifiers && combo.key == OBS_KEY_NONE;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,477 @@
|
|||
OBS_HOTKEY(OBS_KEY_NONE)
|
||||
|
||||
OBS_HOTKEY(OBS_KEY_RETURN)
|
||||
OBS_HOTKEY(OBS_KEY_ENTER)
|
||||
OBS_HOTKEY(OBS_KEY_ESCAPE)
|
||||
OBS_HOTKEY(OBS_KEY_TAB)
|
||||
OBS_HOTKEY(OBS_KEY_BACKTAB)
|
||||
OBS_HOTKEY(OBS_KEY_BACKSPACE)
|
||||
OBS_HOTKEY(OBS_KEY_INSERT)
|
||||
OBS_HOTKEY(OBS_KEY_DELETE)
|
||||
OBS_HOTKEY(OBS_KEY_PAUSE)
|
||||
OBS_HOTKEY(OBS_KEY_PRINT)
|
||||
OBS_HOTKEY(OBS_KEY_SYSREQ)
|
||||
OBS_HOTKEY(OBS_KEY_CLEAR)
|
||||
OBS_HOTKEY(OBS_KEY_HOME)
|
||||
OBS_HOTKEY(OBS_KEY_END)
|
||||
OBS_HOTKEY(OBS_KEY_LEFT)
|
||||
OBS_HOTKEY(OBS_KEY_UP)
|
||||
OBS_HOTKEY(OBS_KEY_RIGHT)
|
||||
OBS_HOTKEY(OBS_KEY_DOWN)
|
||||
OBS_HOTKEY(OBS_KEY_PAGEUP)
|
||||
OBS_HOTKEY(OBS_KEY_PAGEDOWN)
|
||||
|
||||
OBS_HOTKEY(OBS_KEY_SHIFT)
|
||||
OBS_HOTKEY(OBS_KEY_CONTROL)
|
||||
OBS_HOTKEY(OBS_KEY_META)
|
||||
OBS_HOTKEY(OBS_KEY_ALT)
|
||||
OBS_HOTKEY(OBS_KEY_ALTGR)
|
||||
OBS_HOTKEY(OBS_KEY_CAPSLOCK)
|
||||
OBS_HOTKEY(OBS_KEY_NUMLOCK)
|
||||
OBS_HOTKEY(OBS_KEY_SCROLLLOCK)
|
||||
|
||||
OBS_HOTKEY(OBS_KEY_F1)
|
||||
OBS_HOTKEY(OBS_KEY_F2)
|
||||
OBS_HOTKEY(OBS_KEY_F3)
|
||||
OBS_HOTKEY(OBS_KEY_F4)
|
||||
OBS_HOTKEY(OBS_KEY_F5)
|
||||
OBS_HOTKEY(OBS_KEY_F6)
|
||||
OBS_HOTKEY(OBS_KEY_F7)
|
||||
OBS_HOTKEY(OBS_KEY_F8)
|
||||
OBS_HOTKEY(OBS_KEY_F9)
|
||||
OBS_HOTKEY(OBS_KEY_F10)
|
||||
OBS_HOTKEY(OBS_KEY_F11)
|
||||
OBS_HOTKEY(OBS_KEY_F12)
|
||||
OBS_HOTKEY(OBS_KEY_F13)
|
||||
OBS_HOTKEY(OBS_KEY_F14)
|
||||
OBS_HOTKEY(OBS_KEY_F15)
|
||||
OBS_HOTKEY(OBS_KEY_F16)
|
||||
OBS_HOTKEY(OBS_KEY_F17)
|
||||
OBS_HOTKEY(OBS_KEY_F18)
|
||||
OBS_HOTKEY(OBS_KEY_F19)
|
||||
OBS_HOTKEY(OBS_KEY_F20)
|
||||
OBS_HOTKEY(OBS_KEY_F21)
|
||||
OBS_HOTKEY(OBS_KEY_F22)
|
||||
OBS_HOTKEY(OBS_KEY_F23)
|
||||
OBS_HOTKEY(OBS_KEY_F24)
|
||||
OBS_HOTKEY(OBS_KEY_F25)
|
||||
OBS_HOTKEY(OBS_KEY_F26)
|
||||
OBS_HOTKEY(OBS_KEY_F27)
|
||||
OBS_HOTKEY(OBS_KEY_F28)
|
||||
OBS_HOTKEY(OBS_KEY_F29)
|
||||
OBS_HOTKEY(OBS_KEY_F30)
|
||||
OBS_HOTKEY(OBS_KEY_F31)
|
||||
OBS_HOTKEY(OBS_KEY_F32)
|
||||
OBS_HOTKEY(OBS_KEY_F33)
|
||||
OBS_HOTKEY(OBS_KEY_F34)
|
||||
OBS_HOTKEY(OBS_KEY_F35)
|
||||
|
||||
OBS_HOTKEY(OBS_KEY_MENU)
|
||||
OBS_HOTKEY(OBS_KEY_HYPER_L)
|
||||
OBS_HOTKEY(OBS_KEY_HYPER_R)
|
||||
OBS_HOTKEY(OBS_KEY_HELP)
|
||||
OBS_HOTKEY(OBS_KEY_DIRECTION_L)
|
||||
OBS_HOTKEY(OBS_KEY_DIRECTION_R)
|
||||
|
||||
OBS_HOTKEY(OBS_KEY_SPACE)
|
||||
OBS_HOTKEY(OBS_KEY_EXCLAM)
|
||||
OBS_HOTKEY(OBS_KEY_QUOTEDBL)
|
||||
OBS_HOTKEY(OBS_KEY_NUMBERSIGN)
|
||||
OBS_HOTKEY(OBS_KEY_DOLLAR)
|
||||
OBS_HOTKEY(OBS_KEY_PERCENT)
|
||||
OBS_HOTKEY(OBS_KEY_AMPERSAND)
|
||||
OBS_HOTKEY(OBS_KEY_APOSTROPHE)
|
||||
OBS_HOTKEY(OBS_KEY_PARENLEFT)
|
||||
OBS_HOTKEY(OBS_KEY_PARENRIGHT)
|
||||
OBS_HOTKEY(OBS_KEY_ASTERISK)
|
||||
OBS_HOTKEY(OBS_KEY_PLUS)
|
||||
OBS_HOTKEY(OBS_KEY_COMMA)
|
||||
OBS_HOTKEY(OBS_KEY_MINUS)
|
||||
OBS_HOTKEY(OBS_KEY_PERIOD)
|
||||
OBS_HOTKEY(OBS_KEY_SLASH)
|
||||
OBS_HOTKEY(OBS_KEY_0)
|
||||
OBS_HOTKEY(OBS_KEY_1)
|
||||
OBS_HOTKEY(OBS_KEY_2)
|
||||
OBS_HOTKEY(OBS_KEY_3)
|
||||
OBS_HOTKEY(OBS_KEY_4)
|
||||
OBS_HOTKEY(OBS_KEY_5)
|
||||
OBS_HOTKEY(OBS_KEY_6)
|
||||
OBS_HOTKEY(OBS_KEY_7)
|
||||
OBS_HOTKEY(OBS_KEY_8)
|
||||
OBS_HOTKEY(OBS_KEY_9)
|
||||
OBS_HOTKEY(OBS_KEY_NUMEQUAL)
|
||||
OBS_HOTKEY(OBS_KEY_NUMASTERISK)
|
||||
OBS_HOTKEY(OBS_KEY_NUMPLUS)
|
||||
OBS_HOTKEY(OBS_KEY_NUMCOMMA)
|
||||
OBS_HOTKEY(OBS_KEY_NUMMINUS)
|
||||
OBS_HOTKEY(OBS_KEY_NUMPERIOD)
|
||||
OBS_HOTKEY(OBS_KEY_NUMSLASH)
|
||||
OBS_HOTKEY(OBS_KEY_NUM0)
|
||||
OBS_HOTKEY(OBS_KEY_NUM1)
|
||||
OBS_HOTKEY(OBS_KEY_NUM2)
|
||||
OBS_HOTKEY(OBS_KEY_NUM3)
|
||||
OBS_HOTKEY(OBS_KEY_NUM4)
|
||||
OBS_HOTKEY(OBS_KEY_NUM5)
|
||||
OBS_HOTKEY(OBS_KEY_NUM6)
|
||||
OBS_HOTKEY(OBS_KEY_NUM7)
|
||||
OBS_HOTKEY(OBS_KEY_NUM8)
|
||||
OBS_HOTKEY(OBS_KEY_NUM9)
|
||||
OBS_HOTKEY(OBS_KEY_COLON)
|
||||
OBS_HOTKEY(OBS_KEY_SEMICOLON)
|
||||
OBS_HOTKEY(OBS_KEY_QUOTE)
|
||||
OBS_HOTKEY(OBS_KEY_LESS)
|
||||
OBS_HOTKEY(OBS_KEY_EQUAL)
|
||||
OBS_HOTKEY(OBS_KEY_GREATER)
|
||||
OBS_HOTKEY(OBS_KEY_QUESTION)
|
||||
OBS_HOTKEY(OBS_KEY_AT)
|
||||
OBS_HOTKEY(OBS_KEY_A)
|
||||
OBS_HOTKEY(OBS_KEY_B)
|
||||
OBS_HOTKEY(OBS_KEY_C)
|
||||
OBS_HOTKEY(OBS_KEY_D)
|
||||
OBS_HOTKEY(OBS_KEY_E)
|
||||
OBS_HOTKEY(OBS_KEY_F)
|
||||
OBS_HOTKEY(OBS_KEY_G)
|
||||
OBS_HOTKEY(OBS_KEY_H)
|
||||
OBS_HOTKEY(OBS_KEY_I)
|
||||
OBS_HOTKEY(OBS_KEY_J)
|
||||
OBS_HOTKEY(OBS_KEY_K)
|
||||
OBS_HOTKEY(OBS_KEY_L)
|
||||
OBS_HOTKEY(OBS_KEY_M)
|
||||
OBS_HOTKEY(OBS_KEY_N)
|
||||
OBS_HOTKEY(OBS_KEY_O)
|
||||
OBS_HOTKEY(OBS_KEY_P)
|
||||
OBS_HOTKEY(OBS_KEY_Q)
|
||||
OBS_HOTKEY(OBS_KEY_R)
|
||||
OBS_HOTKEY(OBS_KEY_S)
|
||||
OBS_HOTKEY(OBS_KEY_T)
|
||||
OBS_HOTKEY(OBS_KEY_U)
|
||||
OBS_HOTKEY(OBS_KEY_V)
|
||||
OBS_HOTKEY(OBS_KEY_W)
|
||||
OBS_HOTKEY(OBS_KEY_X)
|
||||
OBS_HOTKEY(OBS_KEY_Y)
|
||||
OBS_HOTKEY(OBS_KEY_Z)
|
||||
OBS_HOTKEY(OBS_KEY_BRACKETLEFT)
|
||||
OBS_HOTKEY(OBS_KEY_BACKSLASH)
|
||||
OBS_HOTKEY(OBS_KEY_BRACKETRIGHT)
|
||||
OBS_HOTKEY(OBS_KEY_ASCIICIRCUM)
|
||||
OBS_HOTKEY(OBS_KEY_UNDERSCORE)
|
||||
OBS_HOTKEY(OBS_KEY_QUOTELEFT)
|
||||
OBS_HOTKEY(OBS_KEY_BRACELEFT)
|
||||
OBS_HOTKEY(OBS_KEY_BAR)
|
||||
OBS_HOTKEY(OBS_KEY_BRACERIGHT)
|
||||
OBS_HOTKEY(OBS_KEY_ASCIITILDE)
|
||||
OBS_HOTKEY(OBS_KEY_NOBREAKSPACE)
|
||||
OBS_HOTKEY(OBS_KEY_EXCLAMDOWN)
|
||||
OBS_HOTKEY(OBS_KEY_CENT)
|
||||
OBS_HOTKEY(OBS_KEY_STERLING)
|
||||
OBS_HOTKEY(OBS_KEY_CURRENCY)
|
||||
OBS_HOTKEY(OBS_KEY_YEN)
|
||||
OBS_HOTKEY(OBS_KEY_BROKENBAR)
|
||||
OBS_HOTKEY(OBS_KEY_SECTION)
|
||||
OBS_HOTKEY(OBS_KEY_DIAERESIS)
|
||||
OBS_HOTKEY(OBS_KEY_COPYRIGHT)
|
||||
OBS_HOTKEY(OBS_KEY_ORDFEMININE)
|
||||
OBS_HOTKEY(OBS_KEY_GUILLEMOTLEFT)
|
||||
OBS_HOTKEY(OBS_KEY_NOTSIGN)
|
||||
OBS_HOTKEY(OBS_KEY_HYPHEN)
|
||||
OBS_HOTKEY(OBS_KEY_REGISTERED)
|
||||
OBS_HOTKEY(OBS_KEY_MACRON)
|
||||
OBS_HOTKEY(OBS_KEY_DEGREE)
|
||||
OBS_HOTKEY(OBS_KEY_PLUSMINUS)
|
||||
OBS_HOTKEY(OBS_KEY_TWOSUPERIOR)
|
||||
OBS_HOTKEY(OBS_KEY_THREESUPERIOR)
|
||||
OBS_HOTKEY(OBS_KEY_ACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_MU)
|
||||
OBS_HOTKEY(OBS_KEY_PARAGRAPH)
|
||||
OBS_HOTKEY(OBS_KEY_PERIODCENTERED)
|
||||
OBS_HOTKEY(OBS_KEY_CEDILLA)
|
||||
OBS_HOTKEY(OBS_KEY_ONESUPERIOR)
|
||||
OBS_HOTKEY(OBS_KEY_MASCULINE)
|
||||
OBS_HOTKEY(OBS_KEY_GUILLEMOTRIGHT)
|
||||
OBS_HOTKEY(OBS_KEY_ONEQUARTER)
|
||||
OBS_HOTKEY(OBS_KEY_ONEHALF)
|
||||
OBS_HOTKEY(OBS_KEY_THREEQUARTERS)
|
||||
OBS_HOTKEY(OBS_KEY_QUESTIONDOWN)
|
||||
OBS_HOTKEY(OBS_KEY_AGRAVE)
|
||||
OBS_HOTKEY(OBS_KEY_AACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_ACIRCUMFLEX)
|
||||
OBS_HOTKEY(OBS_KEY_ATILDE)
|
||||
OBS_HOTKEY(OBS_KEY_ADIAERESIS)
|
||||
OBS_HOTKEY(OBS_KEY_ARING)
|
||||
OBS_HOTKEY(OBS_KEY_AE)
|
||||
OBS_HOTKEY(OBS_KEY_CCEDILLA)
|
||||
OBS_HOTKEY(OBS_KEY_EGRAVE)
|
||||
OBS_HOTKEY(OBS_KEY_EACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_ECIRCUMFLEX)
|
||||
OBS_HOTKEY(OBS_KEY_EDIAERESIS)
|
||||
OBS_HOTKEY(OBS_KEY_IGRAVE)
|
||||
OBS_HOTKEY(OBS_KEY_IACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_ICIRCUMFLEX)
|
||||
OBS_HOTKEY(OBS_KEY_IDIAERESIS)
|
||||
OBS_HOTKEY(OBS_KEY_ETH)
|
||||
OBS_HOTKEY(OBS_KEY_NTILDE)
|
||||
OBS_HOTKEY(OBS_KEY_OGRAVE)
|
||||
OBS_HOTKEY(OBS_KEY_OACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_OCIRCUMFLEX)
|
||||
OBS_HOTKEY(OBS_KEY_OTILDE)
|
||||
OBS_HOTKEY(OBS_KEY_ODIAERESIS)
|
||||
OBS_HOTKEY(OBS_KEY_MULTIPLY)
|
||||
OBS_HOTKEY(OBS_KEY_OOBLIQUE)
|
||||
OBS_HOTKEY(OBS_KEY_UGRAVE)
|
||||
OBS_HOTKEY(OBS_KEY_UACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_UCIRCUMFLEX)
|
||||
OBS_HOTKEY(OBS_KEY_UDIAERESIS)
|
||||
OBS_HOTKEY(OBS_KEY_YACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_THORN)
|
||||
OBS_HOTKEY(OBS_KEY_SSHARP)
|
||||
OBS_HOTKEY(OBS_KEY_DIVISION)
|
||||
OBS_HOTKEY(OBS_KEY_YDIAERESIS)
|
||||
OBS_HOTKEY(OBS_KEY_MULTI_KEY)
|
||||
OBS_HOTKEY(OBS_KEY_CODEINPUT)
|
||||
OBS_HOTKEY(OBS_KEY_SINGLECANDIDATE)
|
||||
OBS_HOTKEY(OBS_KEY_MULTIPLECANDIDATE)
|
||||
OBS_HOTKEY(OBS_KEY_PREVIOUSCANDIDATE)
|
||||
OBS_HOTKEY(OBS_KEY_MODE_SWITCH)
|
||||
OBS_HOTKEY(OBS_KEY_KANJI)
|
||||
OBS_HOTKEY(OBS_KEY_MUHENKAN)
|
||||
OBS_HOTKEY(OBS_KEY_HENKAN)
|
||||
OBS_HOTKEY(OBS_KEY_ROMAJI)
|
||||
OBS_HOTKEY(OBS_KEY_HIRAGANA)
|
||||
OBS_HOTKEY(OBS_KEY_KATAKANA)
|
||||
OBS_HOTKEY(OBS_KEY_HIRAGANA_KATAKANA)
|
||||
OBS_HOTKEY(OBS_KEY_ZENKAKU)
|
||||
OBS_HOTKEY(OBS_KEY_HANKAKU)
|
||||
OBS_HOTKEY(OBS_KEY_ZENKAKU_HANKAKU)
|
||||
OBS_HOTKEY(OBS_KEY_TOUROKU)
|
||||
OBS_HOTKEY(OBS_KEY_MASSYO)
|
||||
OBS_HOTKEY(OBS_KEY_KANA_LOCK)
|
||||
OBS_HOTKEY(OBS_KEY_KANA_SHIFT)
|
||||
OBS_HOTKEY(OBS_KEY_EISU_SHIFT)
|
||||
OBS_HOTKEY(OBS_KEY_EISU_TOGGLE)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_START)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_END)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_HANJA)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_JAMO)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_ROMAJA)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_JEONJA)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_BANJA)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_PREHANJA)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_POSTHANJA)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUL_SPECIAL)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_GRAVE)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_ACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_CIRCUMFLEX)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_TILDE)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_MACRON)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_BREVE)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_ABOVEDOT)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_DIAERESIS)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_ABOVERING)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_DOUBLEACUTE)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_CARON)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_CEDILLA)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_OGONEK)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_IOTA)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_VOICED_SOUND)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_SEMIVOICED_SOUND)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_BELOWDOT)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_HOOK)
|
||||
OBS_HOTKEY(OBS_KEY_DEAD_HORN)
|
||||
OBS_HOTKEY(OBS_KEY_BACK)
|
||||
OBS_HOTKEY(OBS_KEY_FORWARD)
|
||||
OBS_HOTKEY(OBS_KEY_STOP)
|
||||
OBS_HOTKEY(OBS_KEY_REFRESH)
|
||||
OBS_HOTKEY(OBS_KEY_VOLUMEDOWN)
|
||||
OBS_HOTKEY(OBS_KEY_VOLUMEMUTE)
|
||||
OBS_HOTKEY(OBS_KEY_VOLUMEUP)
|
||||
OBS_HOTKEY(OBS_KEY_BASSBOOST)
|
||||
OBS_HOTKEY(OBS_KEY_BASSUP)
|
||||
OBS_HOTKEY(OBS_KEY_BASSDOWN)
|
||||
OBS_HOTKEY(OBS_KEY_TREBLEUP)
|
||||
OBS_HOTKEY(OBS_KEY_TREBLEDOWN)
|
||||
OBS_HOTKEY(OBS_KEY_MEDIAPLAY)
|
||||
OBS_HOTKEY(OBS_KEY_MEDIASTOP)
|
||||
OBS_HOTKEY(OBS_KEY_MEDIAPREVIOUS)
|
||||
OBS_HOTKEY(OBS_KEY_MEDIANEXT)
|
||||
OBS_HOTKEY(OBS_KEY_MEDIARECORD)
|
||||
OBS_HOTKEY(OBS_KEY_MEDIAPAUSE)
|
||||
OBS_HOTKEY(OBS_KEY_MEDIATOGGLEPLAYPAUSE)
|
||||
OBS_HOTKEY(OBS_KEY_HOMEPAGE)
|
||||
OBS_HOTKEY(OBS_KEY_FAVORITES)
|
||||
OBS_HOTKEY(OBS_KEY_SEARCH)
|
||||
OBS_HOTKEY(OBS_KEY_STANDBY)
|
||||
OBS_HOTKEY(OBS_KEY_OPENURL)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHMAIL)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHMEDIA)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH0)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH1)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH2)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH3)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH4)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH5)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH6)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH7)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH8)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCH9)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHA)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHB)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHC)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHD)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHE)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHF)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHG)
|
||||
OBS_HOTKEY(OBS_KEY_LAUNCHH)
|
||||
OBS_HOTKEY(OBS_KEY_MONBRIGHTNESSUP)
|
||||
OBS_HOTKEY(OBS_KEY_MONBRIGHTNESSDOWN)
|
||||
OBS_HOTKEY(OBS_KEY_KEYBOARDLIGHTONOFF)
|
||||
OBS_HOTKEY(OBS_KEY_KEYBOARDBRIGHTNESSUP)
|
||||
OBS_HOTKEY(OBS_KEY_KEYBOARDBRIGHTNESSDOWN)
|
||||
OBS_HOTKEY(OBS_KEY_POWEROFF)
|
||||
OBS_HOTKEY(OBS_KEY_WAKEUP)
|
||||
OBS_HOTKEY(OBS_KEY_EJECT)
|
||||
OBS_HOTKEY(OBS_KEY_SCREENSAVER)
|
||||
OBS_HOTKEY(OBS_KEY_WWW)
|
||||
OBS_HOTKEY(OBS_KEY_MEMO)
|
||||
OBS_HOTKEY(OBS_KEY_LIGHTBULB)
|
||||
OBS_HOTKEY(OBS_KEY_SHOP)
|
||||
OBS_HOTKEY(OBS_KEY_HISTORY)
|
||||
OBS_HOTKEY(OBS_KEY_ADDFAVORITE)
|
||||
OBS_HOTKEY(OBS_KEY_HOTLINKS)
|
||||
OBS_HOTKEY(OBS_KEY_BRIGHTNESSADJUST)
|
||||
OBS_HOTKEY(OBS_KEY_FINANCE)
|
||||
OBS_HOTKEY(OBS_KEY_COMMUNITY)
|
||||
OBS_HOTKEY(OBS_KEY_AUDIOREWIND)
|
||||
OBS_HOTKEY(OBS_KEY_BACKFORWARD)
|
||||
OBS_HOTKEY(OBS_KEY_APPLICATIONLEFT)
|
||||
OBS_HOTKEY(OBS_KEY_APPLICATIONRIGHT)
|
||||
OBS_HOTKEY(OBS_KEY_BOOK)
|
||||
OBS_HOTKEY(OBS_KEY_CD)
|
||||
OBS_HOTKEY(OBS_KEY_CALCULATOR)
|
||||
OBS_HOTKEY(OBS_KEY_TODOLIST)
|
||||
OBS_HOTKEY(OBS_KEY_CLEARGRAB)
|
||||
OBS_HOTKEY(OBS_KEY_CLOSE)
|
||||
OBS_HOTKEY(OBS_KEY_COPY)
|
||||
OBS_HOTKEY(OBS_KEY_CUT)
|
||||
OBS_HOTKEY(OBS_KEY_DISPLAY)
|
||||
OBS_HOTKEY(OBS_KEY_DOS)
|
||||
OBS_HOTKEY(OBS_KEY_DOCUMENTS)
|
||||
OBS_HOTKEY(OBS_KEY_EXCEL)
|
||||
OBS_HOTKEY(OBS_KEY_EXPLORER)
|
||||
OBS_HOTKEY(OBS_KEY_GAME)
|
||||
OBS_HOTKEY(OBS_KEY_GO)
|
||||
OBS_HOTKEY(OBS_KEY_ITOUCH)
|
||||
OBS_HOTKEY(OBS_KEY_LOGOFF)
|
||||
OBS_HOTKEY(OBS_KEY_MARKET)
|
||||
OBS_HOTKEY(OBS_KEY_MEETING)
|
||||
OBS_HOTKEY(OBS_KEY_MENUKB)
|
||||
OBS_HOTKEY(OBS_KEY_MENUPB)
|
||||
OBS_HOTKEY(OBS_KEY_MYSITES)
|
||||
OBS_HOTKEY(OBS_KEY_NEWS)
|
||||
OBS_HOTKEY(OBS_KEY_OFFICEHOME)
|
||||
OBS_HOTKEY(OBS_KEY_OPTION)
|
||||
OBS_HOTKEY(OBS_KEY_PASTE)
|
||||
OBS_HOTKEY(OBS_KEY_PHONE)
|
||||
OBS_HOTKEY(OBS_KEY_CALENDAR)
|
||||
OBS_HOTKEY(OBS_KEY_REPLY)
|
||||
OBS_HOTKEY(OBS_KEY_RELOAD)
|
||||
OBS_HOTKEY(OBS_KEY_ROTATEWINDOWS)
|
||||
OBS_HOTKEY(OBS_KEY_ROTATIONPB)
|
||||
OBS_HOTKEY(OBS_KEY_ROTATIONKB)
|
||||
OBS_HOTKEY(OBS_KEY_SAVE)
|
||||
OBS_HOTKEY(OBS_KEY_SEND)
|
||||
OBS_HOTKEY(OBS_KEY_SPELL)
|
||||
OBS_HOTKEY(OBS_KEY_SPLITSCREEN)
|
||||
OBS_HOTKEY(OBS_KEY_SUPPORT)
|
||||
OBS_HOTKEY(OBS_KEY_TASKPANE)
|
||||
OBS_HOTKEY(OBS_KEY_TERMINAL)
|
||||
OBS_HOTKEY(OBS_KEY_TOOLS)
|
||||
OBS_HOTKEY(OBS_KEY_TRAVEL)
|
||||
OBS_HOTKEY(OBS_KEY_VIDEO)
|
||||
OBS_HOTKEY(OBS_KEY_WORD)
|
||||
OBS_HOTKEY(OBS_KEY_XFER)
|
||||
OBS_HOTKEY(OBS_KEY_ZOOMIN)
|
||||
OBS_HOTKEY(OBS_KEY_ZOOMOUT)
|
||||
OBS_HOTKEY(OBS_KEY_AWAY)
|
||||
OBS_HOTKEY(OBS_KEY_MESSENGER)
|
||||
OBS_HOTKEY(OBS_KEY_WEBCAM)
|
||||
OBS_HOTKEY(OBS_KEY_MAILFORWARD)
|
||||
OBS_HOTKEY(OBS_KEY_PICTURES)
|
||||
OBS_HOTKEY(OBS_KEY_MUSIC)
|
||||
OBS_HOTKEY(OBS_KEY_BATTERY)
|
||||
OBS_HOTKEY(OBS_KEY_BLUETOOTH)
|
||||
OBS_HOTKEY(OBS_KEY_WLAN)
|
||||
OBS_HOTKEY(OBS_KEY_UWB)
|
||||
OBS_HOTKEY(OBS_KEY_AUDIOFORWARD)
|
||||
OBS_HOTKEY(OBS_KEY_AUDIOREPEAT)
|
||||
OBS_HOTKEY(OBS_KEY_AUDIORANDOMPLAY)
|
||||
OBS_HOTKEY(OBS_KEY_SUBTITLE)
|
||||
OBS_HOTKEY(OBS_KEY_AUDIOCYCLETRACK)
|
||||
OBS_HOTKEY(OBS_KEY_TIME)
|
||||
OBS_HOTKEY(OBS_KEY_HIBERNATE)
|
||||
OBS_HOTKEY(OBS_KEY_VIEW)
|
||||
OBS_HOTKEY(OBS_KEY_TOPMENU)
|
||||
OBS_HOTKEY(OBS_KEY_POWERDOWN)
|
||||
OBS_HOTKEY(OBS_KEY_SUSPEND)
|
||||
OBS_HOTKEY(OBS_KEY_CONTRASTADJUST)
|
||||
OBS_HOTKEY(OBS_KEY_MEDIALAST)
|
||||
OBS_HOTKEY(OBS_KEY_CALL)
|
||||
OBS_HOTKEY(OBS_KEY_CAMERA)
|
||||
OBS_HOTKEY(OBS_KEY_CAMERAFOCUS)
|
||||
OBS_HOTKEY(OBS_KEY_CONTEXT1)
|
||||
OBS_HOTKEY(OBS_KEY_CONTEXT2)
|
||||
OBS_HOTKEY(OBS_KEY_CONTEXT3)
|
||||
OBS_HOTKEY(OBS_KEY_CONTEXT4)
|
||||
OBS_HOTKEY(OBS_KEY_FLIP)
|
||||
OBS_HOTKEY(OBS_KEY_HANGUP)
|
||||
OBS_HOTKEY(OBS_KEY_NO)
|
||||
OBS_HOTKEY(OBS_KEY_SELECT)
|
||||
OBS_HOTKEY(OBS_KEY_YES)
|
||||
OBS_HOTKEY(OBS_KEY_TOGGLECALLHANGUP)
|
||||
OBS_HOTKEY(OBS_KEY_VOICEDIAL)
|
||||
OBS_HOTKEY(OBS_KEY_LASTNUMBERREDIAL)
|
||||
OBS_HOTKEY(OBS_KEY_EXECUTE)
|
||||
OBS_HOTKEY(OBS_KEY_PRINTER)
|
||||
OBS_HOTKEY(OBS_KEY_PLAY)
|
||||
OBS_HOTKEY(OBS_KEY_SLEEP)
|
||||
OBS_HOTKEY(OBS_KEY_ZOOM)
|
||||
OBS_HOTKEY(OBS_KEY_CANCEL)
|
||||
|
||||
|
||||
#ifndef OBS_MOUSE_BUTTON
|
||||
#define OBS_MOUSE_BUTTON(x) OBS_HOTKEY(x)
|
||||
#define OBS_MOUSE_BUTTON_DEFAULT 1
|
||||
#endif
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE1)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE2)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE3)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE4)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE5)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE6)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE7)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE8)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE9)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE10)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE11)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE12)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE13)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE14)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE15)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE16)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE17)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE18)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE19)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE20)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE21)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE22)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE23)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE24)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE25)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE26)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE27)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE28)
|
||||
OBS_MOUSE_BUTTON(OBS_KEY_MOUSE29)
|
||||
#ifdef OBS_MOUSE_BUTTON_DEFAULT
|
||||
#undef OBS_MOUSE_BUTTON
|
||||
#undef OBS_MOUSE_BUTTON_DEFAULT
|
||||
#endif
|
|
@ -95,6 +95,65 @@ static inline bool check_path(const char *data, const char *path,
|
|||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* hotkeys */
|
||||
|
||||
struct obs_hotkey {
|
||||
obs_hotkey_id id;
|
||||
char *name;
|
||||
char *description;
|
||||
|
||||
obs_hotkey_func func;
|
||||
void *data;
|
||||
int pressed;
|
||||
|
||||
obs_hotkey_registerer_t registerer_type;
|
||||
void *registerer;
|
||||
|
||||
obs_hotkey_id pair_partner_id;
|
||||
};
|
||||
|
||||
struct obs_hotkey_pair {
|
||||
obs_hotkey_pair_id pair_id;
|
||||
obs_hotkey_id id[2];
|
||||
obs_hotkey_active_func func[2];
|
||||
bool pressed0 : 1;
|
||||
bool pressed1 : 1;
|
||||
void *data[2];
|
||||
};
|
||||
|
||||
typedef struct obs_hotkey_pair obs_hotkey_pair_t;
|
||||
|
||||
typedef struct obs_hotkeys_platform obs_hotkeys_platform_t;
|
||||
|
||||
void *obs_hotkey_thread(void *param);
|
||||
|
||||
struct obs_core_hotkeys;
|
||||
bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys);
|
||||
void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys);
|
||||
bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *context,
|
||||
obs_key_t key);
|
||||
|
||||
const char *obs_get_hotkey_translation(obs_key_t key, const char *def);
|
||||
|
||||
struct obs_context_data;
|
||||
void obs_hotkeys_context_release(struct obs_context_data *context);
|
||||
|
||||
void obs_hotkeys_free(void);
|
||||
|
||||
struct obs_hotkey_binding {
|
||||
obs_key_combination_t key;
|
||||
bool pressed : 1;
|
||||
bool modifiers_match : 1;
|
||||
|
||||
obs_hotkey_id hotkey_id;
|
||||
obs_hotkey_t *hotkey;
|
||||
};
|
||||
|
||||
struct obs_hotkey_name_map;
|
||||
void obs_hotkey_name_map_free(void);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* views */
|
||||
|
||||
|
@ -213,6 +272,41 @@ struct obs_core_data {
|
|||
volatile bool valid;
|
||||
};
|
||||
|
||||
/* user hotkeys */
|
||||
struct obs_core_hotkeys {
|
||||
pthread_mutex_t mutex;
|
||||
DARRAY(obs_hotkey_t) hotkeys;
|
||||
obs_hotkey_id next_id;
|
||||
DARRAY(obs_hotkey_pair_t) hotkey_pairs;
|
||||
obs_hotkey_pair_id next_pair_id;
|
||||
|
||||
pthread_t hotkey_thread;
|
||||
bool hotkey_thread_initialized;
|
||||
os_event_t *stop_event;
|
||||
bool thread_disable_press : 1;
|
||||
bool strict_modifiers : 1;
|
||||
bool reroute_hotkeys : 1;
|
||||
DARRAY(obs_hotkey_binding_t) bindings;
|
||||
|
||||
obs_hotkey_callback_router_func router_func;
|
||||
void *router_func_data;
|
||||
|
||||
obs_hotkeys_platform_t *platform_context;
|
||||
|
||||
pthread_once_t name_map_init_token;
|
||||
struct obs_hotkey_name_map *name_map;
|
||||
|
||||
signal_handler_t *signals;
|
||||
|
||||
char *translations[OBS_KEY_LAST_VALUE];
|
||||
char *mute;
|
||||
char *unmute;
|
||||
char *push_to_mute;
|
||||
char *push_to_talk;
|
||||
char *sceneitem_show;
|
||||
char *sceneitem_hide;
|
||||
};
|
||||
|
||||
struct obs_core {
|
||||
struct obs_module *first_module;
|
||||
DARRAY(struct obs_module_path) module_paths;
|
||||
|
@ -236,6 +330,7 @@ struct obs_core {
|
|||
struct obs_core_video video;
|
||||
struct obs_core_audio audio;
|
||||
struct obs_core_data data;
|
||||
struct obs_core_hotkeys hotkeys;
|
||||
};
|
||||
|
||||
extern struct obs_core *obs;
|
||||
|
@ -253,6 +348,10 @@ struct obs_context_data {
|
|||
signal_handler_t *signals;
|
||||
proc_handler_t *procs;
|
||||
|
||||
DARRAY(obs_hotkey_id) hotkeys;
|
||||
DARRAY(obs_hotkey_pair_id) hotkey_pairs;
|
||||
obs_data_t *hotkey_data;
|
||||
|
||||
DARRAY(char*) rename_cache;
|
||||
pthread_mutex_t rename_cache_mutex;
|
||||
|
||||
|
@ -264,7 +363,8 @@ struct obs_context_data {
|
|||
extern bool obs_context_data_init(
|
||||
struct obs_context_data *context,
|
||||
obs_data_t *settings,
|
||||
const char *name);
|
||||
const char *name,
|
||||
obs_data_t *hotkey_data);
|
||||
extern void obs_context_data_free(struct obs_context_data *context);
|
||||
|
||||
extern void obs_context_data_insert(struct obs_context_data *context,
|
||||
|
@ -418,12 +518,26 @@ struct obs_source {
|
|||
gs_texrender_t *filter_texrender;
|
||||
enum obs_allow_direct_render allow_direct;
|
||||
bool rendering_filter;
|
||||
|
||||
/* sources specific hotkeys */
|
||||
obs_hotkey_pair_id mute_unmute_key;
|
||||
obs_hotkey_id push_to_mute_key;
|
||||
obs_hotkey_id push_to_talk_key;
|
||||
bool push_to_mute_enabled : 1;
|
||||
bool push_to_mute_pressed : 1;
|
||||
bool push_to_talk_enabled : 1;
|
||||
bool push_to_talk_pressed : 1;
|
||||
uint64_t push_to_mute_delay;
|
||||
uint64_t push_to_mute_stop_time;
|
||||
uint64_t push_to_talk_delay;
|
||||
uint64_t push_to_talk_stop_time;
|
||||
};
|
||||
|
||||
extern const struct obs_source_info *find_source(struct darray *list,
|
||||
const char *id);
|
||||
extern bool obs_source_init_context(struct obs_source *source,
|
||||
obs_data_t *settings, const char *name);
|
||||
obs_data_t *settings, const char *name,
|
||||
obs_data_t *hotkey_data);
|
||||
extern bool obs_source_init(struct obs_source *source,
|
||||
const struct obs_source_info *info);
|
||||
|
||||
|
|
737
libobs/obs-nix.c
737
libobs/obs-nix.c
|
@ -24,6 +24,11 @@
|
|||
#endif
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xlib-xcb.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <inttypes.h>
|
||||
#include "util/dstr.h"
|
||||
#include "obs-internal.h"
|
||||
|
@ -227,3 +232,735 @@ void log_system_info(void)
|
|||
log_distribution_info();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* So here's how linux works with key mapping:
|
||||
*
|
||||
* First, there's a global key symbol enum (xcb_keysym_t) which has unique
|
||||
* values for all possible symbols keys can have (e.g., '1' and '!' are
|
||||
* different values).
|
||||
*
|
||||
* Then there's a key code (xcb_keycode_t), which is basically an index to the
|
||||
* actual key itself on the keyboard (e.g., '1' and '!' will share the same
|
||||
* value).
|
||||
*
|
||||
* xcb_keysym_t values should be given to libobs, and libobs will translate it
|
||||
* to an obs_key_t, and although xcb_keysym_t can differ ('!' vs '1'), it will
|
||||
* get the obs_key_t value that represents the actual key pressed; in other
|
||||
* words it will be based on the key code rather than the key symbol. The same
|
||||
* applies to checking key press states.
|
||||
*/
|
||||
|
||||
struct keycode_list {
|
||||
DARRAY(xcb_keycode_t) list;
|
||||
};
|
||||
|
||||
struct obs_hotkeys_platform {
|
||||
Display *display;
|
||||
xcb_keysym_t base_keysyms[OBS_KEY_LAST_VALUE];
|
||||
struct keycode_list keycodes[OBS_KEY_LAST_VALUE];
|
||||
xcb_keycode_t min_keycode;
|
||||
xcb_keycode_t super_l_code;
|
||||
xcb_keycode_t super_r_code;
|
||||
|
||||
/* stores a copy of the keysym map for keycodes */
|
||||
xcb_keysym_t *keysyms;
|
||||
int num_keysyms;
|
||||
int syms_per_code;
|
||||
};
|
||||
|
||||
#define MOUSE_1 (1<<16)
|
||||
#define MOUSE_2 (2<<16)
|
||||
#define MOUSE_3 (3<<16)
|
||||
#define MOUSE_4 (4<<16)
|
||||
#define MOUSE_5 (5<<16)
|
||||
|
||||
static int get_keysym(obs_key_t key)
|
||||
{
|
||||
switch (key) {
|
||||
case OBS_KEY_RETURN: return XK_Return;
|
||||
case OBS_KEY_ESCAPE: return XK_Escape;
|
||||
case OBS_KEY_TAB: return XK_Tab;
|
||||
case OBS_KEY_BACKSPACE: return XK_BackSpace;
|
||||
case OBS_KEY_INSERT: return XK_Insert;
|
||||
case OBS_KEY_DELETE: return XK_Delete;
|
||||
case OBS_KEY_PAUSE: return XK_Pause;
|
||||
case OBS_KEY_PRINT: return XK_Print;
|
||||
case OBS_KEY_HOME: return XK_Home;
|
||||
case OBS_KEY_END: return XK_End;
|
||||
case OBS_KEY_LEFT: return XK_Left;
|
||||
case OBS_KEY_UP: return XK_Up;
|
||||
case OBS_KEY_RIGHT: return XK_Right;
|
||||
case OBS_KEY_DOWN: return XK_Down;
|
||||
case OBS_KEY_PAGEUP: return XK_Prior;
|
||||
case OBS_KEY_PAGEDOWN: return XK_Next;
|
||||
|
||||
case OBS_KEY_SHIFT: return XK_Shift_L;
|
||||
case OBS_KEY_CONTROL: return XK_Control_L;
|
||||
case OBS_KEY_ALT: return XK_Alt_L;
|
||||
case OBS_KEY_CAPSLOCK: return XK_Caps_Lock;
|
||||
case OBS_KEY_NUMLOCK: return XK_Num_Lock;
|
||||
case OBS_KEY_SCROLLLOCK: return XK_Scroll_Lock;
|
||||
|
||||
case OBS_KEY_F1: return XK_F1;
|
||||
case OBS_KEY_F2: return XK_F2;
|
||||
case OBS_KEY_F3: return XK_F3;
|
||||
case OBS_KEY_F4: return XK_F4;
|
||||
case OBS_KEY_F5: return XK_F5;
|
||||
case OBS_KEY_F6: return XK_F6;
|
||||
case OBS_KEY_F7: return XK_F7;
|
||||
case OBS_KEY_F8: return XK_F8;
|
||||
case OBS_KEY_F9: return XK_F9;
|
||||
case OBS_KEY_F10: return XK_F10;
|
||||
case OBS_KEY_F11: return XK_F11;
|
||||
case OBS_KEY_F12: return XK_F12;
|
||||
case OBS_KEY_F13: return XK_F13;
|
||||
case OBS_KEY_F14: return XK_F14;
|
||||
case OBS_KEY_F15: return XK_F15;
|
||||
case OBS_KEY_F16: return XK_F16;
|
||||
case OBS_KEY_F17: return XK_F17;
|
||||
case OBS_KEY_F18: return XK_F18;
|
||||
case OBS_KEY_F19: return XK_F19;
|
||||
case OBS_KEY_F20: return XK_F20;
|
||||
case OBS_KEY_F21: return XK_F21;
|
||||
case OBS_KEY_F22: return XK_F22;
|
||||
case OBS_KEY_F23: return XK_F23;
|
||||
case OBS_KEY_F24: return XK_F24;
|
||||
|
||||
case OBS_KEY_MENU: return XK_Menu;
|
||||
case OBS_KEY_HYPER_L: return XK_Hyper_L;
|
||||
case OBS_KEY_HYPER_R: return XK_Hyper_R;
|
||||
case OBS_KEY_HELP: return XK_Help;
|
||||
case OBS_KEY_SPACE: return XK_space;
|
||||
|
||||
case OBS_KEY_EXCLAM: return XK_exclam;
|
||||
case OBS_KEY_QUOTEDBL: return XK_quotedbl;
|
||||
case OBS_KEY_NUMBERSIGN: return XK_numbersign;
|
||||
case OBS_KEY_DOLLAR: return XK_dollar;
|
||||
case OBS_KEY_PERCENT: return XK_percent;
|
||||
case OBS_KEY_AMPERSAND: return XK_ampersand;
|
||||
case OBS_KEY_APOSTROPHE: return XK_apostrophe;
|
||||
case OBS_KEY_PARENLEFT: return XK_parenleft;
|
||||
case OBS_KEY_PARENRIGHT: return XK_parenright;
|
||||
case OBS_KEY_ASTERISK: return XK_asterisk;
|
||||
case OBS_KEY_PLUS: return XK_plus;
|
||||
case OBS_KEY_COMMA: return XK_comma;
|
||||
case OBS_KEY_MINUS: return XK_minus;
|
||||
case OBS_KEY_PERIOD: return XK_period;
|
||||
case OBS_KEY_SLASH: return XK_slash;
|
||||
case OBS_KEY_0: return XK_0;
|
||||
case OBS_KEY_1: return XK_1;
|
||||
case OBS_KEY_2: return XK_2;
|
||||
case OBS_KEY_3: return XK_3;
|
||||
case OBS_KEY_4: return XK_4;
|
||||
case OBS_KEY_5: return XK_5;
|
||||
case OBS_KEY_6: return XK_6;
|
||||
case OBS_KEY_7: return XK_7;
|
||||
case OBS_KEY_8: return XK_8;
|
||||
case OBS_KEY_9: return XK_9;
|
||||
case OBS_KEY_NUMEQUAL: return XK_KP_Equal;
|
||||
case OBS_KEY_NUMASTERISK: return XK_KP_Multiply;
|
||||
case OBS_KEY_NUMPLUS: return XK_KP_Add;
|
||||
case OBS_KEY_NUMCOMMA: return XK_KP_Separator;
|
||||
case OBS_KEY_NUMMINUS: return XK_KP_Subtract;
|
||||
case OBS_KEY_NUMPERIOD: return XK_KP_Decimal;
|
||||
case OBS_KEY_NUMSLASH: return XK_KP_Divide;
|
||||
case OBS_KEY_NUM0: return XK_KP_0;
|
||||
case OBS_KEY_NUM1: return XK_KP_1;
|
||||
case OBS_KEY_NUM2: return XK_KP_2;
|
||||
case OBS_KEY_NUM3: return XK_KP_3;
|
||||
case OBS_KEY_NUM4: return XK_KP_4;
|
||||
case OBS_KEY_NUM5: return XK_KP_5;
|
||||
case OBS_KEY_NUM6: return XK_KP_6;
|
||||
case OBS_KEY_NUM7: return XK_KP_7;
|
||||
case OBS_KEY_NUM8: return XK_KP_8;
|
||||
case OBS_KEY_NUM9: return XK_KP_9;
|
||||
case OBS_KEY_COLON: return XK_colon;
|
||||
case OBS_KEY_SEMICOLON: return XK_semicolon;
|
||||
case OBS_KEY_LESS: return XK_less;
|
||||
case OBS_KEY_EQUAL: return XK_equal;
|
||||
case OBS_KEY_GREATER: return XK_greater;
|
||||
case OBS_KEY_QUESTION: return XK_question;
|
||||
case OBS_KEY_AT: return XK_at;
|
||||
case OBS_KEY_A: return XK_A;
|
||||
case OBS_KEY_B: return XK_B;
|
||||
case OBS_KEY_C: return XK_C;
|
||||
case OBS_KEY_D: return XK_D;
|
||||
case OBS_KEY_E: return XK_E;
|
||||
case OBS_KEY_F: return XK_F;
|
||||
case OBS_KEY_G: return XK_G;
|
||||
case OBS_KEY_H: return XK_H;
|
||||
case OBS_KEY_I: return XK_I;
|
||||
case OBS_KEY_J: return XK_J;
|
||||
case OBS_KEY_K: return XK_K;
|
||||
case OBS_KEY_L: return XK_L;
|
||||
case OBS_KEY_M: return XK_M;
|
||||
case OBS_KEY_N: return XK_N;
|
||||
case OBS_KEY_O: return XK_O;
|
||||
case OBS_KEY_P: return XK_P;
|
||||
case OBS_KEY_Q: return XK_Q;
|
||||
case OBS_KEY_R: return XK_R;
|
||||
case OBS_KEY_S: return XK_S;
|
||||
case OBS_KEY_T: return XK_T;
|
||||
case OBS_KEY_U: return XK_U;
|
||||
case OBS_KEY_V: return XK_V;
|
||||
case OBS_KEY_W: return XK_W;
|
||||
case OBS_KEY_X: return XK_X;
|
||||
case OBS_KEY_Y: return XK_Y;
|
||||
case OBS_KEY_Z: return XK_Z;
|
||||
case OBS_KEY_BRACKETLEFT: return XK_bracketleft;
|
||||
case OBS_KEY_BACKSLASH: return XK_backslash;
|
||||
case OBS_KEY_BRACKETRIGHT: return XK_bracketright;
|
||||
case OBS_KEY_ASCIICIRCUM: return XK_asciicircum;
|
||||
case OBS_KEY_UNDERSCORE: return XK_underscore;
|
||||
case OBS_KEY_QUOTELEFT: return XK_quoteleft;
|
||||
case OBS_KEY_BRACELEFT: return XK_braceleft;
|
||||
case OBS_KEY_BAR: return XK_bar;
|
||||
case OBS_KEY_BRACERIGHT: return XK_braceright;
|
||||
case OBS_KEY_ASCIITILDE: return XK_grave;
|
||||
case OBS_KEY_NOBREAKSPACE: return XK_nobreakspace;
|
||||
case OBS_KEY_EXCLAMDOWN: return XK_exclamdown;
|
||||
case OBS_KEY_CENT: return XK_cent;
|
||||
case OBS_KEY_STERLING: return XK_sterling;
|
||||
case OBS_KEY_CURRENCY: return XK_currency;
|
||||
case OBS_KEY_YEN: return XK_yen;
|
||||
case OBS_KEY_BROKENBAR: return XK_brokenbar;
|
||||
case OBS_KEY_SECTION: return XK_section;
|
||||
case OBS_KEY_DIAERESIS: return XK_diaeresis;
|
||||
case OBS_KEY_COPYRIGHT: return XK_copyright;
|
||||
case OBS_KEY_ORDFEMININE: return XK_ordfeminine;
|
||||
case OBS_KEY_GUILLEMOTLEFT: return XK_guillemotleft;
|
||||
case OBS_KEY_NOTSIGN: return XK_notsign;
|
||||
case OBS_KEY_HYPHEN: return XK_hyphen;
|
||||
case OBS_KEY_REGISTERED: return XK_registered;
|
||||
case OBS_KEY_MACRON: return XK_macron;
|
||||
case OBS_KEY_DEGREE: return XK_degree;
|
||||
case OBS_KEY_PLUSMINUS: return XK_plusminus;
|
||||
case OBS_KEY_TWOSUPERIOR: return XK_twosuperior;
|
||||
case OBS_KEY_THREESUPERIOR: return XK_threesuperior;
|
||||
case OBS_KEY_ACUTE: return XK_acute;
|
||||
case OBS_KEY_MU: return XK_mu;
|
||||
case OBS_KEY_PARAGRAPH: return XK_paragraph;
|
||||
case OBS_KEY_PERIODCENTERED: return XK_periodcentered;
|
||||
case OBS_KEY_CEDILLA: return XK_cedilla;
|
||||
case OBS_KEY_ONESUPERIOR: return XK_onesuperior;
|
||||
case OBS_KEY_MASCULINE: return XK_masculine;
|
||||
case OBS_KEY_GUILLEMOTRIGHT: return XK_guillemotright;
|
||||
case OBS_KEY_ONEQUARTER: return XK_onequarter;
|
||||
case OBS_KEY_ONEHALF: return XK_onehalf;
|
||||
case OBS_KEY_THREEQUARTERS: return XK_threequarters;
|
||||
case OBS_KEY_QUESTIONDOWN: return XK_questiondown;
|
||||
case OBS_KEY_AGRAVE: return XK_Agrave;
|
||||
case OBS_KEY_AACUTE: return XK_Aacute;
|
||||
case OBS_KEY_ACIRCUMFLEX: return XK_Acircumflex;
|
||||
case OBS_KEY_ATILDE: return XK_Atilde;
|
||||
case OBS_KEY_ADIAERESIS: return XK_Adiaeresis;
|
||||
case OBS_KEY_ARING: return XK_Aring;
|
||||
case OBS_KEY_AE: return XK_AE;
|
||||
case OBS_KEY_CCEDILLA: return XK_cedilla;
|
||||
case OBS_KEY_EGRAVE: return XK_Egrave;
|
||||
case OBS_KEY_EACUTE: return XK_Eacute;
|
||||
case OBS_KEY_ECIRCUMFLEX: return XK_Ecircumflex;
|
||||
case OBS_KEY_EDIAERESIS: return XK_Ediaeresis;
|
||||
case OBS_KEY_IGRAVE: return XK_Igrave;
|
||||
case OBS_KEY_IACUTE: return XK_Iacute;
|
||||
case OBS_KEY_ICIRCUMFLEX: return XK_Icircumflex;
|
||||
case OBS_KEY_IDIAERESIS: return XK_Idiaeresis;
|
||||
case OBS_KEY_ETH: return XK_ETH;
|
||||
case OBS_KEY_NTILDE: return XK_Ntilde;
|
||||
case OBS_KEY_OGRAVE: return XK_Ograve;
|
||||
case OBS_KEY_OACUTE: return XK_Oacute;
|
||||
case OBS_KEY_OCIRCUMFLEX: return XK_Ocircumflex;
|
||||
case OBS_KEY_ODIAERESIS: return XK_Odiaeresis;
|
||||
case OBS_KEY_MULTIPLY: return XK_multiply;
|
||||
case OBS_KEY_OOBLIQUE: return XK_Ooblique;
|
||||
case OBS_KEY_UGRAVE: return XK_Ugrave;
|
||||
case OBS_KEY_UACUTE: return XK_Uacute;
|
||||
case OBS_KEY_UCIRCUMFLEX: return XK_Ucircumflex;
|
||||
case OBS_KEY_UDIAERESIS: return XK_Udiaeresis;
|
||||
case OBS_KEY_YACUTE: return XK_Yacute;
|
||||
case OBS_KEY_THORN: return XK_Thorn;
|
||||
case OBS_KEY_SSHARP: return XK_ssharp;
|
||||
case OBS_KEY_DIVISION: return XK_division;
|
||||
case OBS_KEY_YDIAERESIS: return XK_Ydiaeresis;
|
||||
case OBS_KEY_MULTI_KEY: return XK_Multi_key;
|
||||
case OBS_KEY_CODEINPUT: return XK_Codeinput;
|
||||
case OBS_KEY_SINGLECANDIDATE: return XK_SingleCandidate;
|
||||
case OBS_KEY_MULTIPLECANDIDATE: return XK_MultipleCandidate;
|
||||
case OBS_KEY_PREVIOUSCANDIDATE: return XK_PreviousCandidate;
|
||||
case OBS_KEY_MODE_SWITCH: return XK_Mode_switch;
|
||||
case OBS_KEY_KANJI: return XK_Kanji;
|
||||
case OBS_KEY_MUHENKAN: return XK_Muhenkan;
|
||||
case OBS_KEY_HENKAN: return XK_Henkan;
|
||||
case OBS_KEY_ROMAJI: return XK_Romaji;
|
||||
case OBS_KEY_HIRAGANA: return XK_Hiragana;
|
||||
case OBS_KEY_KATAKANA: return XK_Katakana;
|
||||
case OBS_KEY_HIRAGANA_KATAKANA: return XK_Hiragana_Katakana;
|
||||
case OBS_KEY_ZENKAKU: return XK_Zenkaku;
|
||||
case OBS_KEY_HANKAKU: return XK_Hankaku;
|
||||
case OBS_KEY_ZENKAKU_HANKAKU: return XK_Zenkaku_Hankaku;
|
||||
case OBS_KEY_TOUROKU: return XK_Touroku;
|
||||
case OBS_KEY_MASSYO: return XK_Massyo;
|
||||
case OBS_KEY_KANA_LOCK: return XK_Kana_Lock;
|
||||
case OBS_KEY_KANA_SHIFT: return XK_Kana_Shift;
|
||||
case OBS_KEY_EISU_SHIFT: return XK_Eisu_Shift;
|
||||
case OBS_KEY_EISU_TOGGLE: return XK_Eisu_toggle;
|
||||
case OBS_KEY_HANGUL: return XK_Hangul;
|
||||
case OBS_KEY_HANGUL_START: return XK_Hangul_Start;
|
||||
case OBS_KEY_HANGUL_END: return XK_Hangul_End;
|
||||
case OBS_KEY_HANGUL_HANJA: return XK_Hangul_Hanja;
|
||||
case OBS_KEY_HANGUL_JAMO: return XK_Hangul_Jamo;
|
||||
case OBS_KEY_HANGUL_ROMAJA: return XK_Hangul_Romaja;
|
||||
case OBS_KEY_HANGUL_BANJA: return XK_Hangul_Banja;
|
||||
case OBS_KEY_HANGUL_PREHANJA: return XK_Hangul_PreHanja;
|
||||
case OBS_KEY_HANGUL_POSTHANJA: return XK_Hangul_PostHanja;
|
||||
case OBS_KEY_HANGUL_SPECIAL: return XK_Hangul_Special;
|
||||
case OBS_KEY_DEAD_GRAVE: return XK_dead_grave;
|
||||
case OBS_KEY_DEAD_ACUTE: return XK_dead_acute;
|
||||
case OBS_KEY_DEAD_CIRCUMFLEX: return XK_dead_circumflex;
|
||||
case OBS_KEY_DEAD_TILDE: return XK_dead_tilde;
|
||||
case OBS_KEY_DEAD_MACRON: return XK_dead_macron;
|
||||
case OBS_KEY_DEAD_BREVE: return XK_dead_breve;
|
||||
case OBS_KEY_DEAD_ABOVEDOT: return XK_dead_abovedot;
|
||||
case OBS_KEY_DEAD_DIAERESIS: return XK_dead_diaeresis;
|
||||
case OBS_KEY_DEAD_ABOVERING: return XK_dead_abovering;
|
||||
case OBS_KEY_DEAD_DOUBLEACUTE: return XK_dead_doubleacute;
|
||||
case OBS_KEY_DEAD_CARON: return XK_dead_caron;
|
||||
case OBS_KEY_DEAD_CEDILLA: return XK_dead_cedilla;
|
||||
case OBS_KEY_DEAD_OGONEK: return XK_dead_ogonek;
|
||||
case OBS_KEY_DEAD_IOTA: return XK_dead_iota;
|
||||
case OBS_KEY_DEAD_VOICED_SOUND: return XK_dead_voiced_sound;
|
||||
case OBS_KEY_DEAD_SEMIVOICED_SOUND: return XK_dead_semivoiced_sound;
|
||||
case OBS_KEY_DEAD_BELOWDOT: return XK_dead_belowdot;
|
||||
case OBS_KEY_DEAD_HOOK: return XK_dead_hook;
|
||||
case OBS_KEY_DEAD_HORN: return XK_dead_horn;
|
||||
|
||||
case OBS_KEY_MOUSE1: return MOUSE_1;
|
||||
case OBS_KEY_MOUSE2: return MOUSE_2;
|
||||
case OBS_KEY_MOUSE3: return MOUSE_3;
|
||||
case OBS_KEY_MOUSE4: return MOUSE_4;
|
||||
case OBS_KEY_MOUSE5: return MOUSE_5;
|
||||
|
||||
/* TODO: Implement keys for non-US keyboards */
|
||||
default:;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void fill_base_keysyms(struct obs_core_hotkeys *hotkeys)
|
||||
{
|
||||
for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++)
|
||||
hotkeys->platform_context->base_keysyms[i] = get_keysym(i);
|
||||
}
|
||||
|
||||
static obs_key_t key_from_base_keysym(obs_hotkeys_platform_t *context,
|
||||
xcb_keysym_t code)
|
||||
{
|
||||
for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
|
||||
if (context->base_keysyms[i] == (xcb_keysym_t)code) {
|
||||
return (obs_key_t)i;
|
||||
}
|
||||
}
|
||||
|
||||
return OBS_KEY_NONE;
|
||||
}
|
||||
|
||||
static inline void add_key(obs_hotkeys_platform_t *context, obs_key_t key,
|
||||
int code)
|
||||
{
|
||||
xcb_keycode_t kc = (xcb_keycode_t)code;
|
||||
da_push_back(context->keycodes[key].list, &kc);
|
||||
|
||||
if (context->keycodes[key].list.num > 1) {
|
||||
blog(LOG_DEBUG, "found alternate keycode %d for %s "
|
||||
"which already has keycode %d",
|
||||
code, obs_key_to_name(key),
|
||||
(int)context->keycodes[key].list.array[0]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool fill_keycodes(struct obs_core_hotkeys *hotkeys)
|
||||
{
|
||||
obs_hotkeys_platform_t *context = hotkeys->platform_context;
|
||||
xcb_connection_t *connection = XGetXCBConnection(context->display);
|
||||
const struct xcb_setup_t *setup = xcb_get_setup(connection);
|
||||
xcb_get_keyboard_mapping_cookie_t cookie;
|
||||
xcb_get_keyboard_mapping_reply_t *reply;
|
||||
xcb_generic_error_t *error = NULL;
|
||||
int code;
|
||||
|
||||
int mincode = setup->min_keycode;
|
||||
int maxcode = setup->max_keycode;
|
||||
|
||||
context->min_keycode = setup->min_keycode;
|
||||
|
||||
cookie = xcb_get_keyboard_mapping(connection,
|
||||
mincode, maxcode - mincode - 1);
|
||||
|
||||
reply = xcb_get_keyboard_mapping_reply(connection, cookie, &error);
|
||||
|
||||
if (error || !reply) {
|
||||
blog(LOG_WARNING, "xcb_get_keyboard_mapping_reply failed");
|
||||
goto error1;
|
||||
}
|
||||
|
||||
const xcb_keysym_t *keysyms = xcb_get_keyboard_mapping_keysyms(reply);
|
||||
int syms_per_code = (int)reply->keysyms_per_keycode;
|
||||
|
||||
context->num_keysyms = (maxcode - mincode) * syms_per_code;
|
||||
context->syms_per_code = syms_per_code;
|
||||
context->keysyms = bmemdup(keysyms,
|
||||
sizeof(xcb_keysym_t) * context->num_keysyms);
|
||||
|
||||
for (code = mincode; code <= maxcode; code++) {
|
||||
const xcb_keysym_t *sym;
|
||||
obs_key_t key;
|
||||
|
||||
sym = &keysyms[(code - mincode) * syms_per_code];
|
||||
|
||||
for (int i = 0; i < syms_per_code; i++) {
|
||||
if (!sym[i])
|
||||
break;
|
||||
|
||||
if (sym[i] == XK_Super_L) {
|
||||
context->super_l_code = code;
|
||||
break;
|
||||
} else if (sym[i] == XK_Super_R) {
|
||||
context->super_r_code = code;
|
||||
break;
|
||||
} else {
|
||||
key = key_from_base_keysym(context, sym[i]);
|
||||
|
||||
if (key != OBS_KEY_NONE) {
|
||||
add_key(context, key, code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
error1:
|
||||
free(reply);
|
||||
free(error);
|
||||
|
||||
return error != NULL || reply == NULL;
|
||||
}
|
||||
|
||||
bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
|
||||
{
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
if (!display)
|
||||
return false;
|
||||
|
||||
hotkeys->platform_context = bzalloc(sizeof(obs_hotkeys_platform_t));
|
||||
hotkeys->platform_context->display = display;
|
||||
|
||||
fill_base_keysyms(hotkeys);
|
||||
fill_keycodes(hotkeys);
|
||||
return true;
|
||||
}
|
||||
|
||||
void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
|
||||
{
|
||||
obs_hotkeys_platform_t *context = hotkeys->platform_context;
|
||||
|
||||
for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++)
|
||||
da_free(context->keycodes[i].list);
|
||||
|
||||
XCloseDisplay(context->display);
|
||||
bfree(context->keysyms);
|
||||
bfree(context);
|
||||
|
||||
hotkeys->platform_context = NULL;
|
||||
}
|
||||
|
||||
static xcb_screen_t *default_screen(obs_hotkeys_platform_t *context,
|
||||
xcb_connection_t *connection)
|
||||
{
|
||||
int def_screen_idx = XDefaultScreen(context->display);
|
||||
xcb_screen_iterator_t iter;
|
||||
|
||||
iter = xcb_setup_roots_iterator(xcb_get_setup(connection));
|
||||
while (iter.rem) {
|
||||
if (--def_screen_idx == 0) {
|
||||
return iter.data;
|
||||
break;
|
||||
}
|
||||
|
||||
xcb_screen_next(&iter);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline xcb_window_t root_window(obs_hotkeys_platform_t *context,
|
||||
xcb_connection_t *connection)
|
||||
{
|
||||
xcb_screen_t *screen = default_screen(context, connection);
|
||||
if (screen)
|
||||
return screen->root;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool mouse_button_pressed(xcb_connection_t *connection,
|
||||
obs_hotkeys_platform_t *context, obs_key_t key)
|
||||
{
|
||||
xcb_generic_error_t *error = NULL;
|
||||
xcb_query_pointer_cookie_t qpc;
|
||||
xcb_query_pointer_reply_t *reply;
|
||||
bool ret = false;
|
||||
|
||||
qpc = xcb_query_pointer(connection, root_window(context, connection));
|
||||
reply = xcb_query_pointer_reply(connection, qpc, &error);
|
||||
|
||||
if (error) {
|
||||
blog(LOG_WARNING, "xcb_query_pointer_reply failed");
|
||||
} else {
|
||||
uint16_t buttons = reply->mask;
|
||||
|
||||
switch (key) {
|
||||
case OBS_KEY_MOUSE1: ret = buttons & XCB_BUTTON_MASK_1; break;
|
||||
case OBS_KEY_MOUSE2: ret = buttons & XCB_BUTTON_MASK_3; break;
|
||||
case OBS_KEY_MOUSE3: ret = buttons & XCB_BUTTON_MASK_2; break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
free(reply);
|
||||
free(error);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool keycode_pressed(xcb_query_keymap_reply_t *reply,
|
||||
xcb_keycode_t code)
|
||||
{
|
||||
return (reply->keys[code / 8] & (1 << (code % 8))) != 0;
|
||||
}
|
||||
|
||||
static bool key_pressed(xcb_connection_t *connection,
|
||||
obs_hotkeys_platform_t *context, obs_key_t key)
|
||||
{
|
||||
struct keycode_list *codes = &context->keycodes[key];
|
||||
xcb_generic_error_t *error = NULL;
|
||||
xcb_query_keymap_reply_t *reply;
|
||||
bool pressed = false;
|
||||
|
||||
reply = xcb_query_keymap_reply(connection,
|
||||
xcb_query_keymap(connection), &error);
|
||||
if (error) {
|
||||
blog(LOG_WARNING, "xcb_query_keymap failed");
|
||||
|
||||
} else if (key == OBS_KEY_META) {
|
||||
pressed = keycode_pressed(reply, context->super_l_code) ||
|
||||
keycode_pressed(reply, context->super_r_code);
|
||||
|
||||
} else {
|
||||
for (size_t i = 0; i < codes->list.num; i++) {
|
||||
if (keycode_pressed(reply, codes->list.array[i])) {
|
||||
pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(reply);
|
||||
free(error);
|
||||
return pressed;
|
||||
}
|
||||
|
||||
bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *context,
|
||||
obs_key_t key)
|
||||
{
|
||||
xcb_connection_t *conn = XGetXCBConnection(context->display);
|
||||
|
||||
if (key >= OBS_KEY_MOUSE1 && key <= OBS_KEY_MOUSE29) {
|
||||
return mouse_button_pressed(conn, context, key);
|
||||
} else {
|
||||
return key_pressed(conn, context, key);
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_key_translation(struct dstr *dstr, xcb_keycode_t keycode)
|
||||
{
|
||||
xcb_connection_t *connection;
|
||||
char name[128];
|
||||
|
||||
connection = XGetXCBConnection(obs->hotkeys.platform_context->display);
|
||||
|
||||
XKeyEvent event = {0};
|
||||
event.type = KeyPress;
|
||||
event.display = obs->hotkeys.platform_context->display;
|
||||
event.keycode = keycode;
|
||||
event.root = root_window(obs->hotkeys.platform_context, connection);
|
||||
event.window = event.root;
|
||||
|
||||
if (keycode) {
|
||||
int len = XLookupString(&event, name, 128, NULL, NULL);
|
||||
if (len) {
|
||||
dstr_ncopy(dstr, name, len);
|
||||
dstr_to_upper(dstr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void obs_key_to_str(obs_key_t key, struct dstr *dstr)
|
||||
{
|
||||
if (key >= OBS_KEY_MOUSE1 && key <= OBS_KEY_MOUSE29) {
|
||||
if (obs->hotkeys.translations[key]) {
|
||||
dstr_copy(dstr, obs->hotkeys.translations[key]);
|
||||
} else {
|
||||
dstr_printf(dstr, "Mouse %d",
|
||||
(int)(key - OBS_KEY_MOUSE1 + 1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (key >= OBS_KEY_NUM0 && key <= OBS_KEY_NUM9) {
|
||||
if (obs->hotkeys.translations[key]) {
|
||||
dstr_copy(dstr, obs->hotkeys.translations[key]);
|
||||
} else {
|
||||
dstr_printf(dstr, "Numpad %d",
|
||||
(int)(key - OBS_KEY_NUM0));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#define translate_key(key, def) \
|
||||
dstr_copy(dstr, obs_get_hotkey_translation(key, def))
|
||||
|
||||
switch (key) {
|
||||
case OBS_KEY_INSERT: return translate_key(key, "Insert");
|
||||
case OBS_KEY_DELETE: return translate_key(key, "Delete");
|
||||
case OBS_KEY_HOME: return translate_key(key, "Home");
|
||||
case OBS_KEY_END: return translate_key(key, "End");
|
||||
case OBS_KEY_PAGEUP: return translate_key(key, "Page Up");
|
||||
case OBS_KEY_PAGEDOWN: return translate_key(key, "Page Down");
|
||||
case OBS_KEY_NUMLOCK: return translate_key(key, "Num Lock");
|
||||
case OBS_KEY_SCROLLLOCK: return translate_key(key, "Scroll Lock");
|
||||
case OBS_KEY_CAPSLOCK: return translate_key(key, "Caps Lock");
|
||||
case OBS_KEY_BACKSPACE: return translate_key(key, "Backspace");
|
||||
case OBS_KEY_TAB: return translate_key(key, "Tab");
|
||||
case OBS_KEY_PRINT: return translate_key(key, "Print");
|
||||
case OBS_KEY_PAUSE: return translate_key(key, "Pause");
|
||||
case OBS_KEY_LEFT: return translate_key(key, "Left");
|
||||
case OBS_KEY_RIGHT: return translate_key(key, "Right");
|
||||
case OBS_KEY_UP: return translate_key(key, "Up");
|
||||
case OBS_KEY_DOWN: return translate_key(key, "Down");
|
||||
case OBS_KEY_SHIFT: return translate_key(key, "Shift");
|
||||
case OBS_KEY_ALT: return translate_key(key, "Alt");
|
||||
case OBS_KEY_CONTROL: return translate_key(key, "Control");
|
||||
case OBS_KEY_META: return translate_key(key, "Super");
|
||||
case OBS_KEY_MENU: return translate_key(key, "Menu");
|
||||
case OBS_KEY_NUMASTERISK: return translate_key(key, "Numpad *");
|
||||
case OBS_KEY_NUMPLUS: return translate_key(key, "Numpad +");
|
||||
case OBS_KEY_NUMCOMMA: return translate_key(key, "Numpad ,");
|
||||
case OBS_KEY_NUMPERIOD: return translate_key(key, "Numpad .");
|
||||
case OBS_KEY_NUMSLASH: return translate_key(key, "Numpad /");
|
||||
default:;
|
||||
}
|
||||
|
||||
if (key >= OBS_KEY_F1 && key <= OBS_KEY_F35) {
|
||||
dstr_printf(dstr, "F%d",
|
||||
(int)(key - OBS_KEY_F1 + 1));
|
||||
return;
|
||||
}
|
||||
|
||||
obs_hotkeys_platform_t *context = obs->hotkeys.platform_context;
|
||||
struct keycode_list *keycodes = &context->keycodes[key];
|
||||
|
||||
for (size_t i = 0; i < keycodes->list.num; i++) {
|
||||
if (get_key_translation(dstr, keycodes->list.array[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (key != OBS_KEY_NONE && dstr_is_empty(dstr)) {
|
||||
dstr_copy(dstr, obs_key_to_name(key));
|
||||
}
|
||||
}
|
||||
|
||||
static obs_key_t key_from_keycode(obs_hotkeys_platform_t *context,
|
||||
xcb_keycode_t code)
|
||||
{
|
||||
for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
|
||||
struct keycode_list *codes = &context->keycodes[i];
|
||||
|
||||
for (size_t j = 0; j < codes->list.num; j++) {
|
||||
if (codes->list.array[j] == code) {
|
||||
return (obs_key_t)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OBS_KEY_NONE;
|
||||
}
|
||||
|
||||
obs_key_t obs_key_from_virtual_key(int sym)
|
||||
{
|
||||
obs_hotkeys_platform_t *context = obs->hotkeys.platform_context;
|
||||
const xcb_keysym_t *keysyms = context->keysyms;
|
||||
int syms_per_code = context->syms_per_code;
|
||||
int num_keysyms = context->num_keysyms;
|
||||
|
||||
if (sym == 0)
|
||||
return OBS_KEY_NONE;
|
||||
|
||||
for (int i = 0; i < num_keysyms; i++) {
|
||||
if (keysyms[i] == (xcb_keysym_t)sym) {
|
||||
xcb_keycode_t code = (xcb_keycode_t)(i / syms_per_code);
|
||||
code += context->min_keycode;
|
||||
obs_key_t key = key_from_keycode(context, code);
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return OBS_KEY_NONE;
|
||||
}
|
||||
|
||||
int obs_key_to_virtual_key(obs_key_t key)
|
||||
{
|
||||
if (key == OBS_KEY_META)
|
||||
return XK_Super_L;
|
||||
|
||||
return (int)obs->hotkeys.platform_context->base_keysyms[(int)key];
|
||||
}
|
||||
|
||||
static inline void add_combo_key(obs_key_t key, struct dstr *str)
|
||||
{
|
||||
struct dstr key_str = {0};
|
||||
|
||||
obs_key_to_str(key, &key_str);
|
||||
|
||||
if (!dstr_is_empty(&key_str)) {
|
||||
if (!dstr_is_empty(str)) {
|
||||
dstr_cat(str, " + ");
|
||||
}
|
||||
dstr_cat_dstr(str, &key_str);
|
||||
}
|
||||
|
||||
dstr_free(&key_str);
|
||||
}
|
||||
|
||||
void obs_key_combination_to_str(obs_key_combination_t combination,
|
||||
struct dstr *str)
|
||||
{
|
||||
if ((combination.modifiers & INTERACT_CONTROL_KEY) != 0) {
|
||||
add_combo_key(OBS_KEY_CONTROL, str);
|
||||
}
|
||||
if ((combination.modifiers & INTERACT_COMMAND_KEY) != 0) {
|
||||
add_combo_key(OBS_KEY_META, str);
|
||||
}
|
||||
if ((combination.modifiers & INTERACT_ALT_KEY) != 0) {
|
||||
add_combo_key(OBS_KEY_ALT, str);
|
||||
}
|
||||
if ((combination.modifiers & INTERACT_SHIFT_KEY) != 0) {
|
||||
add_combo_key(OBS_KEY_SHIFT, str);
|
||||
}
|
||||
if (combination.key != OBS_KEY_NONE) {
|
||||
add_combo_key(combination.key, str);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,9 +47,10 @@ static const char *output_signals[] = {
|
|||
};
|
||||
|
||||
static bool init_output_handlers(struct obs_output *output, const char *name,
|
||||
obs_data_t *settings)
|
||||
obs_data_t *settings, obs_data_t *hotkey_data)
|
||||
{
|
||||
if (!obs_context_data_init(&output->context, settings, name))
|
||||
if (!obs_context_data_init(&output->context, settings, name,
|
||||
hotkey_data))
|
||||
return false;
|
||||
|
||||
signal_handler_add_array(output->context.signals, output_signals);
|
||||
|
@ -57,7 +58,7 @@ static bool init_output_handlers(struct obs_output *output, const char *name,
|
|||
}
|
||||
|
||||
obs_output_t *obs_output_create(const char *id, const char *name,
|
||||
obs_data_t *settings)
|
||||
obs_data_t *settings, obs_data_t *hotkey_data)
|
||||
{
|
||||
const struct obs_output_info *info = find_output(id);
|
||||
struct obs_output *output;
|
||||
|
@ -73,7 +74,7 @@ obs_output_t *obs_output_create(const char *id, const char *name,
|
|||
|
||||
if (pthread_mutex_init(&output->interleaved_mutex, NULL) != 0)
|
||||
goto fail;
|
||||
if (!init_output_handlers(output, name, settings))
|
||||
if (!init_output_handlers(output, name, settings, hotkey_data))
|
||||
goto fail;
|
||||
|
||||
output->info = *info;
|
||||
|
|
|
@ -473,7 +473,8 @@ const struct obs_source_info scene_info =
|
|||
obs_scene_t *obs_scene_create(const char *name)
|
||||
{
|
||||
struct obs_source *source =
|
||||
obs_source_create(OBS_SOURCE_TYPE_INPUT, "scene", name, NULL);
|
||||
obs_source_create(OBS_SOURCE_TYPE_INPUT, "scene", name, NULL,
|
||||
NULL);
|
||||
return source->context.data;
|
||||
}
|
||||
|
||||
|
@ -554,6 +555,82 @@ void obs_scene_enum_items(obs_scene_t *scene,
|
|||
pthread_mutex_unlock(&scene->mutex);
|
||||
}
|
||||
|
||||
static obs_sceneitem_t *sceneitem_get_ref(obs_sceneitem_t *si)
|
||||
{
|
||||
long owners = si->ref;
|
||||
while (owners > 0) {
|
||||
if (os_atomic_compare_swap_long(&si->ref, owners, owners + 1))
|
||||
return si;
|
||||
|
||||
owners = si->ref;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool hotkey_show_sceneitem(void *data, obs_hotkey_pair_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
obs_sceneitem_t *si = sceneitem_get_ref(data);
|
||||
if (pressed && si && !si->visible) {
|
||||
obs_sceneitem_set_visible(si, true);
|
||||
obs_sceneitem_release(si);
|
||||
return true;
|
||||
}
|
||||
|
||||
obs_sceneitem_release(si);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hotkey_hide_sceneitem(void *data, obs_hotkey_pair_id id,
|
||||
obs_hotkey_t *hotkey, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(hotkey);
|
||||
|
||||
obs_sceneitem_t *si = sceneitem_get_ref(data);
|
||||
if (pressed && si && si->visible) {
|
||||
obs_sceneitem_set_visible(si, false);
|
||||
obs_sceneitem_release(si);
|
||||
return true;
|
||||
}
|
||||
|
||||
obs_sceneitem_release(si);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void init_hotkeys(obs_scene_t *scene, obs_sceneitem_t *item,
|
||||
const char *name)
|
||||
{
|
||||
struct dstr show = {0};
|
||||
struct dstr hide = {0};
|
||||
struct dstr show_desc = {0};
|
||||
struct dstr hide_desc = {0};
|
||||
|
||||
dstr_copy(&show, "libobs.show_scene_item.%1");
|
||||
dstr_replace(&show, "%1", name);
|
||||
dstr_copy(&hide, "libobs.hide_scene_item.%1");
|
||||
dstr_replace(&hide, "%1", name);
|
||||
|
||||
dstr_copy(&show_desc, obs->hotkeys.sceneitem_show);
|
||||
dstr_replace(&show_desc, "%1", name);
|
||||
dstr_copy(&hide_desc, obs->hotkeys.sceneitem_hide);
|
||||
dstr_replace(&hide_desc, "%1", name);
|
||||
|
||||
item->toggle_visibility = obs_hotkey_pair_register_source(scene->source,
|
||||
show.array, show_desc.array,
|
||||
hide.array, hide_desc.array,
|
||||
hotkey_show_sceneitem, hotkey_hide_sceneitem,
|
||||
item, item);
|
||||
|
||||
dstr_free(&show);
|
||||
dstr_free(&hide);
|
||||
dstr_free(&show_desc);
|
||||
dstr_free(&hide_desc);
|
||||
}
|
||||
|
||||
obs_sceneitem_t *obs_scene_add(obs_scene_t *scene, obs_source_t *source)
|
||||
{
|
||||
struct obs_scene_item *last;
|
||||
|
@ -601,6 +678,8 @@ obs_sceneitem_t *obs_scene_add(obs_scene_t *scene, obs_source_t *source)
|
|||
|
||||
pthread_mutex_unlock(&scene->mutex);
|
||||
|
||||
init_hotkeys(scene, item, obs_source_get_name(source));
|
||||
|
||||
calldata_set_ptr(¶ms, "scene", scene);
|
||||
calldata_set_ptr(¶ms, "item", item);
|
||||
signal_handler_signal(scene->source->context.signals, "item_add",
|
||||
|
@ -613,6 +692,7 @@ obs_sceneitem_t *obs_scene_add(obs_scene_t *scene, obs_source_t *source)
|
|||
static void obs_sceneitem_destroy(obs_sceneitem_t *item)
|
||||
{
|
||||
if (item) {
|
||||
obs_hotkey_pair_unregister(item->toggle_visibility);
|
||||
if (item->source)
|
||||
obs_source_release(item->source);
|
||||
bfree(item);
|
||||
|
|
|
@ -49,6 +49,8 @@ struct obs_scene_item {
|
|||
uint32_t bounds_align;
|
||||
struct vec2 bounds;
|
||||
|
||||
obs_hotkey_pair_id toggle_visibility;
|
||||
|
||||
/* would do **prev_next, but not really great for reordering */
|
||||
struct obs_scene_item *prev;
|
||||
struct obs_scene_item *next;
|
||||
|
|
|
@ -34,7 +34,7 @@ const char *obs_service_get_display_name(const char *id)
|
|||
}
|
||||
|
||||
obs_service_t *obs_service_create(const char *id, const char *name,
|
||||
obs_data_t *settings)
|
||||
obs_data_t *settings, obs_data_t *hotkey_data)
|
||||
{
|
||||
const struct obs_service_info *info = find_service(id);
|
||||
struct obs_service *service;
|
||||
|
@ -46,7 +46,8 @@ obs_service_t *obs_service_create(const char *id, const char *name,
|
|||
|
||||
service = bzalloc(sizeof(struct obs_service));
|
||||
|
||||
if (!obs_context_data_init(&service->context, settings, name)) {
|
||||
if (!obs_context_data_init(&service->context, settings, name,
|
||||
hotkey_data)) {
|
||||
bfree(service);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -79,6 +79,10 @@ static const char *source_signals[] = {
|
|||
"void show(ptr source)",
|
||||
"void hide(ptr source)",
|
||||
"void mute(ptr source, bool muted)",
|
||||
"void push_to_mute_changed(ptr source, bool enabled)",
|
||||
"void push_to_mute_delay(ptr source, int delay)",
|
||||
"void push_to_talk_changed(ptr source, bool enabled)",
|
||||
"void push_to_talk_delay(ptr source, int delay)",
|
||||
"void enable(ptr source, bool enabled)",
|
||||
"void rename(ptr source, string new_name, string prev_name)",
|
||||
"void volume(ptr source, in out float volume)",
|
||||
|
@ -94,9 +98,10 @@ static const char *source_signals[] = {
|
|||
};
|
||||
|
||||
bool obs_source_init_context(struct obs_source *source,
|
||||
obs_data_t *settings, const char *name)
|
||||
obs_data_t *settings, const char *name, obs_data_t *hotkey_data)
|
||||
{
|
||||
if (!obs_context_data_init(&source->context, settings, name))
|
||||
if (!obs_context_data_init(&source->context, settings, name,
|
||||
hotkey_data))
|
||||
return false;
|
||||
|
||||
return signal_handler_add_array(source->context.signals,
|
||||
|
@ -154,6 +159,83 @@ bool obs_source_init(struct obs_source *source,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool obs_source_hotkey_mute(void *data,
|
||||
obs_hotkey_pair_id id, obs_hotkey_t *key, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(key);
|
||||
|
||||
struct obs_source *source = data;
|
||||
|
||||
if (!pressed || obs_source_muted(source)) return false;
|
||||
|
||||
obs_source_set_muted(source, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool obs_source_hotkey_unmute(void *data,
|
||||
obs_hotkey_pair_id id, obs_hotkey_t *key, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(key);
|
||||
|
||||
struct obs_source *source = data;
|
||||
|
||||
if (!pressed || !obs_source_muted(source)) return false;
|
||||
|
||||
obs_source_set_muted(source, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void obs_source_hotkey_push_to_mute(void *data,
|
||||
obs_hotkey_id id, obs_hotkey_t *key, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(key);
|
||||
|
||||
struct obs_source *source = data;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
source->push_to_mute_pressed = pressed;
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
}
|
||||
|
||||
static void obs_source_hotkey_push_to_talk(void *data,
|
||||
obs_hotkey_id id, obs_hotkey_t *key, bool pressed)
|
||||
{
|
||||
UNUSED_PARAMETER(id);
|
||||
UNUSED_PARAMETER(key);
|
||||
|
||||
struct obs_source *source = data;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
source->push_to_talk_pressed = pressed;
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
}
|
||||
|
||||
static void obs_source_init_audio_hotkeys(struct obs_source *source)
|
||||
{
|
||||
if (!(source->info.output_flags & OBS_SOURCE_AUDIO)) {
|
||||
source->mute_unmute_key = OBS_INVALID_HOTKEY_ID;
|
||||
source->push_to_talk_key = OBS_INVALID_HOTKEY_ID;
|
||||
return;
|
||||
}
|
||||
|
||||
source->mute_unmute_key = obs_hotkey_pair_register_source(source,
|
||||
"libobs.mute", obs->hotkeys.mute,
|
||||
"libobs.unmute", obs->hotkeys.unmute,
|
||||
obs_source_hotkey_mute, obs_source_hotkey_unmute,
|
||||
source, source);
|
||||
|
||||
source->push_to_mute_key = obs_hotkey_register_source(source,
|
||||
"libobs.push-to-mute", obs->hotkeys.push_to_mute,
|
||||
obs_source_hotkey_push_to_mute, source);
|
||||
|
||||
source->push_to_talk_key = obs_hotkey_register_source(source,
|
||||
"libobs.push-to-talk", obs->hotkeys.push_to_talk,
|
||||
obs_source_hotkey_push_to_talk, source);
|
||||
}
|
||||
|
||||
static inline void obs_source_dosignal(struct obs_source *source,
|
||||
const char *signal_obs, const char *signal_source)
|
||||
{
|
||||
|
@ -170,7 +252,7 @@ static inline void obs_source_dosignal(struct obs_source *source,
|
|||
}
|
||||
|
||||
obs_source_t *obs_source_create(enum obs_source_type type, const char *id,
|
||||
const char *name, obs_data_t *settings)
|
||||
const char *name, obs_data_t *settings, obs_data_t *hotkey_data)
|
||||
{
|
||||
struct obs_source *source = bzalloc(sizeof(struct obs_source));
|
||||
|
||||
|
@ -185,7 +267,11 @@ obs_source_t *obs_source_create(enum obs_source_type type, const char *id,
|
|||
source->info = *info;
|
||||
}
|
||||
|
||||
if (!obs_source_init_context(source, settings, name))
|
||||
source->mute_unmute_key = OBS_INVALID_HOTKEY_PAIR_ID;
|
||||
source->push_to_mute_key = OBS_INVALID_HOTKEY_ID;
|
||||
source->push_to_talk_key = OBS_INVALID_HOTKEY_ID;
|
||||
|
||||
if (!obs_source_init_context(source, settings, name, hotkey_data))
|
||||
goto fail;
|
||||
|
||||
if (info && info->get_defaults)
|
||||
|
@ -194,6 +280,8 @@ obs_source_t *obs_source_create(enum obs_source_type type, const char *id,
|
|||
if (!obs_source_init(source, info))
|
||||
goto fail;
|
||||
|
||||
obs_source_init_audio_hotkeys(source);
|
||||
|
||||
/* allow the source to be created even if creation fails so that the
|
||||
* user's data doesn't become lost */
|
||||
if (info)
|
||||
|
@ -273,6 +361,10 @@ void obs_source_destroy(struct obs_source *source)
|
|||
source->context.data = NULL;
|
||||
}
|
||||
|
||||
obs_hotkey_unregister(source->push_to_talk_key);
|
||||
obs_hotkey_unregister(source->push_to_mute_key);
|
||||
obs_hotkey_pair_unregister(source->mute_unmute_key);
|
||||
|
||||
for (i = 0; i < source->async_cache.num; i++)
|
||||
obs_source_frame_decref(source->async_cache.array[i].frame);
|
||||
|
||||
|
@ -828,7 +920,22 @@ static void source_output_audio_line(obs_source_t *source,
|
|||
source->present_volume * obs->audio.user_volume *
|
||||
obs->audio.present_volume;
|
||||
|
||||
bool muted = !source->enabled || source->muted;
|
||||
if (source->push_to_mute_enabled && source->push_to_mute_pressed)
|
||||
source->push_to_mute_stop_time = os_time +
|
||||
source->push_to_mute_delay * 1000000;
|
||||
|
||||
if (source->push_to_talk_enabled && source->push_to_talk_pressed)
|
||||
source->push_to_talk_stop_time = os_time +
|
||||
source->push_to_talk_delay * 1000000;
|
||||
|
||||
bool push_to_mute_active = source->push_to_mute_pressed ||
|
||||
os_time < source->push_to_mute_stop_time;
|
||||
bool push_to_talk_active = source->push_to_talk_pressed ||
|
||||
os_time < source->push_to_talk_stop_time;
|
||||
|
||||
bool muted = !source->enabled || source->muted ||
|
||||
(source->push_to_mute_enabled && push_to_mute_active) ||
|
||||
(source->push_to_talk_enabled && !push_to_talk_active);
|
||||
|
||||
if (muted)
|
||||
in.volume = 0.0f;
|
||||
|
@ -2819,3 +2926,135 @@ void obs_source_set_muted(obs_source_t *source, bool muted)
|
|||
|
||||
calldata_free(&data);
|
||||
}
|
||||
|
||||
static void source_signal_push_to_changed(obs_source_t *source,
|
||||
const char *signal, bool enabled)
|
||||
{
|
||||
struct calldata data = {0};
|
||||
|
||||
calldata_set_ptr (&data, "source", source);
|
||||
calldata_set_bool(&data, "enabled", enabled);
|
||||
|
||||
signal_handler_signal(source->context.signals, signal, &data);
|
||||
calldata_free(&data);
|
||||
}
|
||||
|
||||
static void source_signal_push_to_delay(obs_source_t *source,
|
||||
const char *signal, uint64_t delay)
|
||||
{
|
||||
struct calldata data = {0};
|
||||
|
||||
calldata_set_ptr (&data, "source", source);
|
||||
calldata_set_bool(&data, "delay", delay);
|
||||
|
||||
signal_handler_signal(source->context.signals, signal, &data);
|
||||
calldata_free(&data);
|
||||
}
|
||||
|
||||
bool obs_source_push_to_mute_enabled(obs_source_t *source)
|
||||
{
|
||||
bool enabled;
|
||||
if (!source) return false;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
enabled = source->push_to_mute_enabled;
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void obs_source_enable_push_to_mute(obs_source_t *source, bool enabled)
|
||||
{
|
||||
if (!source) return;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
bool changed = source->push_to_mute_enabled != enabled;
|
||||
if (obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO && changed)
|
||||
blog(LOG_INFO, "source '%s' %s push-to-mute",
|
||||
obs_source_get_name(source),
|
||||
enabled ? "enabled" : "disabled");
|
||||
|
||||
source->push_to_mute_enabled = enabled;
|
||||
|
||||
if (changed)
|
||||
source_signal_push_to_changed(source, "push_to_mute_changed",
|
||||
enabled);
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
}
|
||||
|
||||
uint64_t obs_source_get_push_to_mute_delay(obs_source_t *source)
|
||||
{
|
||||
uint64_t delay;
|
||||
if (!source) return 0;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
delay = source->push_to_mute_delay;
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
void obs_source_set_push_to_mute_delay(obs_source_t *source, uint64_t delay)
|
||||
{
|
||||
if (!source) return;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
source->push_to_mute_delay = delay;
|
||||
|
||||
source_signal_push_to_delay(source, "push_to_mute_delay", delay);
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
}
|
||||
|
||||
bool obs_source_push_to_talk_enabled(obs_source_t *source)
|
||||
{
|
||||
bool enabled;
|
||||
if (!source) return false;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
enabled = source->push_to_talk_enabled;
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void obs_source_enable_push_to_talk(obs_source_t *source, bool enabled)
|
||||
{
|
||||
if (!source) return;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
bool changed = source->push_to_talk_enabled != enabled;
|
||||
if (obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO && changed)
|
||||
blog(LOG_INFO, "source '%s' %s push-to-talk",
|
||||
obs_source_get_name(source),
|
||||
enabled ? "enabled" : "disabled");
|
||||
|
||||
source->push_to_talk_enabled = enabled;
|
||||
|
||||
if (changed)
|
||||
source_signal_push_to_changed(source, "push_to_talk_changed",
|
||||
enabled);
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
}
|
||||
|
||||
uint64_t obs_source_get_push_to_talk_delay(obs_source_t *source)
|
||||
{
|
||||
uint64_t delay;
|
||||
if (!source) return 0;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
delay = source->push_to_talk_delay;
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
void obs_source_set_push_to_talk_delay(obs_source_t *source, uint64_t delay)
|
||||
{
|
||||
if (!source) return;
|
||||
|
||||
pthread_mutex_lock(&source->audio_mutex);
|
||||
source->push_to_talk_delay = delay;
|
||||
|
||||
source_signal_push_to_delay(source, "push_to_talk_delay", delay);
|
||||
pthread_mutex_unlock(&source->audio_mutex);
|
||||
}
|
||||
|
|
|
@ -194,3 +194,289 @@ void log_system_info(void)
|
|||
log_available_memory();
|
||||
log_windows_version();
|
||||
}
|
||||
|
||||
|
||||
struct obs_hotkeys_platform {
|
||||
int vk_codes[OBS_KEY_LAST_VALUE];
|
||||
};
|
||||
|
||||
static int get_virtual_key(obs_key_t key)
|
||||
{
|
||||
switch (key) {
|
||||
case OBS_KEY_RETURN: return VK_RETURN;
|
||||
case OBS_KEY_ESCAPE: return VK_ESCAPE;
|
||||
case OBS_KEY_TAB: return VK_TAB;
|
||||
case OBS_KEY_BACKTAB: return VK_OEM_BACKTAB;
|
||||
case OBS_KEY_BACKSPACE: return VK_BACK;
|
||||
case OBS_KEY_INSERT: return VK_INSERT;
|
||||
case OBS_KEY_DELETE: return VK_DELETE;
|
||||
case OBS_KEY_PAUSE: return VK_PAUSE;
|
||||
case OBS_KEY_PRINT: return VK_SNAPSHOT;
|
||||
case OBS_KEY_CLEAR: return VK_CLEAR;
|
||||
case OBS_KEY_HOME: return VK_HOME;
|
||||
case OBS_KEY_END: return VK_END;
|
||||
case OBS_KEY_LEFT: return VK_LEFT;
|
||||
case OBS_KEY_UP: return VK_UP;
|
||||
case OBS_KEY_RIGHT: return VK_RIGHT;
|
||||
case OBS_KEY_DOWN: return VK_DOWN;
|
||||
case OBS_KEY_PAGEUP: return VK_PRIOR;
|
||||
case OBS_KEY_PAGEDOWN: return VK_NEXT;
|
||||
|
||||
case OBS_KEY_SHIFT: return VK_SHIFT;
|
||||
case OBS_KEY_CONTROL: return VK_CONTROL;
|
||||
case OBS_KEY_ALT: return VK_MENU;
|
||||
case OBS_KEY_CAPSLOCK: return VK_CAPITAL;
|
||||
case OBS_KEY_NUMLOCK: return VK_NUMLOCK;
|
||||
case OBS_KEY_SCROLLLOCK: return VK_SCROLL;
|
||||
|
||||
case OBS_KEY_F1: return VK_F1;
|
||||
case OBS_KEY_F2: return VK_F2;
|
||||
case OBS_KEY_F3: return VK_F3;
|
||||
case OBS_KEY_F4: return VK_F4;
|
||||
case OBS_KEY_F5: return VK_F5;
|
||||
case OBS_KEY_F6: return VK_F6;
|
||||
case OBS_KEY_F7: return VK_F7;
|
||||
case OBS_KEY_F8: return VK_F8;
|
||||
case OBS_KEY_F9: return VK_F9;
|
||||
case OBS_KEY_F10: return VK_F10;
|
||||
case OBS_KEY_F11: return VK_F11;
|
||||
case OBS_KEY_F12: return VK_F12;
|
||||
case OBS_KEY_F13: return VK_F13;
|
||||
case OBS_KEY_F14: return VK_F14;
|
||||
case OBS_KEY_F15: return VK_F15;
|
||||
case OBS_KEY_F16: return VK_F16;
|
||||
case OBS_KEY_F17: return VK_F17;
|
||||
case OBS_KEY_F18: return VK_F18;
|
||||
case OBS_KEY_F19: return VK_F19;
|
||||
case OBS_KEY_F20: return VK_F20;
|
||||
case OBS_KEY_F21: return VK_F21;
|
||||
case OBS_KEY_F22: return VK_F22;
|
||||
case OBS_KEY_F23: return VK_F23;
|
||||
case OBS_KEY_F24: return VK_F24;
|
||||
|
||||
case OBS_KEY_SPACE: return VK_SPACE;
|
||||
|
||||
case OBS_KEY_APOSTROPHE: return VK_OEM_7;
|
||||
case OBS_KEY_PLUS: return VK_OEM_PLUS;
|
||||
case OBS_KEY_COMMA: return VK_OEM_COMMA;
|
||||
case OBS_KEY_MINUS: return VK_OEM_MINUS;
|
||||
case OBS_KEY_PERIOD: return VK_OEM_PERIOD;
|
||||
case OBS_KEY_SLASH: return VK_OEM_2;
|
||||
case OBS_KEY_0: return '0';
|
||||
case OBS_KEY_1: return '1';
|
||||
case OBS_KEY_2: return '2';
|
||||
case OBS_KEY_3: return '3';
|
||||
case OBS_KEY_4: return '4';
|
||||
case OBS_KEY_5: return '5';
|
||||
case OBS_KEY_6: return '6';
|
||||
case OBS_KEY_7: return '7';
|
||||
case OBS_KEY_8: return '8';
|
||||
case OBS_KEY_9: return '9';
|
||||
case OBS_KEY_NUMASTERISK: return VK_MULTIPLY;
|
||||
case OBS_KEY_NUMPLUS: return VK_ADD;
|
||||
case OBS_KEY_NUMMINUS: return VK_SUBTRACT;
|
||||
case OBS_KEY_NUMPERIOD: return VK_DECIMAL;
|
||||
case OBS_KEY_NUMSLASH: return VK_DIVIDE;
|
||||
case OBS_KEY_NUM0: return VK_NUMPAD0;
|
||||
case OBS_KEY_NUM1: return VK_NUMPAD1;
|
||||
case OBS_KEY_NUM2: return VK_NUMPAD2;
|
||||
case OBS_KEY_NUM3: return VK_NUMPAD3;
|
||||
case OBS_KEY_NUM4: return VK_NUMPAD4;
|
||||
case OBS_KEY_NUM5: return VK_NUMPAD5;
|
||||
case OBS_KEY_NUM6: return VK_NUMPAD6;
|
||||
case OBS_KEY_NUM7: return VK_NUMPAD7;
|
||||
case OBS_KEY_NUM8: return VK_NUMPAD8;
|
||||
case OBS_KEY_NUM9: return VK_NUMPAD9;
|
||||
case OBS_KEY_SEMICOLON: return VK_OEM_1;
|
||||
case OBS_KEY_A: return 'A';
|
||||
case OBS_KEY_B: return 'B';
|
||||
case OBS_KEY_C: return 'C';
|
||||
case OBS_KEY_D: return 'D';
|
||||
case OBS_KEY_E: return 'E';
|
||||
case OBS_KEY_F: return 'F';
|
||||
case OBS_KEY_G: return 'G';
|
||||
case OBS_KEY_H: return 'H';
|
||||
case OBS_KEY_I: return 'I';
|
||||
case OBS_KEY_J: return 'J';
|
||||
case OBS_KEY_K: return 'K';
|
||||
case OBS_KEY_L: return 'L';
|
||||
case OBS_KEY_M: return 'M';
|
||||
case OBS_KEY_N: return 'N';
|
||||
case OBS_KEY_O: return 'O';
|
||||
case OBS_KEY_P: return 'P';
|
||||
case OBS_KEY_Q: return 'Q';
|
||||
case OBS_KEY_R: return 'R';
|
||||
case OBS_KEY_S: return 'S';
|
||||
case OBS_KEY_T: return 'T';
|
||||
case OBS_KEY_U: return 'U';
|
||||
case OBS_KEY_V: return 'V';
|
||||
case OBS_KEY_W: return 'W';
|
||||
case OBS_KEY_X: return 'X';
|
||||
case OBS_KEY_Y: return 'Y';
|
||||
case OBS_KEY_Z: return 'Z';
|
||||
case OBS_KEY_BRACKETLEFT: return VK_OEM_4;
|
||||
case OBS_KEY_BACKSLASH: return VK_OEM_5;
|
||||
case OBS_KEY_BRACKETRIGHT: return VK_OEM_6;
|
||||
case OBS_KEY_ASCIITILDE: return VK_OEM_3;
|
||||
|
||||
case OBS_KEY_KANJI: return VK_KANJI;
|
||||
case OBS_KEY_TOUROKU: return VK_OEM_FJ_TOUROKU;
|
||||
case OBS_KEY_MASSYO: return VK_OEM_FJ_MASSHOU;
|
||||
|
||||
case OBS_KEY_HANGUL: return VK_HANGUL;
|
||||
|
||||
case OBS_KEY_MOUSE1: return VK_LBUTTON;
|
||||
case OBS_KEY_MOUSE2: return VK_RBUTTON;
|
||||
case OBS_KEY_MOUSE3: return VK_MBUTTON;
|
||||
case OBS_KEY_MOUSE4: return VK_XBUTTON1;
|
||||
case OBS_KEY_MOUSE5: return VK_XBUTTON2;
|
||||
|
||||
/* TODO: Implement keys for non-US keyboards */
|
||||
default:;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool obs_hotkeys_platform_init(struct obs_core_hotkeys *hotkeys)
|
||||
{
|
||||
hotkeys->platform_context = bzalloc(sizeof(obs_hotkeys_platform_t));
|
||||
|
||||
for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++)
|
||||
hotkeys->platform_context->vk_codes[i] = get_virtual_key(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void obs_hotkeys_platform_free(struct obs_core_hotkeys *hotkeys)
|
||||
{
|
||||
bfree(hotkeys->platform_context);
|
||||
hotkeys->platform_context = NULL;
|
||||
}
|
||||
|
||||
static bool vk_down(DWORD vk)
|
||||
{
|
||||
short state = GetAsyncKeyState(vk);
|
||||
bool down = (state & 0x8000) != 0;
|
||||
bool was_down = (state & 0x1) != 0;
|
||||
return down || was_down;
|
||||
}
|
||||
|
||||
bool obs_hotkeys_platform_is_pressed(obs_hotkeys_platform_t *context,
|
||||
obs_key_t key)
|
||||
{
|
||||
if (key == OBS_KEY_META) {
|
||||
return vk_down(VK_LWIN) || vk_down(VK_RWIN);
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(context);
|
||||
return vk_down(obs_key_to_virtual_key(key));
|
||||
}
|
||||
|
||||
void obs_key_to_str(obs_key_t key, struct dstr *str)
|
||||
{
|
||||
wchar_t name[128] = L"";
|
||||
UINT scan_code;
|
||||
int vk;
|
||||
|
||||
if (key == OBS_KEY_NONE) {
|
||||
return;
|
||||
|
||||
} else if (key >= OBS_KEY_MOUSE1 && key <= OBS_KEY_MOUSE29) {
|
||||
if (obs->hotkeys.translations[key]) {
|
||||
dstr_copy(str, obs->hotkeys.translations[key]);
|
||||
} else {
|
||||
dstr_printf(str, "Mouse %d",
|
||||
(int)(key - OBS_KEY_MOUSE1 + 1));
|
||||
}
|
||||
return;
|
||||
|
||||
} if (key == OBS_KEY_PAUSE) {
|
||||
dstr_copy(str, obs_get_hotkey_translation(key, "Pause"));
|
||||
return;
|
||||
|
||||
} else if (key == OBS_KEY_META) {
|
||||
dstr_copy(str, obs_get_hotkey_translation(key, "Windows"));
|
||||
return;
|
||||
}
|
||||
|
||||
vk = obs_key_to_virtual_key(key);
|
||||
scan_code = MapVirtualKey(vk, 0) << 16;
|
||||
|
||||
switch (vk) {
|
||||
case VK_HOME:
|
||||
case VK_END:
|
||||
case VK_LEFT:
|
||||
case VK_UP:
|
||||
case VK_RIGHT:
|
||||
case VK_DOWN:
|
||||
case VK_PRIOR:
|
||||
case VK_NEXT:
|
||||
case VK_INSERT:
|
||||
case VK_DELETE:
|
||||
case VK_NUMLOCK:
|
||||
scan_code |= 0x01000000;
|
||||
}
|
||||
|
||||
if (scan_code != 0 && GetKeyNameTextW(scan_code, name, 128) != 0) {
|
||||
dstr_from_wcs(str, name);
|
||||
} else if (key != OBS_KEY_NONE) {
|
||||
dstr_copy(str, obs_key_to_name(key));
|
||||
}
|
||||
}
|
||||
|
||||
obs_key_t obs_key_from_virtual_key(int code)
|
||||
{
|
||||
obs_hotkeys_platform_t *platform = obs->hotkeys.platform_context;
|
||||
|
||||
for (size_t i = 0; i < OBS_KEY_LAST_VALUE; i++) {
|
||||
if (platform->vk_codes[i] == code) {
|
||||
return (obs_key_t)i;
|
||||
}
|
||||
}
|
||||
|
||||
return OBS_KEY_NONE;
|
||||
}
|
||||
|
||||
int obs_key_to_virtual_key(obs_key_t key)
|
||||
{
|
||||
if (key == OBS_KEY_META)
|
||||
return VK_LWIN;
|
||||
|
||||
return obs->hotkeys.platform_context->vk_codes[(int)key];
|
||||
}
|
||||
|
||||
static inline void add_combo_key(obs_key_t key, struct dstr *str)
|
||||
{
|
||||
struct dstr key_str = {0};
|
||||
|
||||
obs_key_to_str(key, &key_str);
|
||||
|
||||
if (!dstr_is_empty(&key_str)) {
|
||||
if (!dstr_is_empty(str)) {
|
||||
dstr_cat(str, " + ");
|
||||
}
|
||||
dstr_cat_dstr(str, &key_str);
|
||||
}
|
||||
|
||||
dstr_free(&key_str);
|
||||
}
|
||||
|
||||
void obs_key_combination_to_str(obs_key_combination_t combination,
|
||||
struct dstr *str)
|
||||
{
|
||||
if ((combination.modifiers & INTERACT_CONTROL_KEY) != 0) {
|
||||
add_combo_key(OBS_KEY_CONTROL, str);
|
||||
}
|
||||
if ((combination.modifiers & INTERACT_COMMAND_KEY) != 0) {
|
||||
add_combo_key(OBS_KEY_META, str);
|
||||
}
|
||||
if ((combination.modifiers & INTERACT_ALT_KEY) != 0) {
|
||||
add_combo_key(OBS_KEY_ALT, str);
|
||||
}
|
||||
if ((combination.modifiers & INTERACT_SHIFT_KEY) != 0) {
|
||||
add_combo_key(OBS_KEY_SHIFT, str);
|
||||
}
|
||||
if (combination.key != OBS_KEY_NONE) {
|
||||
add_combo_key(combination.key, str);
|
||||
}
|
||||
}
|
||||
|
|
126
libobs/obs.c
126
libobs/obs.c
|
@ -609,6 +609,11 @@ static const char *obs_signals[] = {
|
|||
"void channel_change(int channel, in out ptr source, ptr prev_source)",
|
||||
"void master_volume(in out float volume)",
|
||||
|
||||
"void hotkey_layout_change()",
|
||||
"void hotkey_register(ptr hotkey)",
|
||||
"void hotkey_unregister(ptr hotkey)",
|
||||
"void hotkey_bindings_changed(ptr hotkey)",
|
||||
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -625,6 +630,82 @@ static inline bool obs_init_handlers(void)
|
|||
return signal_handler_add_array(obs->signals, obs_signals);
|
||||
}
|
||||
|
||||
static pthread_once_t obs_pthread_once_init_token = PTHREAD_ONCE_INIT;
|
||||
static inline bool obs_init_hotkeys(void)
|
||||
{
|
||||
struct obs_core_hotkeys *hotkeys = &obs->hotkeys;
|
||||
pthread_mutexattr_t attr;
|
||||
bool success = false;
|
||||
|
||||
assert(hotkeys != NULL);
|
||||
|
||||
da_init(hotkeys->hotkeys);
|
||||
hotkeys->signals = obs->signals;
|
||||
hotkeys->name_map_init_token = obs_pthread_once_init_token;
|
||||
hotkeys->mute = bstrdup("Mute");
|
||||
hotkeys->unmute = bstrdup("Unmute");
|
||||
hotkeys->push_to_mute = bstrdup("Push-to-mute");
|
||||
hotkeys->push_to_talk = bstrdup("Push-to-talk");
|
||||
hotkeys->sceneitem_show = bstrdup("Show '%1'");
|
||||
hotkeys->sceneitem_hide = bstrdup("Hide '%1'");
|
||||
|
||||
if (!obs_hotkeys_platform_init(hotkeys))
|
||||
return false;
|
||||
|
||||
if (pthread_mutexattr_init(&attr) != 0)
|
||||
return false;
|
||||
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) != 0)
|
||||
goto fail;
|
||||
if (pthread_mutex_init(&hotkeys->mutex, &attr) != 0)
|
||||
goto fail;
|
||||
|
||||
if (os_event_init(&hotkeys->stop_event, OS_EVENT_TYPE_MANUAL) != 0)
|
||||
goto fail;
|
||||
if (pthread_create(&hotkeys->hotkey_thread, NULL,
|
||||
obs_hotkey_thread, NULL))
|
||||
goto fail;
|
||||
|
||||
hotkeys->hotkey_thread_initialized = true;
|
||||
|
||||
success = true;
|
||||
|
||||
fail:
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline void stop_hotkeys(void)
|
||||
{
|
||||
struct obs_core_hotkeys *hotkeys = &obs->hotkeys;
|
||||
void *thread_ret;
|
||||
|
||||
if (hotkeys->hotkey_thread_initialized) {
|
||||
os_event_signal(hotkeys->stop_event);
|
||||
pthread_join(hotkeys->hotkey_thread, &thread_ret);
|
||||
hotkeys->hotkey_thread_initialized = false;
|
||||
}
|
||||
|
||||
os_event_destroy(hotkeys->stop_event);
|
||||
obs_hotkeys_free();
|
||||
}
|
||||
|
||||
static inline void obs_free_hotkeys(void)
|
||||
{
|
||||
struct obs_core_hotkeys *hotkeys = &obs->hotkeys;
|
||||
|
||||
bfree(hotkeys->mute);
|
||||
bfree(hotkeys->unmute);
|
||||
bfree(hotkeys->push_to_mute);
|
||||
bfree(hotkeys->push_to_talk);
|
||||
bfree(hotkeys->sceneitem_show);
|
||||
bfree(hotkeys->sceneitem_hide);
|
||||
|
||||
obs_hotkey_name_map_free();
|
||||
|
||||
obs_hotkeys_platform_free(hotkeys);
|
||||
pthread_mutex_destroy(&hotkeys->mutex);
|
||||
}
|
||||
|
||||
extern const struct obs_source_info scene_info;
|
||||
|
||||
extern void log_system_info(void);
|
||||
|
@ -639,6 +720,8 @@ static bool obs_init(const char *locale)
|
|||
return false;
|
||||
if (!obs_init_handlers())
|
||||
return false;
|
||||
if (!obs_init_hotkeys())
|
||||
return false;
|
||||
|
||||
obs->locale = bstrdup(locale);
|
||||
obs_register_source(&scene_info);
|
||||
|
@ -687,9 +770,11 @@ void obs_shutdown(void)
|
|||
da_free(obs->modeless_ui_callbacks);
|
||||
|
||||
stop_video();
|
||||
stop_hotkeys();
|
||||
|
||||
obs_free_data();
|
||||
obs_free_video();
|
||||
obs_free_hotkeys();
|
||||
obs_free_graphics();
|
||||
obs_free_audio();
|
||||
proc_handler_destroy(obs->procs);
|
||||
|
@ -1347,12 +1432,15 @@ static obs_source_t *obs_load_source_type(obs_data_t *source_data,
|
|||
const char *name = obs_data_get_string(source_data, "name");
|
||||
const char *id = obs_data_get_string(source_data, "id");
|
||||
obs_data_t *settings = obs_data_get_obj(source_data, "settings");
|
||||
obs_data_t *hotkeys = obs_data_get_obj(source_data, "hotkeys");
|
||||
double volume;
|
||||
int64_t sync;
|
||||
uint32_t flags;
|
||||
uint32_t mixers;
|
||||
|
||||
source = obs_source_create(type, id, name, settings);
|
||||
source = obs_source_create(type, id, name, settings, hotkeys);
|
||||
|
||||
obs_data_release(hotkeys);
|
||||
|
||||
obs_data_set_default_double(source_data, "volume", 1.0);
|
||||
volume = obs_data_get_double(source_data, "volume");
|
||||
|
@ -1376,6 +1464,14 @@ static obs_source_t *obs_load_source_type(obs_data_t *source_data,
|
|||
obs_data_set_default_bool(source_data, "muted", false);
|
||||
obs_source_set_muted(source, obs_data_get_bool(source_data, "muted"));
|
||||
|
||||
obs_data_set_default_bool(source_data, "push-to-talk", false);
|
||||
obs_source_enable_push_to_talk(source,
|
||||
obs_data_get_bool(source_data, "push-to-talk"));
|
||||
|
||||
obs_data_set_default_int(source_data, "push-to-talk-delay", 0);
|
||||
obs_source_set_push_to_talk_delay(source,
|
||||
obs_data_get_int(source_data, "push-to-talk-delay"));
|
||||
|
||||
if (filters) {
|
||||
size_t count = obs_data_array_count(filters);
|
||||
|
||||
|
@ -1439,6 +1535,8 @@ obs_data_t *obs_save_source(obs_source_t *source)
|
|||
obs_data_array_t *filters = obs_data_array_create();
|
||||
obs_data_t *source_data = obs_data_create();
|
||||
obs_data_t *settings = obs_source_get_settings(source);
|
||||
obs_data_t *hotkey_data = source->context.hotkey_data;
|
||||
obs_data_t *hotkeys;
|
||||
float volume = obs_source_get_volume(source);
|
||||
uint32_t mixers = obs_source_get_audio_mixers(source);
|
||||
int64_t sync = obs_source_get_sync_offset(source);
|
||||
|
@ -1447,8 +1545,17 @@ obs_data_t *obs_save_source(obs_source_t *source)
|
|||
const char *id = obs_source_get_id(source);
|
||||
bool enabled = obs_source_enabled(source);
|
||||
bool muted = obs_source_muted(source);
|
||||
bool push_to_talk= obs_source_push_to_talk_enabled(source);
|
||||
uint64_t ptt_delay = obs_source_get_push_to_talk_delay(source);
|
||||
|
||||
obs_source_save(source);
|
||||
hotkeys = obs_hotkeys_save_source(source);
|
||||
|
||||
if (hotkeys) {
|
||||
obs_data_release(hotkey_data);
|
||||
source->context.hotkey_data = hotkeys;
|
||||
hotkey_data = hotkeys;
|
||||
}
|
||||
|
||||
obs_data_set_string(source_data, "name", name);
|
||||
obs_data_set_string(source_data, "id", id);
|
||||
|
@ -1459,6 +1566,9 @@ obs_data_t *obs_save_source(obs_source_t *source)
|
|||
obs_data_set_double(source_data, "volume", volume);
|
||||
obs_data_set_bool (source_data, "enabled", enabled);
|
||||
obs_data_set_bool (source_data, "muted", muted);
|
||||
obs_data_set_bool (source_data, "push-to-talk", push_to_talk);
|
||||
obs_data_set_int (source_data, "push-to-talk-delay", ptt_delay);
|
||||
obs_data_set_obj (source_data, "hotkeys", hotkey_data);
|
||||
|
||||
pthread_mutex_lock(&source->filter_mutex);
|
||||
|
||||
|
@ -1522,7 +1632,8 @@ static inline char *dup_name(const char *name)
|
|||
static inline bool obs_context_data_init_wrap(
|
||||
struct obs_context_data *context,
|
||||
obs_data_t *settings,
|
||||
const char *name)
|
||||
const char *name,
|
||||
obs_data_t *hotkey_data)
|
||||
{
|
||||
assert(context);
|
||||
memset(context, 0, sizeof(*context));
|
||||
|
@ -1539,17 +1650,19 @@ static inline bool obs_context_data_init_wrap(
|
|||
if (!context->procs)
|
||||
return false;
|
||||
|
||||
context->name = dup_name(name);
|
||||
context->settings = obs_data_newref(settings);
|
||||
context->name = dup_name(name);
|
||||
context->settings = obs_data_newref(settings);
|
||||
context->hotkey_data = obs_data_newref(hotkey_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool obs_context_data_init(
|
||||
struct obs_context_data *context,
|
||||
obs_data_t *settings,
|
||||
const char *name)
|
||||
const char *name,
|
||||
obs_data_t *hotkey_data)
|
||||
{
|
||||
if (obs_context_data_init_wrap(context, settings, name)) {
|
||||
if (obs_context_data_init_wrap(context, settings, name, hotkey_data)) {
|
||||
return true;
|
||||
} else {
|
||||
obs_context_data_free(context);
|
||||
|
@ -1559,6 +1672,7 @@ bool obs_context_data_init(
|
|||
|
||||
void obs_context_data_free(struct obs_context_data *context)
|
||||
{
|
||||
obs_hotkeys_context_release(context);
|
||||
signal_handler_destroy(context->signals);
|
||||
proc_handler_destroy(context->procs);
|
||||
obs_data_release(context->settings);
|
||||
|
|
27
libobs/obs.h
27
libobs/obs.h
|
@ -72,6 +72,7 @@ typedef struct obs_weak_service obs_weak_service_t;
|
|||
#include "obs-output.h"
|
||||
#include "obs-service.h"
|
||||
#include "obs-audio-controls.h"
|
||||
#include "obs-hotkey.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
|
@ -654,7 +655,8 @@ EXPORT const char *obs_source_get_display_name(enum obs_source_type type,
|
|||
* or modifying video/audio. Use obs_source_release to release it.
|
||||
*/
|
||||
EXPORT obs_source_t *obs_source_create(enum obs_source_type type,
|
||||
const char *id, const char *name, obs_data_t *settings);
|
||||
const char *id, const char *name, obs_data_t *settings,
|
||||
obs_data_t *hotkey_data);
|
||||
|
||||
/**
|
||||
* Adds/releases a reference to a source. When the last reference is
|
||||
|
@ -863,6 +865,20 @@ EXPORT void obs_source_set_enabled(obs_source_t *source, bool enabled);
|
|||
EXPORT bool obs_source_muted(const obs_source_t *source);
|
||||
EXPORT void obs_source_set_muted(obs_source_t *source, bool muted);
|
||||
|
||||
EXPORT bool obs_source_push_to_mute_enabled(obs_source_t *source);
|
||||
EXPORT void obs_source_enable_push_to_mute(obs_source_t *source, bool enabled);
|
||||
|
||||
EXPORT uint64_t obs_source_get_push_to_mute_delay(obs_source_t *source);
|
||||
EXPORT void obs_source_set_push_to_mute_delay(obs_source_t *source,
|
||||
uint64_t delay);
|
||||
|
||||
EXPORT bool obs_source_push_to_talk_enabled(obs_source_t *source);
|
||||
EXPORT void obs_source_enable_push_to_talk(obs_source_t *source, bool enabled);
|
||||
|
||||
EXPORT uint64_t obs_source_get_push_to_talk_delay(obs_source_t *source);
|
||||
EXPORT void obs_source_set_push_to_talk_delay(obs_source_t *source,
|
||||
uint64_t delay);
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* Functions used by sources */
|
||||
|
||||
|
@ -1091,7 +1107,7 @@ EXPORT const char *obs_output_get_display_name(const char *id);
|
|||
* directshow, or other custom outputs.
|
||||
*/
|
||||
EXPORT obs_output_t *obs_output_create(const char *id, const char *name,
|
||||
obs_data_t *settings);
|
||||
obs_data_t *settings, obs_data_t *hotkey_data);
|
||||
|
||||
/**
|
||||
* Adds/releases a reference to an output. When the last reference is
|
||||
|
@ -1301,7 +1317,7 @@ EXPORT const char *obs_encoder_get_display_name(const char *id);
|
|||
* @return The video encoder context, or NULL if failed or not found.
|
||||
*/
|
||||
EXPORT obs_encoder_t *obs_video_encoder_create(const char *id, const char *name,
|
||||
obs_data_t *settings);
|
||||
obs_data_t *settings, obs_data_t *hotkey_data);
|
||||
|
||||
/**
|
||||
* Creates an audio encoder context
|
||||
|
@ -1313,7 +1329,8 @@ EXPORT obs_encoder_t *obs_video_encoder_create(const char *id, const char *name,
|
|||
* @return The video encoder context, or NULL if failed or not found.
|
||||
*/
|
||||
EXPORT obs_encoder_t *obs_audio_encoder_create(const char *id, const char *name,
|
||||
obs_data_t *settings, size_t mixer_idx);
|
||||
obs_data_t *settings, size_t mixer_idx,
|
||||
obs_data_t *hotkey_data);
|
||||
|
||||
/**
|
||||
* Adds/releases a reference to an encoder. When the last reference is
|
||||
|
@ -1433,7 +1450,7 @@ EXPORT void obs_free_encoder_packet(struct encoder_packet *packet);
|
|||
EXPORT const char *obs_service_get_display_name(const char *id);
|
||||
|
||||
EXPORT obs_service_t *obs_service_create(const char *id, const char *name,
|
||||
obs_data_t *settings);
|
||||
obs_data_t *settings, obs_data_t *hotkey_data);
|
||||
|
||||
/**
|
||||
* Adds/releases a reference to a service. When the last reference is
|
||||
|
|
|
@ -117,6 +117,8 @@ set(obs_SOURCES
|
|||
slider-absoluteset-style.cpp
|
||||
source-list-widget.cpp
|
||||
crash-report.cpp
|
||||
hotkey-edit.cpp
|
||||
source-label.cpp
|
||||
qt-wrappers.cpp)
|
||||
|
||||
set(obs_HEADERS
|
||||
|
@ -153,6 +155,8 @@ set(obs_HEADERS
|
|||
source-list-widget.hpp
|
||||
qt-display.hpp
|
||||
crash-report.hpp
|
||||
hotkey-edit.hpp
|
||||
source-label.hpp
|
||||
qt-wrappers.hpp)
|
||||
|
||||
set(obs_UI
|
||||
|
|
|
@ -35,6 +35,8 @@ DroppedFrames="Dropped Frames %1 (%2%)"
|
|||
PreviewProjector="Fullscreen Projector (Preview)"
|
||||
SceneProjector="Fullscreen Projector (Scene)"
|
||||
SourceProjector="Fullscreen Projector (Source)"
|
||||
Clear="Clear"
|
||||
Revert="Revert"
|
||||
|
||||
# "name already exists" dialog box
|
||||
NameExists.Title="Name already exists"
|
||||
|
@ -331,6 +333,10 @@ Basic.Settings.Audio.DesktopDevice2="Desktop Audio Device 2"
|
|||
Basic.Settings.Audio.AuxDevice="Mic/Auxiliary Audio Device"
|
||||
Basic.Settings.Audio.AuxDevice2="Mic/Auxiliary Audio Device 2"
|
||||
Basic.Settings.Audio.AuxDevice3="Mic/Auxiliary Audio Device 3"
|
||||
Basic.Settings.Audio.EnablePushToMute="Enable Push-to-mute"
|
||||
Basic.Settings.Audio.PushToMuteDelay="Push-to-mute delay"
|
||||
Basic.Settings.Audio.EnablePushToTalk="Enable Push-to-talk"
|
||||
Basic.Settings.Audio.PushToTalkDelay="Push-to-talk delay"
|
||||
|
||||
# basic mode 'advanced' settings
|
||||
Basic.Settings.Advanced="Advanced"
|
||||
|
@ -350,3 +356,61 @@ Basic.AdvAudio.Mono="Downmix to Mono"
|
|||
Basic.AdvAudio.Panning="Panning"
|
||||
Basic.AdvAudio.SyncOffset="Sync Offset (ms)"
|
||||
Basic.AdvAudio.AudioTracks="Tracks"
|
||||
|
||||
# basic mode 'hotkeys' settings
|
||||
Basic.Settings.Hotkeys="Hotkeys"
|
||||
Basic.Settings.Hotkeys.Pair="Key combinations shared with '%1' act as toggles"
|
||||
|
||||
# basic mode hotkeys
|
||||
Basic.Hotkeys.StartStreaming="Start Streaming"
|
||||
Basic.Hotkeys.StopStreaming="Stop Streaming"
|
||||
Basic.Hotkeys.StartRecording="Start Recording"
|
||||
Basic.Hotkeys.StopRecording="Stop Recording"
|
||||
Basic.Hotkeys.SelectScene="Switch to scene"
|
||||
|
||||
# hotkeys that may lack translation on certain operating systems
|
||||
Hotkeys.Insert="Insert"
|
||||
Hotkeys.Delete="Delete"
|
||||
Hotkeys.Home="Home"
|
||||
Hotkeys.End="End"
|
||||
Hotkeys.PageUp="Page Up"
|
||||
Hotkeys.PageDown="Page Down"
|
||||
Hotkeys.NumLock="Num Lock"
|
||||
Hotkeys.ScrollLock="Scroll Lock"
|
||||
Hotkeys.CapsLock="Caps Lock"
|
||||
Hotkeys.Backspace="Backspace"
|
||||
Hotkeys.Tab="Tab"
|
||||
Hotkeys.Print="Print"
|
||||
Hotkeys.Pause="Pause"
|
||||
Hotkeys.Left="Left"
|
||||
Hotkeys.Right="Right"
|
||||
Hotkeys.Up="Up"
|
||||
Hotkeys.Down="Down"
|
||||
Hotkeys.Windows="Windows"
|
||||
Hotkeys.Super="Super"
|
||||
Hotkeys.Menu="Menu"
|
||||
Hotkeys.Space="Space"
|
||||
Hotkeys.NumpadNum="Numpad %1"
|
||||
Hotkeys.NumpadMultiply="Numpad Multiply"
|
||||
Hotkeys.NumpadDivide="Numpad Divide"
|
||||
Hotkeys.NumpadAdd="Numpad Add"
|
||||
Hotkeys.NumpadSubtract="Numpad Subtract"
|
||||
Hotkeys.NumpadDecimal="Numpad Decimal"
|
||||
Hotkeys.AppleKeypadNum="%1 (Keypad)"
|
||||
Hotkeys.AppleKeypadMultiply="* (Keypad)"
|
||||
Hotkeys.AppleKeypadDivide="/ (Keypad)"
|
||||
Hotkeys.AppleKeypadAdd="+ (Keypad)"
|
||||
Hotkeys.AppleKeypadSubtract="- (Keypad)"
|
||||
Hotkeys.AppleKeypadDecimal=". (Keypad)"
|
||||
Hotkeys.AppleKeypadEqual="= (Keypad)"
|
||||
Hotkeys.MouseButton="Mouse %1"
|
||||
|
||||
# audio hotkeys
|
||||
Mute="Mute"
|
||||
Unmute="Unmute"
|
||||
Push-to-mute="Push-to-mute"
|
||||
Push-to-talk="Push-to-talk"
|
||||
|
||||
# scene item hotkeys
|
||||
SceneItemShow="Show '%1'"
|
||||
SceneItemHide="Hide '%1'"
|
||||
|
|
|
@ -487,3 +487,7 @@ MuteCheckBox::indicator:checked {
|
|||
MuteCheckBox::indicator:unchecked {
|
||||
image: url(./Dark/unmute.png);
|
||||
}
|
||||
|
||||
OBSHotkeyLabel[hotkeyPairHover=true] {
|
||||
color: red;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,10 @@ MuteCheckBox::indicator:unchecked {
|
|||
image: url(:/res/images/unmute.png);
|
||||
}
|
||||
|
||||
OBSHotkeyLabel[hotkeyPairHover=true] {
|
||||
color: red;
|
||||
}
|
||||
|
||||
|
||||
/* Volume Control */
|
||||
|
||||
|
|
|
@ -87,6 +87,15 @@
|
|||
<normaloff>:/settings/images/settings/video-display-3.png</normaloff>:/settings/images/settings/video-display-3.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.Settings.Hotkeys</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="obs.qrc">
|
||||
<normaloff>:/settings/images/settings/preferences-desktop-keyboard-shortcuts.png</normaloff>:/settings/images/settings/preferences-desktop-keyboard-shortcuts.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.Settings.Advanced</string>
|
||||
|
@ -2005,7 +2014,16 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="7" colspan="2">
|
||||
<widget class="QScrollArea" name="audioSourceScrollArea">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="audioSourceWidget">
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLabel" name="audioMsg">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(255, 0, 4);</string>
|
||||
|
@ -2330,6 +2348,24 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QScrollArea" name="hotkeyPage">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="hotkeyWidget">
|
||||
<layout class="QFormLayout" name="hotkeyLayout">
|
||||
<property name="verticalSpacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="advancedPage">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
||||
<property name="leftMargin">
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
|
@ -22,5 +22,6 @@
|
|||
<file>images/settings/applications-system-2.png</file>
|
||||
<file>images/settings/system-settings-3.png</file>
|
||||
<file>images/settings/network-bluetooth.png</file>
|
||||
<file>images/settings/preferences-desktop-keyboard-shortcuts.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -0,0 +1,471 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2014-2015 by Ruwen Hahn <palana@stunned.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "hotkey-edit.hpp"
|
||||
|
||||
#include <util/dstr.hpp>
|
||||
#include <QPointer>
|
||||
#include <QStyle>
|
||||
|
||||
#include "obs-app.hpp"
|
||||
#include "qt-wrappers.hpp"
|
||||
|
||||
static inline bool operator!=(const obs_key_combination_t &c1,
|
||||
const obs_key_combination_t &c2)
|
||||
{
|
||||
return c1.modifiers != c2.modifiers || c1.key != c2.key;
|
||||
}
|
||||
|
||||
static inline bool operator==(const obs_key_combination_t &c1,
|
||||
const obs_key_combination_t &c2)
|
||||
{
|
||||
return !(c1 != c2);
|
||||
}
|
||||
|
||||
void OBSHotkeyEdit::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->isAutoRepeat())
|
||||
return;
|
||||
|
||||
obs_key_combination_t new_key;
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Shift:
|
||||
case Qt::Key_Control:
|
||||
case Qt::Key_Alt:
|
||||
case Qt::Key_Meta:
|
||||
new_key.key = OBS_KEY_NONE;
|
||||
break;
|
||||
|
||||
#ifdef __APPLE__
|
||||
case Qt::Key_CapsLock:
|
||||
// kVK_CapsLock == 57
|
||||
new_key.key = obs_key_from_virtual_key(57);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
new_key.key =
|
||||
obs_key_from_virtual_key(event->nativeVirtualKey());
|
||||
}
|
||||
|
||||
new_key.modifiers =
|
||||
TranslateQtKeyboardEventModifiers(event->modifiers());
|
||||
|
||||
HandleNewKey(new_key);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
void OBSHotkeyEdit::keyReleaseEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->isAutoRepeat())
|
||||
return;
|
||||
|
||||
if (event->key() != Qt::Key_CapsLock)
|
||||
return;
|
||||
|
||||
obs_key_combination_t new_key;
|
||||
|
||||
// kVK_CapsLock == 57
|
||||
new_key.key = obs_key_from_virtual_key(57);
|
||||
new_key.modifiers =
|
||||
TranslateQtKeyboardEventModifiers(event->modifiers());
|
||||
|
||||
HandleNewKey(new_key);
|
||||
}
|
||||
#endif
|
||||
|
||||
void OBSHotkeyEdit::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
obs_key_combination_t new_key;
|
||||
|
||||
switch (event->button()) {
|
||||
case Qt::NoButton:
|
||||
case Qt::LeftButton:
|
||||
case Qt::RightButton:
|
||||
case Qt::AllButtons:
|
||||
case Qt::MouseButtonMask:
|
||||
return;
|
||||
|
||||
case Qt::MidButton:
|
||||
new_key.key = OBS_KEY_MOUSE3;
|
||||
break;
|
||||
|
||||
#define MAP_BUTTON(i, j) case Qt::ExtraButton ## i: \
|
||||
new_key.key = OBS_KEY_MOUSE ## j; break;
|
||||
MAP_BUTTON( 1, 4);
|
||||
MAP_BUTTON( 2, 5);
|
||||
MAP_BUTTON( 3, 6);
|
||||
MAP_BUTTON( 4, 7);
|
||||
MAP_BUTTON( 5, 8);
|
||||
MAP_BUTTON( 6, 9);
|
||||
MAP_BUTTON( 7, 10);
|
||||
MAP_BUTTON( 8, 11);
|
||||
MAP_BUTTON( 9, 12);
|
||||
MAP_BUTTON(10, 13);
|
||||
MAP_BUTTON(11, 14);
|
||||
MAP_BUTTON(12, 15);
|
||||
MAP_BUTTON(13, 16);
|
||||
MAP_BUTTON(14, 17);
|
||||
MAP_BUTTON(15, 18);
|
||||
MAP_BUTTON(16, 19);
|
||||
MAP_BUTTON(17, 20);
|
||||
MAP_BUTTON(18, 21);
|
||||
MAP_BUTTON(19, 22);
|
||||
MAP_BUTTON(20, 23);
|
||||
MAP_BUTTON(21, 24);
|
||||
MAP_BUTTON(22, 25);
|
||||
MAP_BUTTON(23, 26);
|
||||
MAP_BUTTON(24, 27);
|
||||
#undef MAP_BUTTON
|
||||
}
|
||||
|
||||
new_key.modifiers =
|
||||
TranslateQtKeyboardEventModifiers(event->modifiers());
|
||||
|
||||
HandleNewKey(new_key);
|
||||
}
|
||||
|
||||
void OBSHotkeyEdit::HandleNewKey(obs_key_combination_t new_key)
|
||||
{
|
||||
if (new_key == key)
|
||||
return;
|
||||
|
||||
key = new_key;
|
||||
|
||||
changed = true;
|
||||
emit KeyChanged(key);
|
||||
|
||||
RenderKey();
|
||||
}
|
||||
|
||||
void OBSHotkeyEdit::RenderKey()
|
||||
{
|
||||
DStr str;
|
||||
obs_key_combination_to_str(key, str);
|
||||
|
||||
setText(QT_UTF8(str));
|
||||
}
|
||||
|
||||
void OBSHotkeyEdit::ResetKey()
|
||||
{
|
||||
key = original;
|
||||
|
||||
changed = false;
|
||||
emit KeyChanged(key);
|
||||
|
||||
RenderKey();
|
||||
}
|
||||
|
||||
void OBSHotkeyEdit::ClearKey()
|
||||
{
|
||||
key = {0, OBS_KEY_NONE};
|
||||
|
||||
changed = true;
|
||||
emit KeyChanged(key);
|
||||
|
||||
RenderKey();
|
||||
}
|
||||
|
||||
void OBSHotkeyEdit::InitSignalHandler()
|
||||
{
|
||||
layoutChanged = {obs_get_signal_handler(),
|
||||
"hotkey_layout_change",
|
||||
[](void *this_, calldata_t*)
|
||||
{
|
||||
auto edit = static_cast<OBSHotkeyEdit*>(this_);
|
||||
QMetaObject::invokeMethod(edit, "ReloadKeyLayout");
|
||||
}, this};
|
||||
}
|
||||
|
||||
void OBSHotkeyEdit::ReloadKeyLayout()
|
||||
{
|
||||
RenderKey();
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::SetKeyCombinations(
|
||||
const std::vector<obs_key_combination_t> &combos)
|
||||
{
|
||||
if (combos.empty())
|
||||
AddEdit({0, OBS_KEY_NONE});
|
||||
|
||||
for (auto combo : combos)
|
||||
AddEdit(combo);
|
||||
}
|
||||
|
||||
bool OBSHotkeyWidget::Changed() const
|
||||
{
|
||||
return changed ||
|
||||
std::any_of(begin(edits), end(edits), [](OBSHotkeyEdit *edit)
|
||||
{
|
||||
return edit->changed;
|
||||
});
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::Apply()
|
||||
{
|
||||
for (auto &edit : edits) {
|
||||
edit->original = edit->key;
|
||||
edit->changed = false;
|
||||
}
|
||||
|
||||
changed = false;
|
||||
|
||||
for (auto &revertButton : revertButtons)
|
||||
revertButton->setEnabled(false);
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::GetCombinations(
|
||||
std::vector<obs_key_combination_t> &combinations) const
|
||||
{
|
||||
combinations.clear();
|
||||
for (auto &edit : edits)
|
||||
if (!obs_key_combination_is_empty(edit->key))
|
||||
combinations.emplace_back(edit->key);
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::Save()
|
||||
{
|
||||
std::vector<obs_key_combination_t> combinations;
|
||||
Save(combinations);
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::Save(std::vector<obs_key_combination_t> &combinations)
|
||||
{
|
||||
GetCombinations(combinations);
|
||||
Apply();
|
||||
|
||||
auto AtomicUpdate = [&]()
|
||||
{
|
||||
ignoreChangedBindings = true;
|
||||
|
||||
obs_hotkey_load_bindings(id,
|
||||
combinations.data(), combinations.size());
|
||||
|
||||
ignoreChangedBindings = false;
|
||||
};
|
||||
using AtomicUpdate_t = decltype(&AtomicUpdate);
|
||||
|
||||
obs_hotkey_update_atomic([](void *d)
|
||||
{
|
||||
(*static_cast<AtomicUpdate_t>(d))();
|
||||
}, static_cast<void*>(&AtomicUpdate));
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::AddEdit(obs_key_combination combo, int idx)
|
||||
{
|
||||
auto edit = new OBSHotkeyEdit(combo);
|
||||
edit->setToolTip(toolTip);
|
||||
|
||||
auto revert = new QPushButton;
|
||||
revert->setText(QTStr("Revert"));
|
||||
revert->setEnabled(false);
|
||||
|
||||
auto clear = new QPushButton;
|
||||
clear->setText(QTStr("Clear"));
|
||||
clear->setEnabled(!obs_key_combination_is_empty(combo));
|
||||
|
||||
QObject::connect(edit, &OBSHotkeyEdit::KeyChanged,
|
||||
[=](obs_key_combination_t new_combo)
|
||||
{
|
||||
clear->setEnabled(!obs_key_combination_is_empty(new_combo));
|
||||
revert->setEnabled(edit->original != new_combo);
|
||||
});
|
||||
|
||||
auto add = new QPushButton;
|
||||
add->setText("+");
|
||||
|
||||
auto remove = new QPushButton;
|
||||
remove->setText("-");
|
||||
remove->setEnabled(removeButtons.size() > 0);
|
||||
|
||||
auto CurrentIndex = [&, remove]
|
||||
{
|
||||
auto res = std::find(begin(removeButtons),
|
||||
end(removeButtons),
|
||||
remove);
|
||||
return std::distance(begin(removeButtons), res);
|
||||
};
|
||||
|
||||
QObject::connect(add, &QPushButton::clicked,
|
||||
[&, CurrentIndex]
|
||||
{
|
||||
AddEdit({0, OBS_KEY_NONE}, CurrentIndex() + 1);
|
||||
});
|
||||
|
||||
QObject::connect(remove, &QPushButton::clicked,
|
||||
[&, CurrentIndex]
|
||||
{
|
||||
RemoveEdit(CurrentIndex());
|
||||
});
|
||||
|
||||
QHBoxLayout *subLayout = new QHBoxLayout;
|
||||
subLayout->addWidget(edit);
|
||||
subLayout->addWidget(revert);
|
||||
subLayout->addWidget(clear);
|
||||
subLayout->addWidget(add);
|
||||
subLayout->addWidget(remove);
|
||||
|
||||
if (removeButtons.size() == 1)
|
||||
removeButtons.front()->setEnabled(true);
|
||||
|
||||
if (idx != -1) {
|
||||
revertButtons.insert(begin(revertButtons) + idx, revert);
|
||||
removeButtons.insert(begin(removeButtons) + idx, remove);
|
||||
edits.insert(begin(edits) + idx, edit);
|
||||
} else {
|
||||
revertButtons.emplace_back(revert);
|
||||
removeButtons.emplace_back(remove);
|
||||
edits.emplace_back(edit);
|
||||
}
|
||||
|
||||
layout()->insertLayout(idx, subLayout);
|
||||
|
||||
QObject::connect(revert, &QPushButton::clicked,
|
||||
edit, &OBSHotkeyEdit::ResetKey);
|
||||
QObject::connect(clear, &QPushButton::clicked,
|
||||
edit, &OBSHotkeyEdit::ClearKey);
|
||||
|
||||
QObject::connect(edit, &OBSHotkeyEdit::KeyChanged,
|
||||
[&](obs_key_combination)
|
||||
{
|
||||
emit KeyChanged();
|
||||
});
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::RemoveEdit(size_t idx, bool signal)
|
||||
{
|
||||
auto &edit = *(begin(edits) + idx);
|
||||
if (!obs_key_combination_is_empty(edit->original) && signal) {
|
||||
changed = true;
|
||||
emit KeyChanged();
|
||||
}
|
||||
|
||||
revertButtons.erase(begin(revertButtons) + idx);
|
||||
removeButtons.erase(begin(removeButtons) + idx);
|
||||
edits.erase(begin(edits) + idx);
|
||||
|
||||
auto item = layout()->takeAt(static_cast<int>(idx));
|
||||
QLayoutItem *child = nullptr;
|
||||
while ((child = item->layout()->takeAt(0))) {
|
||||
delete child->widget();
|
||||
delete child;
|
||||
}
|
||||
delete item;
|
||||
|
||||
if (removeButtons.size() == 1)
|
||||
removeButtons.front()->setEnabled(false);
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::BindingsChanged(void *data, calldata_t *param)
|
||||
{
|
||||
auto widget = static_cast<OBSHotkeyWidget*>(data);
|
||||
auto key = static_cast<obs_hotkey_t*>(calldata_ptr(param, "key"));
|
||||
|
||||
QMetaObject::invokeMethod(widget, "HandleChangedBindings",
|
||||
Q_ARG(obs_hotkey_id, obs_hotkey_get_id(key)));
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::HandleChangedBindings(obs_hotkey_id id_)
|
||||
{
|
||||
if (ignoreChangedBindings || id != id_) return;
|
||||
|
||||
std::vector<obs_key_combination_t> bindings;
|
||||
auto LoadBindings = [&](obs_hotkey_binding_t *binding)
|
||||
{
|
||||
if (obs_hotkey_binding_get_hotkey_id(binding) != id) return;
|
||||
|
||||
auto get_combo = obs_hotkey_binding_get_key_combination;
|
||||
bindings.push_back(get_combo(binding));
|
||||
};
|
||||
using LoadBindings_t = decltype(&LoadBindings);
|
||||
|
||||
obs_enum_hotkey_bindings([](void *data,
|
||||
size_t, obs_hotkey_binding_t *binding)
|
||||
{
|
||||
auto LoadBindings = *static_cast<LoadBindings_t>(data);
|
||||
LoadBindings(binding);
|
||||
return true;
|
||||
}, static_cast<void*>(&LoadBindings));
|
||||
|
||||
while (edits.size() > 0)
|
||||
RemoveEdit(edits.size() - 1, false);
|
||||
|
||||
SetKeyCombinations(bindings);
|
||||
}
|
||||
|
||||
static inline void updateStyle(QWidget *widget)
|
||||
{
|
||||
auto style = widget->style();
|
||||
style->unpolish(widget);
|
||||
style->polish(widget);
|
||||
widget->update();
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::enterEvent(QEvent *event)
|
||||
{
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
event->accept();
|
||||
label->highlightPair(true);
|
||||
}
|
||||
|
||||
void OBSHotkeyWidget::leaveEvent(QEvent *event)
|
||||
{
|
||||
if (!label)
|
||||
return;
|
||||
|
||||
event->accept();
|
||||
label->highlightPair(false);
|
||||
}
|
||||
|
||||
void OBSHotkeyLabel::highlightPair(bool highlight)
|
||||
{
|
||||
if (!pairPartner)
|
||||
return;
|
||||
|
||||
pairPartner->setProperty("hotkeyPairHover", highlight);
|
||||
updateStyle(pairPartner);
|
||||
setProperty("hotkeyPairHover", highlight);
|
||||
updateStyle(this);
|
||||
}
|
||||
|
||||
void OBSHotkeyLabel::enterEvent(QEvent *event)
|
||||
{
|
||||
if (!pairPartner)
|
||||
return;
|
||||
|
||||
event->accept();
|
||||
highlightPair(true);
|
||||
}
|
||||
|
||||
void OBSHotkeyLabel::leaveEvent(QEvent *event)
|
||||
{
|
||||
if (!pairPartner)
|
||||
return;
|
||||
|
||||
event->accept();
|
||||
highlightPair(false);
|
||||
}
|
||||
|
||||
void OBSHotkeyLabel::setToolTip(const QString &toolTip)
|
||||
{
|
||||
QLabel::setToolTip(toolTip);
|
||||
if (widget)
|
||||
widget->setToolTip(toolTip);
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2014-2015 by Ruwen Hahn <palana@stunned.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QKeyEvent>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <QPointer>
|
||||
#include <QLabel>
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
class OBSHotkeyWidget;
|
||||
|
||||
class OBSHotkeyLabel : public QLabel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QPointer<OBSHotkeyLabel> pairPartner;
|
||||
QPointer<OBSHotkeyWidget> widget;
|
||||
void highlightPair(bool highlight);
|
||||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void setToolTip(const QString &toolTip);
|
||||
};
|
||||
|
||||
class OBSHotkeyEdit : public QLineEdit {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
OBSHotkeyEdit(obs_key_combination_t original,
|
||||
QWidget *parent=nullptr)
|
||||
: QLineEdit(parent),
|
||||
original(original)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// disable the input cursor on OSX, focus should be clear
|
||||
// enough with the default focus frame
|
||||
setReadOnly(true);
|
||||
#endif
|
||||
setAttribute(Qt::WA_MacShowFocusRect, true);
|
||||
InitSignalHandler();
|
||||
ResetKey();
|
||||
}
|
||||
|
||||
obs_key_combination_t original;
|
||||
obs_key_combination_t key;
|
||||
bool changed = false;
|
||||
protected:
|
||||
OBSSignal layoutChanged;
|
||||
|
||||
void InitSignalHandler();
|
||||
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
#ifdef __APPLE__
|
||||
void keyReleaseEvent(QKeyEvent *event) override;
|
||||
#endif
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
|
||||
void HandleNewKey(obs_key_combination_t new_key);
|
||||
void RenderKey();
|
||||
|
||||
public slots:
|
||||
void ReloadKeyLayout();
|
||||
void ResetKey();
|
||||
void ClearKey();
|
||||
|
||||
signals:
|
||||
void KeyChanged(obs_key_combination_t);
|
||||
};
|
||||
|
||||
class OBSHotkeyWidget : public QWidget {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
OBSHotkeyWidget(obs_hotkey_id id, std::string name,
|
||||
const std::vector<obs_key_combination_t> &combos={},
|
||||
QWidget *parent=nullptr)
|
||||
: QWidget(parent),
|
||||
id(id),
|
||||
name(name),
|
||||
bindingsChanged(obs_get_signal_handler(),
|
||||
"hotkey_bindings_changed",
|
||||
&OBSHotkeyWidget::BindingsChanged,
|
||||
this)
|
||||
{
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->setSpacing(0);
|
||||
layout->setMargin(0);
|
||||
setLayout(layout);
|
||||
|
||||
SetKeyCombinations(combos);
|
||||
}
|
||||
|
||||
void SetKeyCombinations(const std::vector<obs_key_combination_t>&);
|
||||
|
||||
obs_hotkey_id id;
|
||||
std::string name;
|
||||
|
||||
bool changed = false;
|
||||
bool Changed() const;
|
||||
|
||||
QPointer<OBSHotkeyLabel> label;
|
||||
|
||||
QString toolTip;
|
||||
void setToolTip(const QString &toolTip_)
|
||||
{
|
||||
toolTip = toolTip_;
|
||||
for (auto &edit : edits)
|
||||
edit->setToolTip(toolTip_);
|
||||
}
|
||||
|
||||
void Apply();
|
||||
void GetCombinations(std::vector<obs_key_combination_t>&) const;
|
||||
void Save();
|
||||
void Save(std::vector<obs_key_combination_t> &combinations);
|
||||
|
||||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
private:
|
||||
void AddEdit(obs_key_combination combo, int idx=-1);
|
||||
void RemoveEdit(size_t idx, bool signal=true);
|
||||
|
||||
static void BindingsChanged(void *data, calldata_t *param);
|
||||
|
||||
std::vector<QPointer<OBSHotkeyEdit>> edits;
|
||||
std::vector<QPointer<QPushButton>> removeButtons;
|
||||
std::vector<QPointer<QPushButton>> revertButtons;
|
||||
OBSSignal bindingsChanged;
|
||||
bool ignoreChangedBindings = false;
|
||||
|
||||
QVBoxLayout *layout() const
|
||||
{
|
||||
return dynamic_cast<QVBoxLayout*>(QWidget::layout());
|
||||
}
|
||||
|
||||
private slots:
|
||||
void HandleChangedBindings(obs_hotkey_id id_);
|
||||
|
||||
signals:
|
||||
void KeyChanged();
|
||||
};
|
114
obs/obs-app.cpp
114
obs/obs-app.cpp
|
@ -52,6 +52,112 @@ static log_handler_t def_log_handler;
|
|||
static string currentLogFile;
|
||||
static string lastLogFile;
|
||||
|
||||
QObject *CreateShortcutFilter()
|
||||
{
|
||||
return new OBSEventFilter([](QObject *, QEvent *event)
|
||||
{
|
||||
auto mouse_event = [](QMouseEvent &event)
|
||||
{
|
||||
obs_key_combination_t hotkey = {0, OBS_KEY_NONE};
|
||||
bool pressed = event.type() == QEvent::MouseButtonPress;
|
||||
|
||||
switch (event.button()) {
|
||||
case Qt::NoButton:
|
||||
case Qt::LeftButton:
|
||||
case Qt::RightButton:
|
||||
case Qt::AllButtons:
|
||||
case Qt::MouseButtonMask:
|
||||
return false;
|
||||
|
||||
case Qt::MidButton:
|
||||
hotkey.key = OBS_KEY_MOUSE3;
|
||||
break;
|
||||
|
||||
#define MAP_BUTTON(i, j) case Qt::ExtraButton ## i: \
|
||||
hotkey.key = OBS_KEY_MOUSE ## j; break;
|
||||
MAP_BUTTON( 1, 4);
|
||||
MAP_BUTTON( 2, 5);
|
||||
MAP_BUTTON( 3, 6);
|
||||
MAP_BUTTON( 4, 7);
|
||||
MAP_BUTTON( 5, 8);
|
||||
MAP_BUTTON( 6, 9);
|
||||
MAP_BUTTON( 7, 10);
|
||||
MAP_BUTTON( 8, 11);
|
||||
MAP_BUTTON( 9, 12);
|
||||
MAP_BUTTON(10, 13);
|
||||
MAP_BUTTON(11, 14);
|
||||
MAP_BUTTON(12, 15);
|
||||
MAP_BUTTON(13, 16);
|
||||
MAP_BUTTON(14, 17);
|
||||
MAP_BUTTON(15, 18);
|
||||
MAP_BUTTON(16, 19);
|
||||
MAP_BUTTON(17, 20);
|
||||
MAP_BUTTON(18, 21);
|
||||
MAP_BUTTON(19, 22);
|
||||
MAP_BUTTON(20, 23);
|
||||
MAP_BUTTON(21, 24);
|
||||
MAP_BUTTON(22, 25);
|
||||
MAP_BUTTON(23, 26);
|
||||
MAP_BUTTON(24, 27);
|
||||
#undef MAP_BUTTON
|
||||
}
|
||||
|
||||
hotkey.modifiers = TranslateQtKeyboardEventModifiers(
|
||||
event.modifiers());
|
||||
|
||||
obs_hotkey_inject_event(hotkey, pressed);
|
||||
return true;
|
||||
};
|
||||
|
||||
auto key_event = [](QKeyEvent *event)
|
||||
{
|
||||
obs_key_combination_t hotkey = {0, OBS_KEY_NONE};
|
||||
bool pressed = event->type() == QEvent::KeyPress;
|
||||
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Shift:
|
||||
case Qt::Key_Control:
|
||||
case Qt::Key_Alt:
|
||||
case Qt::Key_Meta:
|
||||
break;
|
||||
|
||||
#ifdef __APPLE__
|
||||
case Qt::Key_CapsLock:
|
||||
// kVK_CapsLock == 57
|
||||
hotkey.key = obs_key_from_virtual_key(57);
|
||||
pressed = true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
hotkey.key = obs_key_from_virtual_key(
|
||||
event->nativeVirtualKey());
|
||||
}
|
||||
|
||||
hotkey.modifiers = TranslateQtKeyboardEventModifiers(
|
||||
event->modifiers());
|
||||
|
||||
obs_hotkey_inject_event(hotkey, pressed);
|
||||
};
|
||||
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
return mouse_event(*static_cast<QMouseEvent*>(event));
|
||||
|
||||
/*case QEvent::MouseButtonDblClick:
|
||||
case QEvent::Wheel:*/
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
key_event(static_cast<QKeyEvent*>(event));
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
string CurrentTimeString()
|
||||
{
|
||||
time_t now = time(0);
|
||||
|
@ -330,6 +436,14 @@ bool OBSApp::OBSInit()
|
|||
|
||||
mainWindow->OBSInit();
|
||||
|
||||
connect(this, &QGuiApplication::applicationStateChanged,
|
||||
[](Qt::ApplicationState state)
|
||||
{
|
||||
obs_hotkey_enable_background_press(
|
||||
state != Qt::ApplicationActive);
|
||||
});
|
||||
obs_hotkey_enable_background_press(
|
||||
applicationState() != Qt::ApplicationActive);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
std::string CurrentTimeString();
|
||||
std::string CurrentDateTimeString();
|
||||
std::string GenerateTimeDateFilename(const char *extension);
|
||||
QObject *CreateShortcutFilter();
|
||||
|
||||
struct BaseLexer {
|
||||
lexer lex;
|
||||
|
|
|
@ -51,3 +51,29 @@ void QTToGSWindow(WId windowId, gs_window &gswindow)
|
|||
gswindow.display = QX11Info::display();
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods)
|
||||
{
|
||||
int obsModifiers = INTERACT_NONE;
|
||||
|
||||
if (mods.testFlag(Qt::ShiftModifier))
|
||||
obsModifiers |= INTERACT_SHIFT_KEY;
|
||||
if (mods.testFlag(Qt::AltModifier))
|
||||
obsModifiers |= INTERACT_ALT_KEY;
|
||||
#ifdef __APPLE__
|
||||
// Mac: Meta = Control, Control = Command
|
||||
if (mods.testFlag(Qt::ControlModifier))
|
||||
obsModifiers |= INTERACT_COMMAND_KEY;
|
||||
if (mods.testFlag(Qt::MetaModifier))
|
||||
obsModifiers |= INTERACT_CONTROL_KEY;
|
||||
#else
|
||||
// Handle windows key? Can a browser even trap that key?
|
||||
if (mods.testFlag(Qt::ControlModifier))
|
||||
obsModifiers |= INTERACT_CONTROL_KEY;
|
||||
if (mods.testFlag(Qt::MetaModifier))
|
||||
obsModifiers |= INTERACT_COMMAND_KEY;
|
||||
|
||||
#endif
|
||||
|
||||
return obsModifiers;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <obs.h>
|
||||
|
||||
#define QT_UTF8(str) QString::fromUtf8(str)
|
||||
#define QT_TO_UTF8(str) str.toUtf8().constData()
|
||||
|
@ -28,3 +29,5 @@ struct gs_window;
|
|||
void OBSErrorBox(QWidget *parent, const char *msg, ...);
|
||||
|
||||
void QTToGSWindow(WId windowId, gs_window &gswindow);
|
||||
|
||||
uint32_t TranslateQtKeyboardEventModifiers(Qt::KeyboardModifiers mods);
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2015 by Ruwen Hahn <palana@stunned.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include "source-label.hpp"
|
||||
|
||||
void OBSSourceLabel::SourceRenamed(void *data, calldata_t *params)
|
||||
{
|
||||
auto &label = *static_cast<OBSSourceLabel*>(data);
|
||||
|
||||
const char *name = calldata_string(params, "new_name");
|
||||
label.setText(name);
|
||||
|
||||
emit label.Renamed(name);
|
||||
}
|
||||
|
||||
void OBSSourceLabel::SourceRemoved(void *data, calldata_t *)
|
||||
{
|
||||
auto &label = *static_cast<OBSSourceLabel*>(data);
|
||||
emit label.Removed();
|
||||
}
|
||||
|
||||
void OBSSourceLabel::SourceDestroyed(void *data, calldata_t *)
|
||||
{
|
||||
auto &label = *static_cast<OBSSourceLabel*>(data);
|
||||
emit label.Destroyed();
|
||||
|
||||
label.destroyedSignal.Disconnect();
|
||||
label.removedSignal.Disconnect();
|
||||
label.renamedSignal.Disconnect();
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/******************************************************************************
|
||||
Copyright (C) 2015 by Ruwen Hahn <palana@stunned.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
#include <QLabel>
|
||||
#include <obs.hpp>
|
||||
|
||||
class OBSSourceLabel : public QLabel {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
OBSSignal renamedSignal;
|
||||
OBSSignal removedSignal;
|
||||
OBSSignal destroyedSignal;
|
||||
|
||||
OBSSourceLabel(const obs_source_t *source, QWidget *parent=nullptr,
|
||||
Qt::WindowFlags f=0)
|
||||
: QLabel(obs_source_get_name(source), parent, f),
|
||||
renamedSignal(obs_source_get_signal_handler(source), "rename",
|
||||
&OBSSourceLabel::SourceRenamed, this),
|
||||
removedSignal(obs_source_get_signal_handler(source), "remove",
|
||||
&OBSSourceLabel::SourceRemoved, this),
|
||||
destroyedSignal(obs_source_get_signal_handler(source),
|
||||
"destroy", &OBSSourceLabel::SourceDestroyed,
|
||||
this)
|
||||
{}
|
||||
|
||||
protected:
|
||||
static void SourceRenamed(void *data, calldata_t *params);
|
||||
static void SourceRemoved(void *data, calldata_t *params);
|
||||
static void SourceDestroyed(void *data, calldata_t *params);
|
||||
|
||||
signals:
|
||||
void Renamed(const char *name);
|
||||
void Removed();
|
||||
void Destroyed();
|
||||
};
|
|
@ -63,6 +63,8 @@ OBSBasicAdvAudio::OBSBasicAdvAudio(QWidget *parent)
|
|||
vlayout->addWidget(scrollArea);
|
||||
setLayout(vlayout);
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
/* get global audio sources */
|
||||
for (uint32_t i = 1; i <= 10; i++) {
|
||||
obs_source_t *source = obs_get_output_source(i);
|
||||
|
|
|
@ -66,6 +66,8 @@ OBSBasicFilters::OBSBasicFilters(QWidget *parent, OBSSource source_)
|
|||
const char *name = obs_source_get_name(source);
|
||||
setWindowTitle(QTStr("Basic.Filters.Title").arg(QT_UTF8(name)));
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
connect(ui->preview, SIGNAL(DisplayResized()),
|
||||
this, SLOT(OnPreviewResized()));
|
||||
|
||||
|
@ -367,7 +369,7 @@ void OBSBasicFilters::AddNewFilter(const char *id)
|
|||
}
|
||||
|
||||
obs_source_t *filter = obs_source_create(OBS_SOURCE_TYPE_FILTER,
|
||||
id, name.c_str(), nullptr);
|
||||
id, name.c_str(), nullptr, nullptr);
|
||||
if (filter) {
|
||||
obs_source_filter_add(source, filter);
|
||||
obs_source_release(filter);
|
||||
|
|
|
@ -65,26 +65,28 @@ struct SimpleOutput : BasicOutputHandler {
|
|||
SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
||||
{
|
||||
streamOutput = obs_output_create("rtmp_output", "simple_stream",
|
||||
nullptr);
|
||||
nullptr, nullptr);
|
||||
if (!streamOutput)
|
||||
throw "Failed to create stream output (simple output)";
|
||||
obs_output_release(streamOutput);
|
||||
|
||||
fileOutput = obs_output_create("flv_output", "simple_file_output",
|
||||
nullptr);
|
||||
nullptr, nullptr);
|
||||
if (!fileOutput)
|
||||
throw "Failed to create recording output (simple output)";
|
||||
obs_output_release(fileOutput);
|
||||
|
||||
h264 = obs_video_encoder_create("obs_x264", "simple_h264", nullptr);
|
||||
h264 = obs_video_encoder_create("obs_x264", "simple_h264", nullptr,
|
||||
nullptr);
|
||||
if (!h264)
|
||||
throw "Failed to create h264 encoder (simple output)";
|
||||
obs_encoder_release(h264);
|
||||
|
||||
aac = obs_audio_encoder_create("libfdk_aac", "simple_aac", nullptr, 0);
|
||||
aac = obs_audio_encoder_create("libfdk_aac", "simple_aac", nullptr, 0,
|
||||
nullptr);
|
||||
if (!aac)
|
||||
aac = obs_audio_encoder_create("ffmpeg_aac", "simple_aac",
|
||||
nullptr, 0);
|
||||
nullptr, 0, nullptr);
|
||||
if (!aac)
|
||||
throw "Failed to create audio encoder (simple output)";
|
||||
obs_encoder_release(aac);
|
||||
|
@ -322,21 +324,21 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
|||
"obs-studio/basic/recordEncoder.json");
|
||||
|
||||
streamOutput = obs_output_create("rtmp_output", "adv_stream",
|
||||
nullptr);
|
||||
nullptr, nullptr);
|
||||
if (!streamOutput)
|
||||
throw "Failed to create stream output (advanced output)";
|
||||
obs_output_release(streamOutput);
|
||||
|
||||
if (ffmpegRecording) {
|
||||
fileOutput = obs_output_create("ffmpeg_output",
|
||||
"adv_ffmpeg_output", nullptr);
|
||||
"adv_ffmpeg_output", nullptr, nullptr);
|
||||
if (!fileOutput)
|
||||
throw "Failed to create recording FFmpeg output "
|
||||
"(advanced output)";
|
||||
obs_output_release(fileOutput);
|
||||
} else {
|
||||
fileOutput = obs_output_create("flv_output", "adv_file_output",
|
||||
nullptr);
|
||||
nullptr, nullptr);
|
||||
if (!fileOutput)
|
||||
throw "Failed to create recording output "
|
||||
"(advanced output)";
|
||||
|
@ -344,7 +346,8 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
|||
|
||||
if (!useStreamEncoder) {
|
||||
h264Recording = obs_video_encoder_create(recordEncoder,
|
||||
"recording_h264", recordEncSettings);
|
||||
"recording_h264", recordEncSettings,
|
||||
nullptr);
|
||||
if (!h264Recording)
|
||||
throw "Failed to create recording h264 "
|
||||
"encoder (advanced output)";
|
||||
|
@ -353,7 +356,7 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
|||
}
|
||||
|
||||
h264Streaming = obs_video_encoder_create(streamEncoder,
|
||||
"streaming_h264", streamEncSettings);
|
||||
"streaming_h264", streamEncSettings, nullptr);
|
||||
if (!h264Streaming)
|
||||
throw "Failed to create streaming h264 encoder "
|
||||
"(advanced output)";
|
||||
|
@ -364,10 +367,10 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
|
|||
sprintf(name, "adv_aac%d", i);
|
||||
|
||||
aacTrack[i] = obs_audio_encoder_create("libfdk_aac",
|
||||
name, nullptr, i);
|
||||
name, nullptr, i, nullptr);
|
||||
if (!aacTrack[i])
|
||||
aacTrack[i] = obs_audio_encoder_create("ffmpeg_aac",
|
||||
name, nullptr, i);
|
||||
name, nullptr, i, nullptr);
|
||||
if (!aacTrack[i])
|
||||
throw "Failed to create audio encoder "
|
||||
"(advanced output)";
|
||||
|
|
|
@ -118,6 +118,7 @@ OBSBasic::OBSBasic(QWidget *parent)
|
|||
qRegisterMetaType<OBSScene> ("OBSScene");
|
||||
qRegisterMetaType<OBSSceneItem>("OBSSceneItem");
|
||||
qRegisterMetaType<OBSSource> ("OBSSource");
|
||||
qRegisterMetaType<obs_hotkey_id>("obs_hotkey_id");
|
||||
|
||||
ui->scenes->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
ui->sources->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
|
@ -132,6 +133,8 @@ OBSBasic::OBSBasic(QWidget *parent)
|
|||
stringstream name;
|
||||
name << "OBS " << App()->GetVersionString();
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
blog(LOG_INFO, "%s", name.str().c_str());
|
||||
setWindowTitle(QT_UTF8(name.str().c_str()));
|
||||
|
||||
|
@ -292,7 +295,7 @@ void OBSBasic::CreateDefaultScene()
|
|||
|
||||
#ifdef __APPLE__
|
||||
source = obs_source_create(OBS_SOURCE_TYPE_INPUT, "display_capture",
|
||||
Str("Basic.DisplayCapture"), NULL);
|
||||
Str("Basic.DisplayCapture"), NULL, nullptr);
|
||||
|
||||
if (source) {
|
||||
obs_scene_add(scene, source);
|
||||
|
@ -406,10 +409,13 @@ bool OBSBasic::LoadService()
|
|||
type = obs_data_get_string(data, "type");
|
||||
|
||||
obs_data_t *settings = obs_data_get_obj(data, "settings");
|
||||
obs_data_t *hotkey_data = obs_data_get_obj(data, "hotkeys");
|
||||
|
||||
service = obs_service_create(type, "default_service", settings);
|
||||
service = obs_service_create(type, "default_service", settings,
|
||||
hotkey_data);
|
||||
obs_service_release(service);
|
||||
|
||||
obs_data_release(hotkey_data);
|
||||
obs_data_release(settings);
|
||||
obs_data_release(data);
|
||||
|
||||
|
@ -421,7 +427,8 @@ bool OBSBasic::InitService()
|
|||
if (LoadService())
|
||||
return true;
|
||||
|
||||
service = obs_service_create("rtmp_common", "default_service", nullptr);
|
||||
service = obs_service_create("rtmp_common", "default_service", nullptr,
|
||||
nullptr);
|
||||
if (!service)
|
||||
return false;
|
||||
obs_service_release(service);
|
||||
|
@ -649,11 +656,13 @@ void OBSBasic::OBSInit()
|
|||
}
|
||||
|
||||
InitOBSCallbacks();
|
||||
InitHotkeys();
|
||||
|
||||
AddExtraModulePaths();
|
||||
obs_load_all_modules();
|
||||
|
||||
ResetOutputs();
|
||||
CreateHotkeys();
|
||||
|
||||
if (!InitService())
|
||||
throw "Failed to initialize service";
|
||||
|
@ -677,6 +686,142 @@ void OBSBasic::OBSInit()
|
|||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void OBSBasic::InitHotkeys()
|
||||
{
|
||||
struct obs_hotkeys_translations t = {};
|
||||
t.insert = Str("Hotkeys.Insert");
|
||||
t.del = Str("Hotkeys.Delete");
|
||||
t.home = Str("Hotkeys.Home");
|
||||
t.end = Str("Hotkeys.End");
|
||||
t.page_up = Str("Hotkeys.PageUp");
|
||||
t.page_down = Str("Hotkeys.PageDown");
|
||||
t.num_lock = Str("Hotkeys.NumLock");
|
||||
t.scroll_lock = Str("Hotkeys.ScrollLock");
|
||||
t.caps_lock = Str("Hotkeys.CapsLock");
|
||||
t.backspace = Str("Hotkeys.Backspace");
|
||||
t.tab = Str("Hotkeys.Tab");
|
||||
t.print = Str("Hotkeys.Print");
|
||||
t.pause = Str("Hotkeys.Pause");
|
||||
t.left = Str("Hotkeys.Left");
|
||||
t.right = Str("Hotkeys.Right");
|
||||
t.up = Str("Hotkeys.Up");
|
||||
t.down = Str("Hotkeys.Down");
|
||||
#ifdef _WIN32
|
||||
t.meta = Str("Hotkeys.Windows");
|
||||
#else
|
||||
t.meta = Str("Hotkeys.Super");
|
||||
#endif
|
||||
t.menu = Str("Hotkeys.Menu");
|
||||
t.space = Str("Hotkeys.Space");
|
||||
t.numpad_num = Str("Hotkeys.NumpadNum");
|
||||
t.numpad_multiply = Str("Hotkeys.NumpadMultiply");
|
||||
t.numpad_divide = Str("Hotkeys.NumpadDivide");
|
||||
t.numpad_plus = Str("Hotkeys.NumpadAdd");
|
||||
t.numpad_minus = Str("Hotkeys.NumpadSubtract");
|
||||
t.numpad_decimal = Str("Hotkeys.NumpadDecimal");
|
||||
t.apple_keypad_num = Str("Hotkeys.AppleKeypadNum");
|
||||
t.apple_keypad_multiply = Str("Hotkeys.AppleKeypadMultiply");
|
||||
t.apple_keypad_divide = Str("Hotkeys.AppleKeypadDivide");
|
||||
t.apple_keypad_plus = Str("Hotkeys.AppleKeypadAdd");
|
||||
t.apple_keypad_minus = Str("Hotkeys.AppleKeypadSubtract");
|
||||
t.apple_keypad_decimal = Str("Hotkeys.AppleKeypadDecimal");
|
||||
t.apple_keypad_equal = Str("Hotkeys.AppleKeypadEqual");
|
||||
t.mouse_num = Str("Hotkeys.MouseButton");
|
||||
obs_hotkeys_set_translations(&t);
|
||||
|
||||
obs_hotkeys_set_audio_hotkeys_translations(Str("Mute"), Str("Unmute"),
|
||||
Str("Push-to-talk"), Str("Push-to-mute"));
|
||||
|
||||
obs_hotkeys_set_sceneitem_hotkeys_translations(
|
||||
Str("SceneItemShow"), Str("SceneItemHide"));
|
||||
|
||||
obs_hotkey_enable_callback_rerouting(true);
|
||||
obs_hotkey_set_callback_routing_func(OBSBasic::HotkeyTriggered, this);
|
||||
}
|
||||
|
||||
void OBSBasic::ProcessHotkey(obs_hotkey_id id, bool pressed)
|
||||
{
|
||||
obs_hotkey_trigger_routed_callback(id, pressed);
|
||||
}
|
||||
|
||||
void OBSBasic::HotkeyTriggered(void *data, obs_hotkey_id id, bool pressed)
|
||||
{
|
||||
OBSBasic &basic = *static_cast<OBSBasic*>(data);
|
||||
QMetaObject::invokeMethod(&basic, "ProcessHotkey",
|
||||
Q_ARG(obs_hotkey_id, id), Q_ARG(bool, pressed));
|
||||
}
|
||||
|
||||
void OBSBasic::CreateHotkeys()
|
||||
{
|
||||
auto LoadHotkeyData = [&](const char *name) -> OBSData
|
||||
{
|
||||
const char *info = config_get_string(basicConfig,
|
||||
"Hotkeys", name);
|
||||
if (!info)
|
||||
return {};
|
||||
|
||||
obs_data_t *data = obs_data_create_from_json(info);
|
||||
if (!data)
|
||||
return {};
|
||||
|
||||
OBSData res = data;
|
||||
obs_data_release(data);
|
||||
return res;
|
||||
};
|
||||
|
||||
auto LoadHotkeyPair = [&](obs_hotkey_pair_id id, const char *name0,
|
||||
const char *name1)
|
||||
{
|
||||
obs_data_array_t *array0 =
|
||||
obs_data_get_array(LoadHotkeyData(name0), "bindings");
|
||||
obs_data_array_t *array1 =
|
||||
obs_data_get_array(LoadHotkeyData(name1), "bindings");
|
||||
|
||||
obs_hotkey_pair_load(id, array0, array1);
|
||||
obs_data_array_release(array0);
|
||||
obs_data_array_release(array1);
|
||||
};
|
||||
|
||||
#define MAKE_CALLBACK(pred, method) \
|
||||
[](void *data, obs_hotkey_pair_id, obs_hotkey_t*, bool pressed) \
|
||||
{ \
|
||||
OBSBasic &basic = *static_cast<OBSBasic*>(data); \
|
||||
if (pred && pressed) { \
|
||||
method(); \
|
||||
return true; \
|
||||
} \
|
||||
return false; \
|
||||
}
|
||||
|
||||
streamingHotkeys = obs_hotkey_pair_register_frontend(
|
||||
"OBSBasic.StartStreaming",
|
||||
Str("Basic.Hotkeys.StartStreaming"),
|
||||
"OBSBasic.StopStreaming",
|
||||
Str("Basic.Hotkeys.StopStreaming"),
|
||||
MAKE_CALLBACK(!basic.outputHandler->StreamingActive(),
|
||||
basic.StartStreaming),
|
||||
MAKE_CALLBACK(basic.outputHandler->StreamingActive(),
|
||||
basic.StopStreaming),
|
||||
this, this);
|
||||
LoadHotkeyPair(streamingHotkeys,
|
||||
"OBSBasic.StartStreaming", "OBSBasic.StopStreaming");
|
||||
|
||||
recordingHotkeys = obs_hotkey_pair_register_frontend(
|
||||
"OBSBasic.StartRecording",
|
||||
Str("Basic.Hotkeys.StartRecording"),
|
||||
"OBSBasic.StopRecording",
|
||||
Str("Basic.Hotkeys.StopRecording"),
|
||||
MAKE_CALLBACK(!basic.outputHandler->RecordingActive(),
|
||||
basic.StartRecording),
|
||||
MAKE_CALLBACK(basic.outputHandler->RecordingActive(),
|
||||
basic.StopRecording),
|
||||
this, this);
|
||||
LoadHotkeyPair(recordingHotkeys,
|
||||
"OBSBasic.StartRecording", "OBSBasic.StopRecording");
|
||||
|
||||
#undef MAKE_CALLBACK
|
||||
}
|
||||
|
||||
OBSBasic::~OBSBasic()
|
||||
{
|
||||
bool previewEnabled = obs_preview_enabled();
|
||||
|
@ -690,6 +835,10 @@ OBSBasic::~OBSBasic()
|
|||
delete cpuUsageTimer;
|
||||
os_cpu_usage_info_destroy(cpuUsageInfo);
|
||||
|
||||
obs_hotkey_set_callback_routing_func(nullptr, nullptr);
|
||||
obs_hotkey_pair_unregister(streamingHotkeys);
|
||||
obs_hotkey_pair_unregister(recordingHotkeys);
|
||||
|
||||
service = nullptr;
|
||||
outputHandler.reset();
|
||||
|
||||
|
@ -843,6 +992,18 @@ void OBSBasic::AddScene(OBSSource source)
|
|||
item->setData(Qt::UserRole, QVariant::fromValue(OBSScene(scene)));
|
||||
ui->scenes->addItem(item);
|
||||
|
||||
obs_hotkey_register_source(source, "OBSBasic.SelectScene",
|
||||
Str("Basic.Hotkeys.SelectScene"),
|
||||
[](void *data,
|
||||
obs_hotkey_id, obs_hotkey_t*, bool pressed)
|
||||
{
|
||||
auto potential_source = static_cast<obs_source_t*>(data);
|
||||
auto source = obs_source_get_ref(potential_source);
|
||||
if (source && pressed)
|
||||
obs_set_output_source(0, source);
|
||||
obs_source_release(source);
|
||||
}, static_cast<obs_source_t*>(source));
|
||||
|
||||
signal_handler_t *handler = obs_source_get_signal_handler(source);
|
||||
signal_handler_connect(handler, "item_add",
|
||||
OBSBasic::SceneItemAdded, this);
|
||||
|
@ -1449,7 +1610,8 @@ void OBSBasic::RenderMain(void *data, uint32_t cx, uint32_t cy)
|
|||
obs_service_t *OBSBasic::GetService()
|
||||
{
|
||||
if (!service) {
|
||||
service = obs_service_create("rtmp_common", NULL, NULL);
|
||||
service = obs_service_create("rtmp_common", NULL, NULL,
|
||||
nullptr);
|
||||
obs_service_release(service);
|
||||
}
|
||||
return service;
|
||||
|
@ -1635,7 +1797,7 @@ void OBSBasic::ResetAudioDevice(const char *sourceId, const char *deviceName,
|
|||
obs_data_t *settings = obs_data_create();
|
||||
obs_data_set_string(settings, "device_id", deviceId);
|
||||
source = obs_source_create(OBS_SOURCE_TYPE_INPUT,
|
||||
sourceId, deviceDesc, settings);
|
||||
sourceId, deviceDesc, settings, nullptr);
|
||||
obs_data_release(settings);
|
||||
|
||||
obs_set_output_source(channel, source);
|
||||
|
@ -2444,6 +2606,27 @@ void OBSBasic::OpenSceneFilters()
|
|||
CreateFiltersWindow(source);
|
||||
}
|
||||
|
||||
void OBSBasic::StartStreaming()
|
||||
{
|
||||
SaveProject();
|
||||
|
||||
if (outputHandler->StreamingActive())
|
||||
return;
|
||||
|
||||
if (outputHandler->StartStreaming(service)) {
|
||||
ui->streamButton->setEnabled(false);
|
||||
ui->streamButton->setText(QTStr("Basic.Main.Connecting"));
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasic::StopStreaming()
|
||||
{
|
||||
SaveProject();
|
||||
|
||||
if (outputHandler->StreamingActive())
|
||||
outputHandler->StopStreaming();
|
||||
}
|
||||
|
||||
void OBSBasic::StreamingStart()
|
||||
{
|
||||
ui->streamButton->setText(QTStr("Basic.Main.StopStreaming"));
|
||||
|
@ -2490,6 +2673,22 @@ void OBSBasic::StreamingStop(int code)
|
|||
QT_UTF8(errorMessage));
|
||||
}
|
||||
|
||||
void OBSBasic::StartRecording()
|
||||
{
|
||||
SaveProject();
|
||||
|
||||
if (!outputHandler->RecordingActive())
|
||||
outputHandler->StartRecording();
|
||||
}
|
||||
|
||||
void OBSBasic::StopRecording()
|
||||
{
|
||||
SaveProject();
|
||||
|
||||
if (outputHandler->RecordingActive())
|
||||
outputHandler->StopRecording();
|
||||
}
|
||||
|
||||
void OBSBasic::RecordingStart()
|
||||
{
|
||||
ui->statusbar->RecordingStarted(outputHandler->fileOutput);
|
||||
|
@ -2504,28 +2703,19 @@ void OBSBasic::RecordingStop()
|
|||
|
||||
void OBSBasic::on_streamButton_clicked()
|
||||
{
|
||||
SaveProject();
|
||||
|
||||
if (outputHandler->StreamingActive()) {
|
||||
outputHandler->StopStreaming();
|
||||
StopStreaming();
|
||||
} else {
|
||||
if (outputHandler->StartStreaming(service)) {
|
||||
ui->streamButton->setEnabled(false);
|
||||
ui->streamButton->setText(
|
||||
QTStr("Basic.Main.Connecting"));
|
||||
}
|
||||
StartStreaming();
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasic::on_recordButton_clicked()
|
||||
{
|
||||
SaveProject();
|
||||
|
||||
if (outputHandler->RecordingActive()) {
|
||||
outputHandler->StopRecording();
|
||||
} else {
|
||||
outputHandler->StartRecording();
|
||||
}
|
||||
if (outputHandler->RecordingActive())
|
||||
StopRecording();
|
||||
else
|
||||
StartRecording();
|
||||
}
|
||||
|
||||
void OBSBasic::on_settingsButton_clicked()
|
||||
|
|
|
@ -112,6 +112,9 @@ private:
|
|||
void Save(const char *file);
|
||||
void Load(const char *file);
|
||||
|
||||
void InitHotkeys();
|
||||
void CreateHotkeys();
|
||||
|
||||
bool InitService();
|
||||
|
||||
bool InitBasicConfigDefaults();
|
||||
|
@ -149,10 +152,18 @@ private:
|
|||
void Nudge(int dist, MoveDir dir);
|
||||
void OpenProjector(obs_source_t *source, int monitor);
|
||||
|
||||
obs_hotkey_pair_id streamingHotkeys, recordingHotkeys;
|
||||
|
||||
public slots:
|
||||
void StartStreaming();
|
||||
void StopStreaming();
|
||||
|
||||
void StreamingStart();
|
||||
void StreamingStop(int errorcode);
|
||||
|
||||
void StartRecording();
|
||||
void StopRecording();
|
||||
|
||||
void RecordingStart();
|
||||
void RecordingStop();
|
||||
|
||||
|
@ -177,6 +188,8 @@ private slots:
|
|||
|
||||
void ReorderSources(OBSScene scene);
|
||||
|
||||
void ProcessHotkey(obs_hotkey_id id, bool pressed);
|
||||
|
||||
private:
|
||||
/* OBS Callbacks */
|
||||
static void SceneReordered(void *data, calldata_t *params);
|
||||
|
@ -199,6 +212,8 @@ private:
|
|||
void AddSourcePopupMenu(const QPoint &pos);
|
||||
void copyActionsDynamicProperties();
|
||||
|
||||
static void HotkeyTriggered(void *data, obs_hotkey_id id, bool pressed);
|
||||
|
||||
public:
|
||||
OBSScene GetCurrentScene();
|
||||
|
||||
|
|
|
@ -78,6 +78,8 @@ OBSBasicProperties::OBSBasicProperties(QWidget *parent, OBSSource source_)
|
|||
view->setMinimumHeight(150);
|
||||
view->show();
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
connect(view, SIGNAL(PropertiesResized()),
|
||||
this, SLOT(OnPropertiesResized()));
|
||||
|
||||
|
|
|
@ -28,7 +28,10 @@
|
|||
#include <QVariant>
|
||||
#include <QTreeView>
|
||||
#include <QStandardItemModel>
|
||||
#include <QSpacerItem>
|
||||
|
||||
#include "hotkey-edit.hpp"
|
||||
#include "source-label.hpp"
|
||||
#include "obs-app.hpp"
|
||||
#include "platform.hpp"
|
||||
#include "properties-view.hpp"
|
||||
|
@ -307,10 +310,49 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
|
|||
// Initialize libff library
|
||||
ff_init();
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
LoadServiceTypes();
|
||||
LoadEncoderTypes();
|
||||
LoadColorRanges();
|
||||
LoadFormats();
|
||||
|
||||
auto ReloadAudioSources = [](void *data, calldata_t *param)
|
||||
{
|
||||
auto settings = static_cast<OBSBasicSettings*>(data);
|
||||
auto source = static_cast<obs_source_t*>(calldata_ptr(param,
|
||||
"source"));
|
||||
|
||||
if (!(obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO))
|
||||
return;
|
||||
|
||||
QMetaObject::invokeMethod(settings, "ReloadAudioSources",
|
||||
Qt::QueuedConnection);
|
||||
};
|
||||
sourceCreated.Connect(obs_get_signal_handler(), "source_create",
|
||||
ReloadAudioSources, this);
|
||||
channelChanged.Connect(obs_get_signal_handler(), "channel_change",
|
||||
ReloadAudioSources, this);
|
||||
|
||||
auto ReloadHotkeys = [](void *data, calldata_t*)
|
||||
{
|
||||
auto settings = static_cast<OBSBasicSettings*>(data);
|
||||
QMetaObject::invokeMethod(settings, "ReloadHotkeys");
|
||||
};
|
||||
hotkeyRegistered.Connect(obs_get_signal_handler(), "hotkey_register",
|
||||
ReloadHotkeys, this);
|
||||
|
||||
auto ReloadHotkeysIgnore = [](void *data, calldata_t *param)
|
||||
{
|
||||
auto settings = static_cast<OBSBasicSettings*>(data);
|
||||
auto key = static_cast<obs_hotkey_t*>(
|
||||
calldata_ptr(param,"key"));
|
||||
QMetaObject::invokeMethod(settings, "ReloadHotkeys",
|
||||
Q_ARG(obs_hotkey_id, obs_hotkey_get_id(key)));
|
||||
};
|
||||
hotkeyUnregistered.Connect(obs_get_signal_handler(),
|
||||
"hotkey_unregister", ReloadHotkeysIgnore, this);
|
||||
|
||||
LoadSettings(false);
|
||||
}
|
||||
|
||||
|
@ -1220,6 +1262,135 @@ void OBSBasicSettings::LoadAudioDevices()
|
|||
}
|
||||
}
|
||||
|
||||
void OBSBasicSettings::LoadAudioSources()
|
||||
{
|
||||
auto layout = new QFormLayout();
|
||||
layout->setVerticalSpacing(15);
|
||||
layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
|
||||
ui->audioSourceScrollArea->takeWidget()->deleteLater();
|
||||
audioSourceSignals.clear();
|
||||
audioSources.clear();
|
||||
|
||||
auto widget = new QWidget();
|
||||
widget->setLayout(layout);
|
||||
ui->audioSourceScrollArea->setWidget(widget);
|
||||
|
||||
const char *enablePtm = Str("Basic.Settings.Audio.EnablePushToMute");
|
||||
const char *ptmDelay = Str("Basic.Settings.Audio.PushToMuteDelay");
|
||||
const char *enablePtt = Str("Basic.Settings.Audio.EnablePushToTalk");
|
||||
const char *pttDelay = Str("Basic.Settings.Audio.PushToTalkDelay");
|
||||
auto AddSource = [&](obs_source_t *source)
|
||||
{
|
||||
if (!(obs_source_get_output_flags(source) & OBS_SOURCE_AUDIO))
|
||||
return true;
|
||||
|
||||
auto form = new QFormLayout();
|
||||
form->setVerticalSpacing(0);
|
||||
form->setHorizontalSpacing(5);
|
||||
form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
|
||||
auto ptmCB = new SilentUpdateCheckBox();
|
||||
ptmCB->setText(enablePtm);
|
||||
ptmCB->setChecked(obs_source_push_to_mute_enabled(source));
|
||||
form->addRow(ptmCB);
|
||||
|
||||
auto ptmSB = new SilentUpdateSpinBox();
|
||||
ptmSB->setSuffix(" ms");
|
||||
ptmSB->setRange(0, INT_MAX);
|
||||
ptmSB->setValue(obs_source_get_push_to_mute_delay(source));
|
||||
form->addRow(ptmDelay, ptmSB);
|
||||
|
||||
auto pttCB = new SilentUpdateCheckBox();
|
||||
pttCB->setText(enablePtt);
|
||||
pttCB->setChecked(obs_source_push_to_talk_enabled(source));
|
||||
form->addRow(pttCB);
|
||||
|
||||
auto pttSB = new SilentUpdateSpinBox();
|
||||
pttSB->setSuffix(" ms");
|
||||
pttSB->setRange(0, INT_MAX);
|
||||
pttSB->setValue(obs_source_get_push_to_talk_delay(source));
|
||||
form->addRow(pttDelay, pttSB);
|
||||
|
||||
HookWidget(ptmCB, CHECK_CHANGED, AUDIO_CHANGED);
|
||||
HookWidget(ptmSB, SCROLL_CHANGED, AUDIO_CHANGED);
|
||||
HookWidget(pttCB, CHECK_CHANGED, AUDIO_CHANGED);
|
||||
HookWidget(pttSB, SCROLL_CHANGED, AUDIO_CHANGED);
|
||||
|
||||
audioSourceSignals.reserve(audioSourceSignals.size() + 4);
|
||||
|
||||
auto handler = obs_source_get_signal_handler(source);
|
||||
audioSourceSignals.emplace_back(handler, "push_to_mute_changed",
|
||||
[](void *data, calldata_t *param)
|
||||
{
|
||||
QMetaObject::invokeMethod(static_cast<QObject*>(data),
|
||||
"setCheckedSilently",
|
||||
Q_ARG(bool, calldata_bool(param, "enabled")));
|
||||
}, ptmCB);
|
||||
audioSourceSignals.emplace_back(handler, "push_to_mute_delay",
|
||||
[](void *data, calldata_t *param)
|
||||
{
|
||||
QMetaObject::invokeMethod(static_cast<QObject*>(data),
|
||||
"setValueSilently",
|
||||
Q_ARG(int, calldata_int(param, "delay")));
|
||||
}, ptmSB);
|
||||
audioSourceSignals.emplace_back(handler, "push_to_talk_changed",
|
||||
[](void *data, calldata_t *param)
|
||||
{
|
||||
QMetaObject::invokeMethod(static_cast<QObject*>(data),
|
||||
"setCheckedSilently",
|
||||
Q_ARG(bool, calldata_bool(param, "enabled")));
|
||||
}, pttCB);
|
||||
audioSourceSignals.emplace_back(handler, "push_to_talk_delay",
|
||||
[](void *data, calldata_t *param)
|
||||
{
|
||||
QMetaObject::invokeMethod(static_cast<QObject*>(data),
|
||||
"setValueSilently",
|
||||
Q_ARG(int, calldata_int(param, "delay")));
|
||||
}, pttSB);
|
||||
|
||||
audioSources.emplace_back(OBSGetWeakRef(source),
|
||||
ptmCB, pttSB, pttCB, pttSB);
|
||||
|
||||
auto label = new OBSSourceLabel(source);
|
||||
connect(label, &OBSSourceLabel::Removed,
|
||||
[=]()
|
||||
{
|
||||
LoadAudioSources();
|
||||
});
|
||||
connect(label, &OBSSourceLabel::Destroyed,
|
||||
[=]()
|
||||
{
|
||||
LoadAudioSources();
|
||||
});
|
||||
|
||||
layout->addRow(label, form);
|
||||
return true;
|
||||
};
|
||||
|
||||
for (int i = 0; i < MAX_CHANNELS; i++) {
|
||||
obs_source_t *source = obs_get_output_source(i);
|
||||
if (!source) continue;
|
||||
|
||||
AddSource(source);
|
||||
obs_source_release(source);
|
||||
}
|
||||
|
||||
using AddSource_t = decltype(AddSource);
|
||||
obs_enum_sources([](void *data, obs_source_t *source)
|
||||
{
|
||||
auto &AddSource = *static_cast<AddSource_t*>(data);
|
||||
AddSource(source);
|
||||
return true;
|
||||
}, static_cast<void*>(&AddSource));
|
||||
|
||||
|
||||
if (layout->rowCount() == 0)
|
||||
ui->audioSourceScrollArea->hide();
|
||||
else
|
||||
ui->audioSourceScrollArea->show();
|
||||
}
|
||||
|
||||
void OBSBasicSettings::LoadAudioSettings()
|
||||
{
|
||||
uint32_t sampleRate = config_get_uint(main->Config(), "Audio",
|
||||
|
@ -1247,6 +1418,7 @@ void OBSBasicSettings::LoadAudioSettings()
|
|||
ui->channelSetup->setCurrentIndex(1);
|
||||
|
||||
LoadAudioDevices();
|
||||
LoadAudioSources();
|
||||
|
||||
loading = false;
|
||||
}
|
||||
|
@ -1276,6 +1448,290 @@ void OBSBasicSettings::LoadAdvancedSettings()
|
|||
loading = false;
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static inline void LayoutHotkey(obs_hotkey_id id, obs_hotkey_t *key, Func &&fun,
|
||||
const map<obs_hotkey_id, vector<obs_key_combination_t>> &keys)
|
||||
{
|
||||
auto *label = new OBSHotkeyLabel;
|
||||
label->setText(obs_hotkey_get_description(key));
|
||||
|
||||
OBSHotkeyWidget *hw = nullptr;
|
||||
|
||||
auto combos = keys.find(id);
|
||||
if (combos == std::end(keys))
|
||||
hw = new OBSHotkeyWidget(id, obs_hotkey_get_name(key));
|
||||
else
|
||||
hw = new OBSHotkeyWidget(id, obs_hotkey_get_name(key),
|
||||
combos->second);
|
||||
|
||||
hw->label = label;
|
||||
label->widget = hw;
|
||||
|
||||
fun(key, label, hw);
|
||||
}
|
||||
|
||||
template <typename Func, typename T>
|
||||
static QLabel *makeLabel(T &t, Func &&getName)
|
||||
{
|
||||
return new QLabel(getName(t));
|
||||
}
|
||||
|
||||
template <typename Func>
|
||||
static QLabel *makeLabel(const OBSSource &source, Func &&)
|
||||
{
|
||||
return new OBSSourceLabel(source);
|
||||
}
|
||||
|
||||
template <typename Func, typename T>
|
||||
static inline void AddHotkeys(QFormLayout &layout,
|
||||
Func &&getName, std::vector<
|
||||
std::tuple<T, QPointer<QLabel>, QPointer<QWidget>>
|
||||
> &hotkeys)
|
||||
{
|
||||
if (hotkeys.empty())
|
||||
return;
|
||||
|
||||
auto line = new QFrame();
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
layout.setItem(layout.rowCount(), QFormLayout::SpanningRole,
|
||||
new QSpacerItem(0, 10));
|
||||
layout.addRow(line);
|
||||
|
||||
using tuple_type =
|
||||
std::tuple<T, QPointer<QLabel>, QPointer<QWidget>>;
|
||||
|
||||
stable_sort(begin(hotkeys), end(hotkeys),
|
||||
[&](const tuple_type &a, const tuple_type &b)
|
||||
{
|
||||
const auto &o_a = get<0>(a);
|
||||
const auto &o_b = get<0>(b);
|
||||
return o_a != o_b &&
|
||||
string(getName(o_a)) <
|
||||
getName(o_b);
|
||||
});
|
||||
|
||||
string prevName;
|
||||
for (const auto &hotkey : hotkeys) {
|
||||
const auto &o = get<0>(hotkey);
|
||||
const char *name = getName(o);
|
||||
if (prevName != name) {
|
||||
prevName = name;
|
||||
layout.setItem(layout.rowCount(),
|
||||
QFormLayout::SpanningRole,
|
||||
new QSpacerItem(0, 10));
|
||||
layout.addRow(makeLabel(o, getName));
|
||||
}
|
||||
|
||||
auto hlabel = get<1>(hotkey);
|
||||
auto widget = get<2>(hotkey);
|
||||
layout.addRow(hlabel, widget);
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasicSettings::LoadHotkeySettings(obs_hotkey_id ignoreKey)
|
||||
{
|
||||
hotkeys.clear();
|
||||
ui->hotkeyPage->takeWidget()->deleteLater();
|
||||
|
||||
using keys_t = map<obs_hotkey_id, vector<obs_key_combination_t>>;
|
||||
keys_t keys;
|
||||
obs_enum_hotkey_bindings([](void *data,
|
||||
size_t, obs_hotkey_binding_t *binding)
|
||||
{
|
||||
auto &keys = *static_cast<keys_t*>(data);
|
||||
|
||||
keys[obs_hotkey_binding_get_hotkey_id(binding)].emplace_back(
|
||||
obs_hotkey_binding_get_key_combination(binding));
|
||||
|
||||
return true;
|
||||
}, &keys);
|
||||
|
||||
auto layout = new QFormLayout();
|
||||
layout->setVerticalSpacing(0);
|
||||
layout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
|
||||
layout->setLabelAlignment(
|
||||
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);
|
||||
|
||||
auto widget = new QWidget();
|
||||
widget->setLayout(layout);
|
||||
ui->hotkeyPage->setWidget(widget);
|
||||
|
||||
using namespace std;
|
||||
using encoders_elem_t =
|
||||
tuple<OBSEncoder, QPointer<QLabel>, QPointer<QWidget>>;
|
||||
using outputs_elem_t =
|
||||
tuple<OBSOutput, QPointer<QLabel>, QPointer<QWidget>>;
|
||||
using services_elem_t =
|
||||
tuple<OBSService, QPointer<QLabel>, QPointer<QWidget>>;
|
||||
using sources_elem_t =
|
||||
tuple<OBSSource, QPointer<QLabel>, QPointer<QWidget>>;
|
||||
vector<encoders_elem_t> encoders;
|
||||
vector<outputs_elem_t> outputs;
|
||||
vector<services_elem_t> services;
|
||||
vector<sources_elem_t> scenes;
|
||||
vector<sources_elem_t> sources;
|
||||
|
||||
vector<obs_hotkey_id> pairIds;
|
||||
map<obs_hotkey_id, pair<obs_hotkey_id, OBSHotkeyLabel*>> pairLabels;
|
||||
|
||||
using std::move;
|
||||
|
||||
auto HandleEncoder = [&](void *registerer, OBSHotkeyLabel *label,
|
||||
OBSHotkeyWidget *hw)
|
||||
{
|
||||
auto weak_encoder =
|
||||
static_cast<obs_weak_encoder_t*>(registerer);
|
||||
auto encoder = OBSGetStrongRef(weak_encoder);
|
||||
|
||||
if (!encoder)
|
||||
return true;
|
||||
|
||||
encoders.emplace_back(move(encoder), label, hw);
|
||||
return false;
|
||||
};
|
||||
|
||||
auto HandleOutput = [&](void *registerer, OBSHotkeyLabel *label,
|
||||
OBSHotkeyWidget *hw)
|
||||
{
|
||||
auto weak_output = static_cast<obs_weak_output_t*>(registerer);
|
||||
auto output = OBSGetStrongRef(weak_output);
|
||||
|
||||
if (!output)
|
||||
return true;
|
||||
|
||||
outputs.emplace_back(move(output), label, hw);
|
||||
return false;
|
||||
};
|
||||
|
||||
auto HandleService = [&](void *registerer, OBSHotkeyLabel *label,
|
||||
OBSHotkeyWidget *hw)
|
||||
{
|
||||
auto weak_service =
|
||||
static_cast<obs_weak_service_t*>(registerer);
|
||||
auto service = OBSGetStrongRef(weak_service);
|
||||
|
||||
if (!service)
|
||||
return true;
|
||||
|
||||
services.emplace_back(move(service), label, hw);
|
||||
return false;
|
||||
};
|
||||
|
||||
auto HandleSource = [&](void *registerer, OBSHotkeyLabel *label,
|
||||
OBSHotkeyWidget *hw)
|
||||
{
|
||||
auto weak_source = static_cast<obs_weak_source_t*>(registerer);
|
||||
auto source = OBSGetStrongRef(weak_source);
|
||||
|
||||
if (!source)
|
||||
return true;
|
||||
|
||||
if (obs_scene_from_source(source))
|
||||
scenes.emplace_back(source, label, hw);
|
||||
else
|
||||
sources.emplace_back(source, label, hw);
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
auto RegisterHotkey = [&](obs_hotkey_t *key, OBSHotkeyLabel *label,
|
||||
OBSHotkeyWidget *hw)
|
||||
{
|
||||
auto registerer_type = obs_hotkey_get_registerer_type(key);
|
||||
void *registerer = obs_hotkey_get_registerer(key);
|
||||
|
||||
obs_hotkey_id partner = obs_hotkey_get_pair_partner_id(key);
|
||||
if (partner != OBS_INVALID_HOTKEY_ID) {
|
||||
pairLabels.emplace(obs_hotkey_get_id(key),
|
||||
make_pair(partner, label));
|
||||
pairIds.push_back(obs_hotkey_get_id(key));
|
||||
}
|
||||
|
||||
using std::move;
|
||||
|
||||
switch (registerer_type) {
|
||||
case OBS_HOTKEY_REGISTERER_FRONTEND:
|
||||
layout->addRow(label, hw);
|
||||
break;
|
||||
|
||||
case OBS_HOTKEY_REGISTERER_ENCODER:
|
||||
if (HandleEncoder(registerer, label, hw))
|
||||
return;
|
||||
break;
|
||||
|
||||
case OBS_HOTKEY_REGISTERER_OUTPUT:
|
||||
if (HandleOutput(registerer, label, hw))
|
||||
return;
|
||||
break;
|
||||
|
||||
case OBS_HOTKEY_REGISTERER_SERVICE:
|
||||
if (HandleService(registerer, label, hw))
|
||||
return;
|
||||
break;
|
||||
|
||||
case OBS_HOTKEY_REGISTERER_SOURCE:
|
||||
if (HandleSource(registerer, label, hw))
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
hotkeys.emplace_back(registerer_type ==
|
||||
OBS_HOTKEY_REGISTERER_FRONTEND, hw);
|
||||
connect(hw, &OBSHotkeyWidget::KeyChanged,
|
||||
this, &OBSBasicSettings::HotkeysChanged);
|
||||
};
|
||||
|
||||
auto data = make_tuple(RegisterHotkey, std::move(keys), ignoreKey);
|
||||
using data_t = decltype(data);
|
||||
obs_enum_hotkeys([](void *data, obs_hotkey_id id, obs_hotkey_t *key)
|
||||
{
|
||||
data_t &d = *static_cast<data_t*>(data);
|
||||
if (id != get<2>(d))
|
||||
LayoutHotkey(id, key, get<0>(d), get<1>(d));
|
||||
return true;
|
||||
}, &data);
|
||||
|
||||
for (auto keyId : pairIds) {
|
||||
auto data1 = pairLabels.find(keyId);
|
||||
if (data1 == end(pairLabels))
|
||||
continue;
|
||||
|
||||
auto &label1 = data1->second.second;
|
||||
if (label1->pairPartner)
|
||||
continue;
|
||||
|
||||
auto data2 = pairLabels.find(data1->second.first);
|
||||
if (data2 == end(pairLabels))
|
||||
continue;
|
||||
|
||||
auto &label2 = data2->second.second;
|
||||
if (label2->pairPartner)
|
||||
continue;
|
||||
|
||||
QString tt = QTStr("Basic.Settings.Hotkeys.Pair");
|
||||
auto name1 = label1->text();
|
||||
auto name2 = label2->text();
|
||||
|
||||
auto Update = [&](OBSHotkeyLabel *label, const QString &name,
|
||||
OBSHotkeyLabel *other, const QString &otherName)
|
||||
{
|
||||
label->setToolTip(tt.arg(otherName));
|
||||
label->setText(name + " ✳");
|
||||
label->pairPartner = other;
|
||||
};
|
||||
Update(label1, name1, label2, name2);
|
||||
Update(label2, name2, label1, name1);
|
||||
}
|
||||
|
||||
AddHotkeys(*layout, obs_output_get_name, outputs);
|
||||
AddHotkeys(*layout, obs_source_get_name, scenes);
|
||||
AddHotkeys(*layout, obs_source_get_name, sources);
|
||||
AddHotkeys(*layout, obs_encoder_get_name, encoders);
|
||||
AddHotkeys(*layout, obs_service_get_name, services);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::LoadSettings(bool changedOnly)
|
||||
{
|
||||
if (!changedOnly || generalChanged)
|
||||
|
@ -1288,6 +1744,8 @@ void OBSBasicSettings::LoadSettings(bool changedOnly)
|
|||
LoadAudioSettings();
|
||||
if (!changedOnly || videoChanged)
|
||||
LoadVideoSettings();
|
||||
if (!changedOnly || hotkeysChanged)
|
||||
LoadHotkeySettings();
|
||||
if (!changedOnly || advancedChanged)
|
||||
LoadAdvancedSettings();
|
||||
}
|
||||
|
@ -1317,8 +1775,14 @@ void OBSBasicSettings::SaveStream1Settings()
|
|||
{
|
||||
QString streamType = GetComboData(ui->streamType);
|
||||
|
||||
obs_service_t *oldService = main->GetService();
|
||||
obs_data_t *hotkeyData = obs_hotkeys_save_service(oldService);
|
||||
|
||||
obs_service_t *newService = obs_service_create(QT_TO_UTF8(streamType),
|
||||
"default_service", streamProperties->GetSettings());
|
||||
"default_service", streamProperties->GetSettings(),
|
||||
hotkeyData);
|
||||
|
||||
obs_data_release(hotkeyData);
|
||||
if (!newService)
|
||||
return;
|
||||
|
||||
|
@ -1549,9 +2013,53 @@ void OBSBasicSettings::SaveAudioSettings()
|
|||
SaveComboData(ui->auxAudioDevice2, "Audio", "AuxDevice2");
|
||||
SaveComboData(ui->auxAudioDevice3, "Audio", "AuxDevice3");
|
||||
|
||||
for (auto &audioSource : audioSources) {
|
||||
auto source = OBSGetStrongRef(get<0>(audioSource));
|
||||
if (!source)
|
||||
continue;
|
||||
|
||||
auto &ptmCB = get<1>(audioSource);
|
||||
auto &ptmSB = get<2>(audioSource);
|
||||
auto &pttCB = get<3>(audioSource);
|
||||
auto &pttSB = get<4>(audioSource);
|
||||
|
||||
obs_source_enable_push_to_mute(source, ptmCB->isChecked());
|
||||
obs_source_set_push_to_mute_delay(source, ptmSB->value());
|
||||
|
||||
obs_source_enable_push_to_talk(source, pttCB->isChecked());
|
||||
obs_source_set_push_to_talk_delay(source, pttSB->value());
|
||||
}
|
||||
|
||||
main->ResetAudioDevices();
|
||||
}
|
||||
|
||||
void OBSBasicSettings::SaveHotkeySettings()
|
||||
{
|
||||
const auto &config = main->Config();
|
||||
|
||||
using namespace std;
|
||||
|
||||
std::vector<obs_key_combination> combinations;
|
||||
for (auto &hotkey : hotkeys) {
|
||||
auto &hw = *hotkey.second;
|
||||
if (!hw.Changed())
|
||||
continue;
|
||||
|
||||
hw.Save(combinations);
|
||||
|
||||
if (!hotkey.first)
|
||||
continue;
|
||||
|
||||
obs_data_array_t *array = obs_hotkey_save(hw.id);
|
||||
obs_data_t *data = obs_data_create();
|
||||
obs_data_set_array(data, "bindings", array);
|
||||
const char *json = obs_data_get_json(data);
|
||||
config_set_string(config, "Hotkeys", hw.name.c_str(), json);
|
||||
obs_data_release(data);
|
||||
obs_data_array_release(array);
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasicSettings::SaveSettings()
|
||||
{
|
||||
if (generalChanged)
|
||||
|
@ -1564,6 +2072,8 @@ void OBSBasicSettings::SaveSettings()
|
|||
SaveAudioSettings();
|
||||
if (videoChanged)
|
||||
SaveVideoSettings();
|
||||
if (hotkeysChanged)
|
||||
SaveHotkeySettings();
|
||||
if (advancedChanged)
|
||||
SaveAdvancedSettings();
|
||||
|
||||
|
@ -1890,6 +2400,11 @@ void OBSBasicSettings::AudioChangedRestart()
|
|||
}
|
||||
}
|
||||
|
||||
void OBSBasicSettings::ReloadAudioSources()
|
||||
{
|
||||
LoadAudioSources();
|
||||
}
|
||||
|
||||
void OBSBasicSettings::VideoChangedRestart()
|
||||
{
|
||||
if (!loading) {
|
||||
|
@ -1929,6 +2444,28 @@ void OBSBasicSettings::VideoChanged()
|
|||
}
|
||||
}
|
||||
|
||||
void OBSBasicSettings::HotkeysChanged()
|
||||
{
|
||||
using namespace std;
|
||||
if (loading)
|
||||
return;
|
||||
|
||||
hotkeysChanged = any_of(begin(hotkeys), end(hotkeys),
|
||||
[](const pair<bool, QPointer<OBSHotkeyWidget>> &hotkey)
|
||||
{
|
||||
const auto &hw = *hotkey.second;
|
||||
return hw.Changed();
|
||||
});
|
||||
|
||||
if (hotkeysChanged)
|
||||
EnableApplyButton(true);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::ReloadHotkeys(obs_hotkey_id ignoreKey)
|
||||
{
|
||||
LoadHotkeySettings(ignoreKey);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::AdvancedChanged()
|
||||
{
|
||||
if (!loading) {
|
||||
|
|
|
@ -31,9 +31,34 @@ class OBSBasic;
|
|||
class QAbstractButton;
|
||||
class QComboBox;
|
||||
class OBSPropertiesView;
|
||||
class OBSHotkeyWidget;
|
||||
|
||||
#include "ui_OBSBasicSettings.h"
|
||||
|
||||
class SilentUpdateCheckBox : public QCheckBox {
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
void setCheckedSilently(bool checked)
|
||||
{
|
||||
bool blocked = blockSignals(true);
|
||||
setChecked(checked);
|
||||
blockSignals(blocked);
|
||||
}
|
||||
};
|
||||
|
||||
class SilentUpdateSpinBox : public QSpinBox {
|
||||
Q_OBJECT
|
||||
|
||||
public slots:
|
||||
void setValueSilently(int val)
|
||||
{
|
||||
bool blocked = blockSignals(true);
|
||||
setValue(val);
|
||||
blockSignals(blocked);
|
||||
}
|
||||
};
|
||||
|
||||
class OBSFFDeleter
|
||||
{
|
||||
public:
|
||||
|
@ -58,11 +83,13 @@ private:
|
|||
OBSBasic *main;
|
||||
|
||||
std::unique_ptr<Ui::OBSBasicSettings> ui;
|
||||
|
||||
bool generalChanged = false;
|
||||
bool stream1Changed = false;
|
||||
bool outputsChanged = false;
|
||||
bool audioChanged = false;
|
||||
bool videoChanged = false;
|
||||
bool hotkeysChanged = false;
|
||||
bool advancedChanged = false;
|
||||
int pageIndex = 0;
|
||||
bool loading = true;
|
||||
|
@ -74,6 +101,19 @@ private:
|
|||
OBSPropertiesView *streamEncoderProps = nullptr;
|
||||
OBSPropertiesView *recordEncoderProps = nullptr;
|
||||
|
||||
using AudioSource_t =
|
||||
std::tuple<OBSWeakSource,
|
||||
QPointer<QCheckBox>, QPointer<QSpinBox>,
|
||||
QPointer<QCheckBox>, QPointer<QSpinBox>>;
|
||||
std::vector<AudioSource_t> audioSources;
|
||||
std::vector<OBSSignal> audioSourceSignals;
|
||||
OBSSignal sourceCreated;
|
||||
OBSSignal channelChanged;
|
||||
|
||||
std::vector<std::pair<bool, QPointer<OBSHotkeyWidget>>> hotkeys;
|
||||
OBSSignal hotkeyRegistered;
|
||||
OBSSignal hotkeyUnregistered;
|
||||
|
||||
void SaveCombo(QComboBox *widget, const char *section,
|
||||
const char *value);
|
||||
void SaveComboData(QComboBox *widget, const char *section,
|
||||
|
@ -91,7 +131,8 @@ private:
|
|||
inline bool Changed() const
|
||||
{
|
||||
return generalChanged || outputsChanged || stream1Changed ||
|
||||
audioChanged || videoChanged || advancedChanged;
|
||||
audioChanged || videoChanged || advancedChanged ||
|
||||
hotkeysChanged;
|
||||
}
|
||||
|
||||
inline void EnableApplyButton(bool en)
|
||||
|
@ -106,6 +147,7 @@ private:
|
|||
outputsChanged = false;
|
||||
audioChanged = false;
|
||||
videoChanged = false;
|
||||
hotkeysChanged = false;
|
||||
advancedChanged= false;
|
||||
EnableApplyButton(false);
|
||||
}
|
||||
|
@ -125,6 +167,7 @@ private:
|
|||
void LoadOutputSettings();
|
||||
void LoadAudioSettings();
|
||||
void LoadVideoSettings();
|
||||
void LoadHotkeySettings(obs_hotkey_id ignoreKey=OBS_INVALID_HOTKEY_ID);
|
||||
void LoadAdvancedSettings();
|
||||
void LoadSettings(bool changedOnly);
|
||||
|
||||
|
@ -151,6 +194,7 @@ private:
|
|||
void LoadListValues(QComboBox *widget, obs_property_t *prop,
|
||||
const char *configName);
|
||||
void LoadAudioDevices();
|
||||
void LoadAudioSources();
|
||||
|
||||
/* video */
|
||||
void LoadRendererList();
|
||||
|
@ -165,6 +209,7 @@ private:
|
|||
void SaveOutputSettings();
|
||||
void SaveAudioSettings();
|
||||
void SaveVideoSettings();
|
||||
void SaveHotkeySettings();
|
||||
void SaveAdvancedSettings();
|
||||
void SaveSettings();
|
||||
|
||||
|
@ -194,11 +239,14 @@ private slots:
|
|||
void GeneralChanged();
|
||||
void AudioChanged();
|
||||
void AudioChangedRestart();
|
||||
void ReloadAudioSources();
|
||||
void OutputsChanged();
|
||||
void Stream1Changed();
|
||||
void VideoChanged();
|
||||
void VideoChangedResolution();
|
||||
void VideoChangedRestart();
|
||||
void HotkeysChanged();
|
||||
void ReloadHotkeys(obs_hotkey_id ignoreKey=OBS_INVALID_HOTKEY_ID);
|
||||
void AdvancedChanged();
|
||||
void AdvancedChangedRestart();
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ bool AddNew(QWidget *parent, const char *id, const char *name)
|
|||
|
||||
} else {
|
||||
source = obs_source_create(OBS_SOURCE_TYPE_INPUT,
|
||||
id, name, NULL);
|
||||
id, name, NULL, nullptr);
|
||||
|
||||
if (source) {
|
||||
obs_add_source(source);
|
||||
|
@ -181,5 +181,7 @@ OBSBasicSourceSelect::OBSBasicSourceSelect(OBSBasic *parent, const char *id_)
|
|||
ui->sourceName->setFocus(); //Fixes deselect of text.
|
||||
ui->sourceName->selectAll();
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
obs_enum_sources(EnumSources, this);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ OBSBasicTransform::OBSBasicTransform(OBSBasic *parent)
|
|||
HookWidget(ui->boundsWidth, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->boundsHeight, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
OBSScene curScene = main->GetCurrentScene();
|
||||
SetScene(curScene);
|
||||
SetItem(FindASelectedItem(curScene));
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <QClipboard>
|
||||
#include "window-log-reply.hpp"
|
||||
#include "obs-app.hpp"
|
||||
|
||||
OBSLogReply::OBSLogReply(QWidget *parent, const QString &url)
|
||||
: QDialog (parent),
|
||||
|
@ -24,6 +25,8 @@ OBSLogReply::OBSLogReply(QWidget *parent, const QString &url)
|
|||
{
|
||||
ui->setupUi(this);
|
||||
ui->urlEdit->setText(url);
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
}
|
||||
|
||||
void OBSLogReply::on_copyURL_clicked()
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "window-namedialog.hpp"
|
||||
#include "ui_NameDialog.h"
|
||||
#include "obs-app.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -25,6 +26,8 @@ NameDialog::NameDialog(QWidget *parent)
|
|||
ui (new Ui::NameDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
}
|
||||
|
||||
bool NameDialog::AskForName(QWidget *parent, const QString &title,
|
||||
|
|
|
@ -15,6 +15,8 @@ OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_)
|
|||
"removed", OBSSourceRemoved, this)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
}
|
||||
|
||||
OBSProjector::~OBSProjector()
|
||||
|
|
|
@ -47,7 +47,9 @@ OBSRemux::OBSRemux(const char *path, QWidget *parent)
|
|||
ui->progressBar->setMinimum(0);
|
||||
ui->progressBar->setMaximum(1000);
|
||||
ui->progressBar->setValue(0);
|
||||
|
||||
|
||||
installEventFilter(CreateShortcutFilter());
|
||||
|
||||
connect(ui->browseSource, &QPushButton::clicked,
|
||||
[&]() { BrowseInput(); });
|
||||
connect(ui->browseTarget, &QPushButton::clicked,
|
||||
|
|
|
@ -68,7 +68,7 @@ static SceneContext SetupScene()
|
|||
/* ------------------------------------------------------ */
|
||||
/* create source */
|
||||
SourceContext source{obs_source_create(OBS_SOURCE_TYPE_INPUT,
|
||||
"random", "a test source", nullptr)};
|
||||
"random", "a test source", nullptr, nullptr)};
|
||||
if (!source)
|
||||
throw "Couldn't create random test source";
|
||||
|
||||
|
|
|
@ -158,14 +158,15 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine,
|
|||
/* ------------------------------------------------------ */
|
||||
/* create source */
|
||||
SourceContext source = obs_source_create(OBS_SOURCE_TYPE_INPUT,
|
||||
"random", "some randon source", NULL);
|
||||
"random", "some randon source", NULL, nullptr);
|
||||
if (!source)
|
||||
throw "Couldn't create random test source";
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
/* create filter */
|
||||
SourceContext filter = obs_source_create(OBS_SOURCE_TYPE_FILTER,
|
||||
"test_filter", "a nice green filter", NULL);
|
||||
"test_filter", "a nice green filter", NULL,
|
||||
nullptr);
|
||||
if (!filter)
|
||||
throw "Couldn't create test filter";
|
||||
obs_source_filter_add(source, filter);
|
||||
|
|
Loading…
Reference in New Issue