Fix bugs about handling key events
[platform/core/api/media-key.git] / src / media_key.cc
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <Ecore.h>
18 #include <Ecore_Input.h>
19 #include <Ecore_Wl2.h>
20 #include <Evas.h>
21
22 #include <map>
23 #include <mutex>
24 #include <string>
25 #include <thread>
26
27 #include "media_key.h"
28 #include "log_private.hh"
29
30 #ifdef EXPORT_API
31 #undef EXPORT_API
32 #endif
33 #define EXPORT_API __attribute__((visibility("default")))
34
35 namespace {
36
37 class MediaKey {
38  private:
39   MediaKey() = default;
40   ~MediaKey() {
41     if (!disposed_)
42       Dispose();
43   }
44
45  public:
46   static MediaKey& GetInst() {
47     static MediaKey inst;
48
49     std::lock_guard<std::recursive_mutex> lock(inst.GetMutex());
50     if (inst.disposed_)
51       inst.Init();
52     return inst;
53   }
54
55   void Dispose() {
56     Fini();
57   }
58
59   int Reserve(media_key_event_cb cb, void* data) {
60     _W("Reserve");
61     std::lock_guard<std::recursive_mutex> lock(GetMutex());
62     cb_ = cb;
63     data_ = data;
64
65     int ret = MEDIA_KEY_ERROR_NONE;
66     if (!grabbed_)
67       ret = Grab();
68
69     return ret;
70   }
71
72   void Release() {
73     _W("Release");
74     std::lock_guard<std::recursive_mutex> lock(GetMutex());
75     if (grabbed_)
76       Ungrab();
77
78     cb_ = nullptr;
79     data_ = nullptr;
80   }
81
82  private:
83   void Init() {
84     key_map_ = {
85       { "XF86AudioPlay", MEDIA_KEY_PLAY },
86       { "XF86AudioStop", MEDIA_KEY_STOP },
87       { "XF86AudioPause", MEDIA_KEY_PAUSE },
88       { "XF86AudioNext", MEDIA_KEY_NEXT },
89       { "XF86AudioPrev", MEDIA_KEY_PREVIOUS },
90       { "XF86AudioRewind", MEDIA_KEY_REWIND },
91       { "XF86AudioForward", MEDIA_KEY_FASTFORWARD },
92       { "XF86AudioPlayPause", MEDIA_KEY_PLAYPAUSE },
93       { "XF86AudioMedia", MEDIA_KEY_MEDIA }
94     };
95
96     ecore_wl2_init();
97
98     if (!ecore_wl2_display_connect(NULL)) {
99       _E("Failed to connect to wl2 display");
100       ecore_wl2_shutdown();
101       return;
102     }
103
104     disposed_ = false;
105   }
106
107   void Fini() {
108     Ecore_Wl2_Display* dpy = ecore_wl2_connected_display_get(NULL);
109     if (dpy)
110       ecore_wl2_display_disconnect(dpy);
111
112     ecore_wl2_shutdown();
113     disposed_ = true;
114   }
115
116   int Grab() {
117     for (auto i = key_map_.begin(); i != key_map_.end(); i++) {
118       _D("key(%s)", i->first.c_str());
119       auto ret = ecore_wl2_window_keygrab_set(NULL, i->first.c_str(),
120           0, 0, 0, ECORE_WL2_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE);
121       if (ret != EINA_TRUE) {
122         _E("Failed to grab key(%s)", i->first.c_str());
123         Ungrab();
124         return MEDIA_KEY_ERROR_OPERATION_FAILED;
125       }
126     }
127
128     key_down_handler_ = ecore_event_handler_add(ECORE_EVENT_KEY_DOWN,
129         MediaKeyPressCb, this);
130     if (!key_down_handler_)
131       _E("Failed to register key down event handler");
132
133     key_up_handler_ = ecore_event_handler_add(ECORE_EVENT_KEY_UP,
134         MediaKeyReleaseCb, this);
135     if (!key_up_handler_)
136       _E("Failed to register key up event handler");
137
138     grabbed_ = true;
139     return 0;
140   }
141
142   void Ungrab() {
143     if (key_up_handler_) {
144       ecore_event_handler_del(key_up_handler_);
145       key_up_handler_ = nullptr;
146     }
147
148     if (key_down_handler_) {
149       ecore_event_handler_del(key_down_handler_);
150       key_down_handler_ = nullptr;
151     }
152
153     for (auto i = key_map_.rbegin(); i != key_map_.rend(); i++) {
154       _D("key(%s)", i->first.c_str());
155       auto ret = ecore_wl2_window_keygrab_unset(NULL, i->first.c_str(), 0, 0);
156       if (ret != EINA_TRUE)
157         _W("Failed to ungrab key(%s)", i->first.c_str());
158     }
159
160     grabbed_ = false;
161   }
162
163   std::recursive_mutex& GetMutex() const {
164     return mutex_;
165   }
166
167   static Eina_Bool MediaKeyPressCb(void* data, int type, void* event) {
168     Evas_Event_Key_Down* ev = static_cast<Evas_Event_Key_Down*>(event);
169     if (ev == nullptr) {
170       _E("Invalid parameter");
171       return ECORE_CALLBACK_RENEW;
172     }
173
174     auto* handle = static_cast<MediaKey*>(data);
175     if (handle->cb_ == nullptr)
176       return ECORE_CALLBACK_RENEW;
177
178     if (handle->key_map_.find(ev->keyname) == handle->key_map_.end())
179       return ECORE_CALLBACK_RENEW;
180
181     media_key_e media_key = handle->key_map_[ev->keyname];
182     handle->cb_(media_key, MEDIA_KEY_STATUS_PRESSED, handle->data_);
183     return ECORE_CALLBACK_RENEW;
184   }
185
186   static Eina_Bool MediaKeyReleaseCb(void* data, int type, void* event) {
187     Evas_Event_Key_Up* ev = static_cast<Evas_Event_Key_Up*>(event);
188     if (ev == nullptr) {
189       _E("Invalid parameter");
190       return ECORE_CALLBACK_RENEW;
191     }
192
193     auto* handle = static_cast<MediaKey*>(data);
194     if (handle->cb_ == nullptr)
195       return ECORE_CALLBACK_RENEW;
196
197     if (handle->key_map_.find(ev->keyname) == handle->key_map_.end())
198       return ECORE_CALLBACK_RENEW;
199
200     media_key_e media_key = handle->key_map_[ev->keyname];
201     handle->cb_(media_key, MEDIA_KEY_STATUS_RELEASED, handle->data_);
202     return ECORE_CALLBACK_RENEW;
203   }
204
205  private:
206   bool disposed_ = true;
207   bool grabbed_ = false;
208   media_key_event_cb cb_ = nullptr;
209   void* data_ = nullptr;
210   Ecore_Event_Handler* key_up_handler_ = nullptr;
211   Ecore_Event_Handler* key_down_handler_ = nullptr;
212   std::map<std::string, media_key_e> key_map_;
213   mutable std::recursive_mutex mutex_;
214 };
215
216 }  // namespace
217
218 extern "C" EXPORT_API int media_key_reserve(media_key_event_cb callback,
219     void* user_data) {
220   if (callback == nullptr) {
221     _E("Invalid parameter");
222     return MEDIA_KEY_ERROR_INVALID_PARAMETER;
223   }
224
225   return ::MediaKey::GetInst().Reserve(callback, user_data);
226 }
227
228 extern "C" EXPORT_API int media_key_release(void) {
229   ::MediaKey::GetInst().Release();
230   return MEDIA_KEY_ERROR_NONE;
231 }
232