5249314d92832c605e6deb85767621ef0815526e
[platform/core/system/deviced.git] / plugins / iot-headless / input / input-handler.c
1 /*
2  * deviced
3  *
4  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <time.h>
20 #include <stdint.h>
21 #include <libinput.h>
22 #include <linux/input.h>
23 #include <glib.h>
24 #include <libsyscommon/libgdbus.h>
25 #include <libsyscommon/list.h>
26
27 #include "shared/common.h"
28 #include "shared/device-notifier.h"
29 #include "shared/log.h"
30 #include "shared/event.h"
31
32 #include "input-config.h"
33 #include "input/input.h"
34 #include "input/input-plugin-interface.h"
35
36 static int input_event_handler_id;
37
38 static gboolean level_event_detected(gpointer data)
39 {
40         struct input_event_unit *ieu = (struct input_event_unit *) data;
41
42         ieu->timer = 0;
43
44         _D("Detected level event=%s(%d), action=%d", ieu->name, ieu->id, ieu->notifier);
45
46         if (check_input_event_condition(ieu) == 0) {
47                 _D("Skip triggering event=%s(%d), condition=%s isn't meet", ieu->name, ieu->id, ieu->cv.keyname);
48                 return G_SOURCE_REMOVE;
49         }
50
51         if (ieu->broadcast)
52                 event_broadcast_id(ieu->id);
53
54         if (ieu->wakelock_duration > 0)
55                 event_acquire_wakelock(ieu->id, ieu->wakelock_duration);
56
57         if (ieu->notifier)
58                 syscommon_notifier_emit_notify(ieu->notifier, ieu->user_data);
59
60         return G_SOURCE_REMOVE;
61 }
62
63 static void edge_event_detected(struct input_event_unit *ieu)
64 {
65         _D("Detected edge event=%s(%d), action=%d", ieu->name, ieu->id, ieu->notifier);
66
67         if (check_input_event_condition(ieu) == 0) {
68                 _D("Skip triggering event=%s(%d), condition=%s isn't meet", ieu->name, ieu->id, ieu->cv.keyname);
69                 return;
70         }
71
72         if (ieu->broadcast)
73                 event_broadcast_id(ieu->id);
74
75         if (ieu->wakelock_duration > 0)
76                 event_acquire_wakelock(ieu->id, ieu->wakelock_duration);
77
78         if (ieu->notifier)
79                 syscommon_notifier_emit_notify(ieu->notifier, ieu->user_data);
80 }
81
82 static void start_event_timer(struct input_config *ic)
83 {
84         struct timespec ts;
85         struct input_event_unit *ieu;
86         GList *elem;
87
88         clock_gettime(CLOCK_MONOTONIC, &ts);
89         ic->start = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
90
91         /* set timer for level-trigger event */
92         SYS_G_LIST_FOREACH(ic->event_list, elem, ieu) {
93                 if (ieu->type == TRIGGER_TYPE_LEVEL) {
94                         if (ieu->timer)
95                                 g_source_remove(ieu->timer);
96                         ieu->timer = g_timeout_add(ieu->interval[0], level_event_detected, (gpointer) ieu);
97                 }
98         }
99 }
100
101 static void stop_event_timer(struct input_config *ic)
102 {
103         struct timespec ts;
104         struct input_event_unit *ieu;
105         GList *elem;
106         unsigned long current;
107         unsigned long lapse;
108
109         if (ic->start == 0)
110                 return;
111
112         clock_gettime(CLOCK_MONOTONIC, &ts);
113         current = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
114         lapse = current - ic->start;
115         ic->start = 0;
116
117         SYS_G_LIST_FOREACH(ic->event_list, elem, ieu) {
118                 /* remove all level-trigger timer */
119                 if (ieu->timer) {
120                         g_source_remove(ieu->timer);
121                         ieu->timer = 0;
122                 }
123
124                 /* detected edge-trigger event */
125                 if (lapse >= ieu->interval[0] && lapse < ieu->interval[1] && ieu->type == TRIGGER_TYPE_EDGE)
126                         edge_event_detected(ieu);
127         }
128 }
129
130 static void input_handler_process_key(struct timeval time, unsigned short type, unsigned short keycode, unsigned int keyvalue)
131 {
132         struct input_config *ic;
133
134         if (type != EV_KEY)
135                 return;
136
137         _D("Key input: code=%d, value=%d", keycode, keyvalue);
138
139         /* acquire tmplock on pressing key */
140         if (keyvalue == KEY_PRESSED)
141                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_KEY_PRESS, (void *)(intptr_t) keycode);
142
143         /* process all registered event to the keycode */
144         ic = find_input_config(keycode);
145         if (ic && keyvalue == KEY_PRESSED)
146                 start_event_timer(ic);
147         else if (ic && keyvalue == KEY_RELEASED)
148                 stop_event_timer(ic);
149
150         /* release tmplock on releasing key */
151         if (keyvalue == KEY_RELEASED)
152                 syscommon_notifier_emit_notify(DEVICE_NOTIFIER_KEY_RELEASE, (void *)(intptr_t) keycode);
153 }
154
155 static int input_handler_init(void *data)
156 {
157         init_input_config();
158         input_register_event_callback(input_handler_process_key, NULL, NULL, &input_event_handler_id);
159
160         return 0;
161 }
162
163 static void input_handler_exit(void *data)
164 {
165         input_unregister_event_callback(input_event_handler_id);
166 }
167
168 const struct input_plugin_interface INPUT_PLUGIN_INTERFACE_SYMBOL = {
169         .init              = input_handler_init,
170         .exit              = input_handler_exit,
171 };