From dad8942122b6f926b691a704f5b8840e674f01ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= Date: Thu, 23 Sep 2021 12:36:07 +0200 Subject: [PATCH] Adds Gamepad API. Gamepad API in libwpe is middleware between WPEWebKit and the application, such as cog. The application is reponsible to provide the gamepad backend by offering the functions for providers and gamepads. WPEWebkit shall provide event callbacks. Original patch by Eugene Mutavchi --- CMakeLists.txt | 2 + include/wpe/gamepad.h | 394 ++++++++++++++++++++++++++++++++++++++++ include/wpe/meson.build | 1 + include/wpe/wpe.h | 1 + meson.build | 1 + src/gamepad.c | 184 +++++++++++++++++++ 6 files changed, 583 insertions(+) create mode 100644 include/wpe/gamepad.h create mode 100644 src/gamepad.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 388e5a7c..ac6d86da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,7 @@ set(WPE_PUBLIC_HEADERS include/wpe/version.h include/wpe/version-deprecated.h include/wpe/export.h + include/wpe/gamepad.h include/wpe/input.h include/wpe/input-xkb.h include/wpe/keysyms.h @@ -85,6 +86,7 @@ add_library( src/renderer-host.c src/version.c src/view-backend.c + src/gamepad.c ) if (BUILD_SHARED_LIBS) diff --git a/include/wpe/gamepad.h b/include/wpe/gamepad.h new file mode 100644 index 00000000..fca04f1d --- /dev/null +++ b/include/wpe/gamepad.h @@ -0,0 +1,394 @@ +/* + * If not stated otherwise in this file or this component's Licenses.txt file the + * following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * Copyright 2022 Igalia, S.L. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if !defined(__WPE_H_INSIDE__) && !defined(WPE_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef wpe_gamepad_h +#define wpe_gamepad_h + +/** + * SECTION:gamepad + * @short_description: Gamepad + * @title: Gamepad + */ + +#if defined(WPE_COMPILATION) +#include +#endif + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * wpe_gamepad_axis: + * @WPE_GAMEPAD_AXIS_LEFT_STICK_X: Horizontal axis for left stick (negative left/positive right). + * @WPE_GAMEPAD_AXIS_LEFT_STICK_Y: Vertical axis for left stick (negative up/positive down). + * @WPE_GAMEPAD_AXIS_RIGHT_STICK_X: Horizontal axis for right stick (negative left/positive right). + * @WPE_GAMEPAD_AXIS_RIGHT_STICK_Y: Vertical axis for right stick (negative up/positive down). + * @WPE_GAMEPAD_AXIS_COUNT: max number of axis. + * + * Standard mapping. + * Refer https://www.w3.org/TR/gamepad/#gamepadbutton-interface + */ +enum wpe_gamepad_axis { + WPE_GAMEPAD_AXIS_LEFT_STICK_X, + WPE_GAMEPAD_AXIS_LEFT_STICK_Y, + WPE_GAMEPAD_AXIS_RIGHT_STICK_X, + WPE_GAMEPAD_AXIS_RIGHT_STICK_Y, + WPE_GAMEPAD_AXIS_COUNT, +}; + +/** + * wpe_gamepad_button: + * @WPE_GAMEPAD_BUTTON_BOTTOM: Bottom button in right cluster. + * @WPE_GAMEPAD_BUTTON_RIGHT: Right button in right cluster. + * @WPE_GAMEPAD_BUTTON_LEFT: Left button in right cluster. + * @WPE_GAMEPAD_BUTTON_TOP: Top button in right cluster. + * @WPE_GAMEPAD_BUTTON_LEFT_SHOULDER: Top left front button. + * @WPE_GAMEPAD_BUTTON_RIGHT_SHOULDER: Top right front button. + * @WPE_GAMEPAD_BUTTON_LEFT_TRIGGER: Bottom left front button. + * @WPE_GAMEPAD_BUTTON_RIGHT_TRIGGER: Bottom right front button. + * @WPE_GAMEPAD_BUTTON_SELECT: Left button in center cluster. + * @WPE_GAMEPAD_BUTTON_START: Right button in center cluster. + * @WPE_GAMEPAD_BUTTON_LEFT_STICK: Left stick pressed button. + * @WPE_GAMEPAD_BUTTON_RIGHT_STICK: Right stick pressed button. + * @WPE_GAMEPAD_BUTTON_D_PAD_TOP: Top button in left cluster. + * @WPE_GAMEPAD_BUTTON_D_PAD_BOTOM: Bottom button in left cluster + * @WPE_GAMEPAD_BUTTON_D_PAD_LEFT: Left button in left cluster. + * @WPE_GAMEPAD_BUTTON_D_PAD_RIGHT: Right button in left cluster. + * @WPE_GAMEPAD_BUTTON_CENTER: Center button in center cluster. + * @WPE_GAMEPAD_BUTTON_COUNT: Max number of buttons. + * + * Standard mapping. + * Refer https://www.w3.org/TR/gamepad/#gamepadbutton-interface + */ +enum wpe_gamepad_button { + WPE_GAMEPAD_BUTTON_BOTTOM, + WPE_GAMEPAD_BUTTON_RIGHT, + WPE_GAMEPAD_BUTTON_LEFT, + WPE_GAMEPAD_BUTTON_TOP, + WPE_GAMEPAD_BUTTON_LEFT_SHOULDER, + WPE_GAMEPAD_BUTTON_RIGHT_SHOULDER, + WPE_GAMEPAD_BUTTON_LEFT_TRIGGER, + WPE_GAMEPAD_BUTTON_RIGHT_TRIGGER, + WPE_GAMEPAD_BUTTON_SELECT, + WPE_GAMEPAD_BUTTON_START, + WPE_GAMEPAD_BUTTON_LEFT_STICK, + WPE_GAMEPAD_BUTTON_RIGHT_STICK, + WPE_GAMEPAD_BUTTON_D_PAD_TOP, + WPE_GAMEPAD_BUTTON_D_PAD_BOTTOM, + WPE_GAMEPAD_BUTTON_D_PAD_LEFT, + WPE_GAMEPAD_BUTTON_D_PAD_RIGHT, + WPE_GAMEPAD_BUTTON_CENTER, + WPE_GAMEPAD_BUTTON_COUNT, +}; + +struct wpe_gamepad; +struct wpe_gamepad_provider; + +/** + * wpe_gamepad_provider_client_interface: + * @connected: Callback to inform WPEWebKit that a new gamepad device is plugged. + * @disconnected: Callback to inform WPEWebKit that a new gamepad device is gone. + * + * This interface is defines gamepad provider callbacks to notify WPEWebKit of devices. + * + * Since: 1.14 + */ +struct wpe_gamepad_provider_client_interface { + void (*connected)(void*, unsigned); + void (*disconnected)(void*, unsigned); + + /*< private >*/ + void (*_wpe_reserved1)(void); + void (*_wpe_reserved2)(void); + void (*_wpe_reserved3)(void); +}; + +/** + * wpe_gamepad_client_interface: + * @button_changed: Callback to inform WPEWebkit a change in the status of a button. + * @axis_changed: Callback to inform WPEWebkit a change in the status of an axis. + * + * This interface is defines gamepad callbacks to notify WPEWebKit of events. + * + * Since: 1.14 + */ +struct wpe_gamepad_client_interface { + void (*button_changed)(void*, enum wpe_gamepad_button, bool); + void (*axis_changed)(void*, enum wpe_gamepad_axis, double); + + /*< private >*/ + void (*_wpe_reserved1)(void); + void (*_wpe_reserved2)(void); + void (*_wpe_reserved3)(void); +}; + +/** + * wpe_gamepad_provider_interface: + * @create: create an internal representation of a gamepad provider. + * @destroy: destroy instance gamepad provider. + * @start: gamepad device should start monitoring for gamepad devices. + * @stop: gamepad device should stop monitoring for gamepad devices. + * @get_view_backend: request the view backend where gamepad device is attached. + * + * Methods called by WebKit requesting gamepad provider operations to implementator. + * + * Since: 1.14 + */ +struct wpe_gamepad_provider_interface { + void* (*create)(struct wpe_gamepad_provider*); + void (*destroy)(void*); + void (*start)(void*); + void (*stop)(void*); + struct wpe_view_backend* (*get_view_backend)(void*, void*); + + /*< private >*/ + void (*_wpe_reserved1)(void); + void (*_wpe_reserved2)(void); + void (*_wpe_reserved3)(void); +}; + +/** + * wpe_gamepad_provider_interface: + * @create: creates a gamepad device. + * @destroy: destroy a gamepad device. + * @get_id: Gets the gamepad's id string. + * + * Methods called by WebKit requesting gamepad device operations to implementator. + * + * Since: 1.14 + */ +struct wpe_gamepad_interface { + void* (*create)(struct wpe_gamepad*, unsigned); + void (*destroy)(void*); + const char* (*get_id)(void*); + + /*< private >*/ + void (*_wpe_reserved1)(void); + void (*_wpe_reserved2)(void); + void (*_wpe_reserved3)(void); +}; + +/** + * wpe_gamepad_provider_create: + * + * This method is called by WPEWebKit. + * + * Returns: an opaque object representing the gamepad provider in libwpe. + * + * Since: 1.14 + */ +WPE_EXPORT +struct wpe_gamepad_provider* wpe_gamepad_provider_create(void); + +/** + * wpe_gamepad_provider_destroy: + * @provider: opaque libwpe's representation of gamepad provider. + * + * Frees the internal resources used by @provider. + * + * This method is called by WPEWebKit. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_provider_destroy(struct wpe_gamepad_provider*); + +/** + * wpe_gamepad_provider_set_client: + * @provider: opaque libwpe's representation of gamepad provider. + * @client_interface: WPEWebKit callbacks for gamepad devices appearance. + * @client_data: WPEWebkit closure data. + * + * Sets WPEWebKit callbacks in @provider. + * + * Since: 1.14 + */ +WPE_EXPORT +void +wpe_gamepad_provider_set_client(struct wpe_gamepad_provider*, struct wpe_gamepad_provider_client_interface*, void*); + +/** + * wpe_gamepad_provider_start: + * @provider: opaque libwpe's representation of gamepad provider. + * + * Called by WPEWebkit to start @provider monitoring for gamepad + * devices. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_provider_start(struct wpe_gamepad_provider*); + +/** + * wpe_gamepad_provider_stop: + * @provider: opaque libwpe's representation of gamepad provider. + * + * Called by WPEWebkit to stop @provider monitoring for gamepad + * devices. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_provider_stop(struct wpe_gamepad_provider*); + +/** + * wpe_gampepad_provider_get_view_backend: + * @provider: opaque libwpe's representation of gamepad provider. + * @gamepad: opaque libwep's representation of gampead + * + * Ask @provider for the view to where @gamepad is attached. + * + * Since: 1.14 + */ +WPE_EXPORT +struct wpe_view_backend* wpe_gamepad_provider_get_view_backend(struct wpe_gamepad_provider*, struct wpe_gamepad*); + +/** + * wpe_gamepad_provider_dispatch_gamepad_connected: + * @provider: opaque libwpe's representation of gamepad provider. + * @gamepad_id: application's gamepad device identifier. + * + * Method called by application (gamepad implementator) to inform + * WPEWebKit that a new gamepad device is plugged. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_provider_dispatch_gamepad_connected(struct wpe_gamepad_provider*, unsigned); + +/** + * wpe_gamepad_provider_dispatch_gamepad_disconnected: + * @provider: opaque libwpe's representation of gamepad provider. + * @gamepad_id: application's gamepad device identifier. + * + * Method called by application (gamepad implementator) to inform + * WPEWebKit that a plugged gamepad device has been unplugged. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_provider_dispatch_gamepad_disconnected(struct wpe_gamepad_provider*, unsigned); + +/** + * wpe_gamepad_create: + * @gamepad_id: opaque application's representation of gamepad provider. + * + * Method called by WPEWebKit to create an internal representation of a gamepad device. + * + * Returns: opaque libwpe's representation of a gamepad device. + * + * Since: 1.14 + */ +WPE_EXPORT +struct wpe_gamepad* wpe_gamepad_create(unsigned); + +/** + * wpe_gamepad_destroy: + * @gamepad: opaque libwpe's representation of gamepad. + * + * Called by WPEWebkit to free the internal resources used by @gamepad + * object. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_destroy(struct wpe_gamepad*); + +/** + * wpe_gamepad_provider_set_client: + * @gamepad: opaque libwpe's representation of gamepad. + * @client_interface: WPEWebKit callbacks for gamepad devices events. + * @client_data: WPEWebkit closure data. + * + * Sets WPEWebKit's callbacks for events in @gamepad. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_set_client(struct wpe_gamepad*, struct wpe_gamepad_client_interface*, void*); + +/** + * wpe_gamepad_get_id: + * @gamepad: opaque libwpe's representation of gamepad. + * + * Gets the identification string for the @gamepad. + * + * Since: 1.14 + */ +WPE_EXPORT +const char* wpe_gamepad_get_id(struct wpe_gamepad*); + +/** + * wpe_gamepad_dispatch_button_changed: + * @gamepad: opaque gamepad object. + * @button: the standard button that changed its state. + * @pressed: the new state: %TRUE pressed, otherwise released. + * + * Method called by application (gamepad implementator). It reports to + * WPEWebkit a change in the status of @button. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_dispatch_button_changed(struct wpe_gamepad*, enum wpe_gamepad_button, bool); + +/** + * wpe_gamepad_dispatch_axis_changed: + * @gamepad: opaque gamepad object. + * @axis: the standard axis that changed its state. + * @value: the value of @axis + * + * Method called by application (gamepad implementator). It reports to + * WPEWebkit a change in the position of @axis. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_dispatch_axis_changed(struct wpe_gamepad*, enum wpe_gamepad_axis, double); + +/** + * wpe_gamepad_set_handler: + * @provider_iface: (transfer none): Application callbacks for gamepad provider. + * @gamepad_iface: (transfer none): Applications callbacks for gamepad device. + * + * Method called by the application (gamepad implementator) to + * register, in libwpe, the callbacks for gamepad devices and gamepad + * provider. + * + * Note that the last registered handlers will be used. + * + * Since: 1.14 + */ +WPE_EXPORT +void wpe_gamepad_set_handler(struct wpe_gamepad_provider_interface*, struct wpe_gamepad_interface*); + +#ifdef __cplusplus +} +#endif + +#endif /* wpe_gamepad_h */ diff --git a/include/wpe/meson.build b/include/wpe/meson.build index e1d4084b..185619d3 100644 --- a/include/wpe/meson.build +++ b/include/wpe/meson.build @@ -1,5 +1,6 @@ api_headers = [ 'export.h', + 'gamepad.h', 'input.h', 'input-xkb.h', 'keysyms.h', diff --git a/include/wpe/wpe.h b/include/wpe/wpe.h index 4b36844f..f266a425 100644 --- a/include/wpe/wpe.h +++ b/include/wpe/wpe.h @@ -34,6 +34,7 @@ #define __WPE_H_INSIDE__ #include "export.h" +#include "gamepad.h" #include "input-xkb.h" #include "input.h" #include "keysyms.h" diff --git a/meson.build b/meson.build index 61d6fba4..c87c04a2 100644 --- a/meson.build +++ b/meson.build @@ -81,6 +81,7 @@ if pkg_cflags.length() > 0 endif libwpe = library('wpe-' + api_version, + 'src/gamepad.c', 'src/input-xkb.c', 'src/key-unicode.c', 'src/pasteboard.c', diff --git a/src/gamepad.c b/src/gamepad.c new file mode 100644 index 00000000..a227b379 --- /dev/null +++ b/src/gamepad.c @@ -0,0 +1,184 @@ +/* + * If not stated otherwise in this file or this component's Licenses.txt file the + * following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * Copyright 2022 Igalia, S.L. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../include/wpe/gamepad.h" + +#include +#include + +struct wpe_gamepad_provider { + void* backend; + const struct wpe_gamepad_provider_client_interface* client_interface; + void* client_data; +}; + +struct wpe_gamepad { + void* backend; + const struct wpe_gamepad_client_interface* client_interface; + void* client_data; +}; + +static struct wpe_gamepad_provider_interface* provider_interface = NULL; +static struct wpe_gamepad_interface* gamepad_interface = NULL; + +struct wpe_gamepad_provider* +wpe_gamepad_provider_create(void) +{ + if (!provider_interface) + return NULL; + + struct wpe_gamepad_provider* provider = calloc(1, sizeof(struct wpe_gamepad_provider)); + if (!provider) + return NULL; + + if (provider_interface->create) + provider->backend = provider_interface->create(provider); + return provider; +} + +void +wpe_gamepad_provider_destroy(struct wpe_gamepad_provider* provider) +{ + if (!provider) + return; + + if (provider_interface && provider_interface->destroy) + provider_interface->destroy(provider->backend); + provider->backend = NULL; + free(provider); +} + +void +wpe_gamepad_provider_set_client(struct wpe_gamepad_provider* provider, + struct wpe_gamepad_provider_client_interface* client_interface, + void* client_data) +{ + if (!provider) + return; + + provider->client_interface = client_interface; + provider->client_data = client_data; +} + +void +wpe_gamepad_provider_start(struct wpe_gamepad_provider* provider) +{ + if (provider && provider_interface && provider_interface->start) + provider_interface->start(provider->backend); +} + +void +wpe_gamepad_provider_stop(struct wpe_gamepad_provider* provider) +{ + if (provider && provider_interface && provider_interface->stop) + provider_interface->stop(provider->backend); +} + +struct wpe_view_backend* +wpe_gamepad_provider_get_view_backend(struct wpe_gamepad_provider* provider, struct wpe_gamepad* gamepad) +{ + if (provider && provider_interface && provider_interface->get_view_backend && gamepad) + return provider_interface->get_view_backend(provider->backend, gamepad->backend); + return NULL; +} + +void +wpe_gamepad_provider_dispatch_gamepad_connected(struct wpe_gamepad_provider* provider, unsigned gamepad_id) +{ + if (provider && provider->client_interface && provider->client_interface->connected) + provider->client_interface->connected(provider->client_data, gamepad_id); +} + +void +wpe_gamepad_provider_dispatch_gamepad_disconnected(struct wpe_gamepad_provider* provider, unsigned gamepad_id) +{ + if (provider && provider->client_interface && provider->client_interface->disconnected) + provider->client_interface->disconnected(provider->client_data, gamepad_id); +} + +struct wpe_gamepad* +wpe_gamepad_create(unsigned gamepad_id) +{ + if (!gamepad_interface) + return NULL; + + struct wpe_gamepad* gamepad = calloc(1, sizeof(struct wpe_gamepad)); + if (!gamepad) + return NULL; + + if (gamepad_interface->create) + gamepad->backend = gamepad_interface->create(gamepad, gamepad_id); + return gamepad; +} + +void +wpe_gamepad_destroy(struct wpe_gamepad* gamepad) +{ + if (!gamepad) + return; + + if (gamepad_interface && gamepad_interface->destroy) + gamepad_interface->destroy(gamepad->backend); + gamepad->backend = NULL; + free(gamepad); +} + +void +wpe_gamepad_set_client(struct wpe_gamepad* gamepad, + struct wpe_gamepad_client_interface* client_interface, + void* client_data) +{ + if (gamepad) { + gamepad->client_interface = client_interface; + gamepad->client_data = client_data; + } +} + +const char* +wpe_gamepad_get_id(struct wpe_gamepad* gamepad) +{ + if (gamepad && gamepad_interface && gamepad_interface->get_id) + return gamepad_interface->get_id(gamepad->backend); + return "Unknown device"; +} + +void +wpe_gamepad_dispatch_button_changed(struct wpe_gamepad* gamepad, enum wpe_gamepad_button button, bool pressed) +{ + if (gamepad && gamepad->client_interface && gamepad->client_interface->button_changed) + gamepad->client_interface->button_changed(gamepad->client_data, button, pressed); +} + +void +wpe_gamepad_dispatch_axis_changed(struct wpe_gamepad* gamepad, enum wpe_gamepad_axis axis, double value) +{ + if (gamepad && gamepad->client_interface && gamepad->client_interface->axis_changed) + gamepad->client_interface->axis_changed(gamepad->client_data, axis, value); +} + +void +wpe_gamepad_set_handler(struct wpe_gamepad_provider_interface* provider_iface, + struct wpe_gamepad_interface* gamepad_iface) +{ + if (provider_iface && !provider_interface && gamepad_iface && !gamepad_interface) { + provider_interface = provider_iface; + gamepad_interface = gamepad_iface; + } +}