+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(capi-system-media-key CXX)
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
-SET(fw_name "capi-system-media-key")
-
-PROJECT(${fw_name})
-
-SET(CMAKE_INSTALL_PREFIX /usr)
-SET(PREFIX ${CMAKE_INSTALL_PREFIX})
-
-SET(INC_DIR include)
-INCLUDE_DIRECTORIES(${INC_DIR})
+INCLUDE(FindPkgConfig)
SET(requires "dlog capi-base-common ecore ecore-input evas ecore-wl2")
SET(pc_requires "capi-base-common")
-INCLUDE(FindPkgConfig)
-pkg_check_modules(${fw_name} REQUIRED ${requires})
-FOREACH(flag ${${fw_name}_CFLAGS})
- SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
-ENDFOREACH(flag)
-
-SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror")
-SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
-
-IF("${ARCH}" STREQUAL "arm")
- ADD_DEFINITIONS("-DTARGET")
-ENDIF("${ARCH}" STREQUAL "arm")
+PKG_CHECK_MODULES(capi-system-media-key REQUIRED ${requires})
-ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
-ADD_DEFINITIONS("-DSLP_DEBUG")
+FOREACH(flag ${capi-system-media-key_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -Wall -Werror -Winline")
-SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}")
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -std=c++11")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_CXX_FLAGS_RELEASE "-O2")
-aux_source_directory(src SOURCES)
-ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
-TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS})
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SOURCES)
+ADD_LIBRARY(${PROJECT_NAME} SHARED ${SOURCES})
-SET_TARGET_PROPERTIES(${fw_name}
- PROPERTIES
- VERSION ${FULLVER}
- SOVERSION ${MAJORVER}
- CLEAN_DIRECT_OUTPUT 1
-)
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${MAJORVER})
+SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${FULLVER})
-INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR})
-INSTALL(
- DIRECTORY ${INC_DIR}/ DESTINATION include/system
- FILES_MATCHING
- PATTERN "*_private.h" EXCLUDE
- PATTERN "${INC_DIR}/*.h"
- )
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${capi-system-media-key_LDFLAGS})
-SET(PC_NAME ${fw_name})
+SET(PC_NAME capi-system-media-key)
SET(PC_REQUIRED ${pc_requires})
-SET(PC_LDFLAGS -l${fw_name})
+SET(PC_LDFLAGS -lcapi-system-media-key)
SET(PC_CFLAGS -I\${includedir}/system)
-CONFIGURE_FILE(
- ${fw_name}.pc.in
- ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc
- @ONLY
-)
-INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
-
-IF(UNIX)
-
-ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution)
-ADD_CUSTOM_COMMAND(
- DEPENDS clean
- COMMENT "distribution clean"
- COMMAND find
- ARGS .
- -not -name config.cmake -and \(
- -name tester.c -or
- -name Testing -or
- -name CMakeFiles -or
- -name cmake.depends -or
- -name cmake.check_depends -or
- -name CMakeCache.txt -or
- -name cmake.check_cache -or
- -name *.cmake -or
- -name Makefile -or
- -name core -or
- -name core.* -or
- -name gmon.out -or
- -name install_manifest.txt -or
- -name *.pc -or
- -name *~ \)
- | grep -v TC | xargs rm -rf
- TARGET distclean
- VERBATIM
-)
-
-ENDIF(UNIX)
+CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY)
+SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.pc")
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
+ DESTINATION include/system
+ FILES_MATCHING PATTERN "*.h")
%endif
export CFLAGS+=" -DEFL_BETA_API_SUPPORT "
+export CXXFLAGS+=" -DEFL_BETA_API_SUPPORT "
MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
%cmake -DFULLVER=%{version} \
-DMAJORVER=${MAJORVER} \
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+#ifndef LOG_PRIVATE_H_
+#define LOG_PRIVATE_H_
+
+#include <dlog.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "CAPI_SYSTEM_MEDIA_KEY"
+
+#ifdef _E
+#undef _E
+#endif
+#define _E LOGE
+
+#ifdef _W
+#undef _W
+#endif
+#define _W LOGW
+
+#ifdef _I
+#undef _I
+#endif
+#define _I LOGI
+
+#ifdef _D
+#undef _D
+#endif
+#define _D LOGD
+
+#endif // LOG_PRIVATE_H_
+++ /dev/null
-/*
- * Copyright (c) 2011 - 2017 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * 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 <unistd.h>
-#include <string.h>
-
-#include <Evas.h>
-#include <Ecore.h>
-#include <Ecore_Input.h>
-#include <Ecore_Wl2.h>
-
-#include <dlog.h>
-
-#include "media_key.h"
-
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-
-#define LOG_TAG "CAPI_SYSTEM_MEDIA_KEY"
-
-struct key_map {
- char *key_str;
- media_key_e key;
-};
-
-struct key_map media_keys[] = {
- { "XF86AudioPlay", MEDIA_KEY_PLAY },
- { "XF86AudioStop", MEDIA_KEY_STOP },
- { "XF86AudioPause", MEDIA_KEY_PAUSE },
- { "XF86AudioNext", MEDIA_KEY_NEXT },
- { "XF86AudioPrev", MEDIA_KEY_PREVIOUS },
- { "XF86AudioRewind", MEDIA_KEY_REWIND },
- { "XF86AudioForward", MEDIA_KEY_FASTFORWARD },
- { "XF86AudioPlayPause", MEDIA_KEY_PLAYPAUSE },
- { "XF86AudioMedia", MEDIA_KEY_MEDIA },
- { NULL, MEDIA_KEY_UNKNOWN },
-};
-
-static media_key_event_cb _media_key_event_cb;
-static void *_media_key_data;
-static int _media_key_initialized;
-
-static Ecore_Event_Handler *_media_key_up;
-static Ecore_Event_Handler *_media_key_down;
-
-static int _media_key_init(void)
-{
- if (_media_key_initialized)
- return 0;
-
- ecore_wl2_init();
- if (!ecore_wl2_display_connect(NULL)) {
- LOGE("Failed to connect to wl2 display");
- ecore_wl2_shutdown();
- return -1;
- }
-
- _media_key_initialized = 1;
-
- return 0;
-}
-
-static void _media_key_handler(const char *key_str, media_key_e event)
-{
- int i;
- media_key_e key = MEDIA_KEY_UNKNOWN;
-
- for (i = 0; media_keys[i].key_str; i++) {
- if (!strcmp(key_str, media_keys[i].key_str)) {
- key = media_keys[i].key;
- break;
- }
- }
-
- if (_media_key_event_cb && key != MEDIA_KEY_UNKNOWN)
- _media_key_event_cb(key, event, _media_key_data);
-}
-
-static Eina_Bool _media_key_press_cb(void *data, int type, void *event)
-{
- Evas_Event_Key_Down *ev;
-
- ev = event;
- if (!ev) {
- LOGE("Invalid event object");
- return ECORE_CALLBACK_RENEW;
- }
-
- _media_key_handler(ev->keyname, MEDIA_KEY_STATUS_PRESSED);
-
- return ECORE_CALLBACK_RENEW;
-}
-
-static Eina_Bool _media_key_release_cb(void *data, int type, void *event)
-{
- Evas_Event_Key_Up *ev;
-
- ev = event;
- if (!ev) {
- LOGE("Invalid event object");
- return ECORE_CALLBACK_RENEW;
- }
-
- _media_key_handler(ev->keyname, MEDIA_KEY_STATUS_RELEASED);
-
- return ECORE_CALLBACK_RENEW;
-}
-
-static int _grab_media_key(void)
-{
- int i;
- Eina_Bool ret;
-
- for (i = 0; media_keys[i].key_str; i++) {
- ret = ecore_wl2_window_keygrab_set(NULL, media_keys[i].key_str,
- 0, 0, 0, ECORE_WL2_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE);
- if (ret != EINA_TRUE) {
- LOGE("failed to grab key: %s", media_keys[i].key_str);
- for (i = i - 1; i >= 0; i--)
- ecore_wl2_window_keygrab_unset(NULL, media_keys[i].key_str, 0, 0);
-
- return -1;
- }
- }
-
- return 0;
-}
-
-static int _ungrab_media_key(void)
-{
- int i;
- Eina_Bool ret;
-
- for (i = 0; media_keys[i].key_str; i++) {
- ret = ecore_wl2_window_keygrab_unset(NULL, media_keys[i].key_str, 0, 0);
- if (ret != EINA_TRUE)
- LOGE("failed to ungrab key: %s", media_keys[i].key_str);
- }
-
- return 0;
-}
-
-int media_key_reserve(media_key_event_cb callback, void *user_data)
-{
- int ret;
-
- LOGW("Reserve");
- if (callback == NULL) {
- LOGE("[%s] media_key_event_cb callback is NULL", __FUNCTION__);
- return MEDIA_KEY_ERROR_INVALID_PARAMETER;
- }
-
- if (!_media_key_initialized) {
- if (_media_key_init())
- return MEDIA_KEY_ERROR_OPERATION_FAILED;
- }
-
- _media_key_event_cb = callback;
- _media_key_data = user_data;
- if (_media_key_down) {
- LOGI("ecore event andler already added, just update callback");
- return MEDIA_KEY_ERROR_NONE;
- }
-
- ret = _grab_media_key();
- if (ret) {
- LOGE("reserve media key error [%d]", ret);
- return MEDIA_KEY_ERROR_OPERATION_FAILED;
- }
-
- _media_key_down = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, _media_key_press_cb, NULL);
- if (!_media_key_down)
- LOGE("failed to register key down event handler");
-
- _media_key_up = ecore_event_handler_add(ECORE_EVENT_KEY_UP, _media_key_release_cb, NULL);
- if (!_media_key_up)
- LOGE("failed to register key up event handler");
-
- return MEDIA_KEY_ERROR_NONE;
-}
-
-int media_key_release(void)
-{
- int ret;
-
- LOGW("Release");
- if (!_media_key_initialized) {
- LOGI("media key is not reserved");
- return MEDIA_KEY_ERROR_NONE;
- }
-
- if (_media_key_down) {
- ecore_event_handler_del(_media_key_down);
- _media_key_down = NULL;
- }
-
- if (_media_key_up) {
- ecore_event_handler_del(_media_key_up);
- _media_key_up = NULL;
- }
-
- ret = _ungrab_media_key();
- if (ret) {
- LOGE("release media key error [%d]", ret);
- return MEDIA_KEY_ERROR_OPERATION_FAILED;
- }
-
- _media_key_event_cb = NULL;
- _media_key_data = NULL;
-
- return MEDIA_KEY_ERROR_NONE;
-}
--- /dev/null
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <Ecore.h>
+#include <Ecore_Input.h>
+#include <Ecore_Wl2.h>
+#include <Evas.h>
+
+#include <map>
+#include <mutex>
+#include <string>
+#include <thread>
+
+#include "media_key.h"
+#include "log_private.hh"
+
+#ifdef EXPORT_API
+#undef EXPORT_API
+#endif
+#define EXPORT_API __attribute__((visibility("default")))
+
+namespace {
+
+class MediaKey {
+ private:
+ MediaKey() = default;
+ ~MediaKey() {
+ if (!disposed_)
+ Dispose();
+ }
+
+ public:
+ static MediaKey& GetInst() {
+ static MediaKey inst;
+
+ std::lock_guard<std::recursive_mutex> lock(inst.GetMutex());
+ if (inst.disposed_)
+ inst.Init();
+ return inst;
+ }
+
+ void Dispose() {
+ Fini();
+ }
+
+ int Reserve(media_key_event_cb cb, void* data) {
+ _W("Reserve");
+ std::lock_guard<std::recursive_mutex> lock(GetMutex());
+ cb_ = cb;
+ data_ = data;
+
+ int ret = MEDIA_KEY_ERROR_NONE;
+ if (!grabbed_)
+ ret = Grab();
+
+ return ret;
+ }
+
+ void Release() {
+ _W("Release");
+ std::lock_guard<std::recursive_mutex> lock(GetMutex());
+ if (grabbed_)
+ Ungrab();
+
+ cb_ = nullptr;
+ data_ = nullptr;
+ }
+
+ private:
+ void Init() {
+ key_map_ = {
+ { "XF86AudioPlay", MEDIA_KEY_PLAY },
+ { "XF86AudioStop", MEDIA_KEY_STOP },
+ { "XF86AudioPause", MEDIA_KEY_PAUSE },
+ { "XF86AudioNext", MEDIA_KEY_NEXT },
+ { "XF86AudioPrev", MEDIA_KEY_PREVIOUS },
+ { "XF86AudioRewind", MEDIA_KEY_REWIND },
+ { "XF86AudioForward", MEDIA_KEY_FASTFORWARD },
+ { "XF86AudioPlayPause", MEDIA_KEY_PLAYPAUSE },
+ { "XF86AudioMedia", MEDIA_KEY_MEDIA }
+ };
+
+ ecore_wl2_init();
+
+ if (!ecore_wl2_display_connect(NULL)) {
+ _E("Failed to connect to wl2 display");
+ ecore_wl2_shutdown();
+ return;
+ }
+
+ disposed_ = false;
+ }
+
+ void Fini() {
+ Ecore_Wl2_Display* dpy = ecore_wl2_connected_display_get(NULL);
+ if (dpy)
+ ecore_wl2_display_disconnect(dpy);
+
+ ecore_wl2_shutdown();
+ disposed_ = true;
+ }
+
+ int Grab() {
+ for (auto i = key_map_.begin(); i != key_map_.end(); i++) {
+ _D("key(%s)", i->first.c_str());
+ auto ret = ecore_wl2_window_keygrab_set(NULL, i->first.c_str(),
+ 0, 0, 0, ECORE_WL2_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE);
+ if (ret != EINA_TRUE) {
+ _E("Failed to grab key(%s)", i->first.c_str());
+ Ungrab();
+ return MEDIA_KEY_ERROR_OPERATION_FAILED;
+ }
+ }
+
+ key_down_handler_ = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
+ MediaKeyPressCb, this);
+ if (!key_down_handler_)
+ _E("Failed to register key down event handler");
+
+ key_up_handler_ = ecore_event_handler_add(ECORE_EVENT_KEY_UP,
+ MediaKeyReleaseCb, this);
+ if (!key_up_handler_)
+ _E("Failed to register key up event handler");
+
+ grabbed_ = true;
+ return 0;
+ }
+
+ void Ungrab() {
+ if (key_up_handler_) {
+ ecore_event_handler_del(key_up_handler_);
+ key_up_handler_ = nullptr;
+ }
+
+ if (key_down_handler_) {
+ ecore_event_handler_del(key_down_handler_);
+ key_down_handler_ = nullptr;
+ }
+
+ for (auto i = key_map_.rbegin(); i != key_map_.rend(); i++) {
+ _D("key(%s)", i->first.c_str());
+ auto ret = ecore_wl2_window_keygrab_unset(NULL, i->first.c_str(), 0, 0);
+ if (ret != EINA_TRUE)
+ _W("Failed to ungrab key(%s)", i->first.c_str());
+ }
+
+ grabbed_ = false;
+ }
+
+ std::recursive_mutex& GetMutex() const {
+ return mutex_;
+ }
+
+ static Eina_Bool MediaKeyPressCb(void* data, int type, void* event) {
+ Evas_Event_Key_Down* ev = static_cast<Evas_Event_Key_Down*>(event);
+ if (ev == nullptr) {
+ _E("Invalid parameter");
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ auto* handle = static_cast<MediaKey*>(data);
+ if (handle->cb_ == nullptr)
+ return ECORE_CALLBACK_RENEW;
+
+ media_key_e media_key = handle->key_map_[ev->keyname];
+ handle->cb_(media_key, MEDIA_KEY_STATUS_PRESSED, handle->data_);
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ static Eina_Bool MediaKeyReleaseCb(void* data, int type, void* event) {
+ Evas_Event_Key_Up* ev = static_cast<Evas_Event_Key_Up*>(event);
+ if (ev == nullptr) {
+ _E("Invalid parameter");
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ auto* handle = static_cast<MediaKey*>(data);
+ if (handle->cb_ == nullptr)
+ return ECORE_CALLBACK_RENEW;
+
+ media_key_e media_key = handle->key_map_[ev->keyname];
+ handle->cb_(media_key, MEDIA_KEY_STATUS_RELEASED, handle->data_);
+ return ECORE_CALLBACK_RENEW;
+ }
+
+ private:
+ bool disposed_ = true;
+ bool grabbed_ = false;
+ media_key_event_cb cb_ = nullptr;
+ void* data_ = nullptr;
+ Ecore_Event_Handler* key_up_handler_ = nullptr;
+ Ecore_Event_Handler* key_down_handler_ = nullptr;
+ std::map<std::string, media_key_e> key_map_;
+ mutable std::recursive_mutex mutex_;
+};
+
+} // namespace
+
+extern "C" EXPORT_API int media_key_reserve(media_key_event_cb callback,
+ void* user_data) {
+ if (callback == nullptr) {
+ _E("Invalid parameter");
+ return MEDIA_KEY_ERROR_INVALID_PARAMETER;
+ }
+
+ return ::MediaKey::GetInst().Reserve(callback, user_data);
+}
+
+extern "C" EXPORT_API int media_key_release(void) {
+ ::MediaKey::GetInst().Release();
+ return MEDIA_KEY_ERROR_NONE;
+}
+