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; + } +}