chiark / gitweb /
c8c03f3d41be9937182fb184252f46e0f0fda544
[elogind.git] / src / libsystemd-terminal / idev.h
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 /*
23  * IDev
24  */
25
26 #pragma once
27
28 #include <inttypes.h>
29 #include <libudev.h>
30 #include <linux/input.h>
31 #include <stdbool.h>
32 #include <stdlib.h>
33 #include <systemd/sd-bus.h>
34 #include <systemd/sd-event.h>
35 #include <xkbcommon/xkbcommon.h>
36 #include "util.h"
37
38 typedef struct idev_data                idev_data;
39 typedef struct idev_data_evdev          idev_data_evdev;
40 typedef struct idev_data_keyboard       idev_data_keyboard;
41
42 typedef struct idev_event               idev_event;
43 typedef struct idev_device              idev_device;
44 typedef struct idev_session             idev_session;
45 typedef struct idev_context             idev_context;
46
47 /*
48  * Types
49  */
50
51 enum {
52         IDEV_ELEMENT_EVDEV,
53         IDEV_ELEMENT_CNT
54 };
55
56 enum {
57         IDEV_DEVICE_KEYBOARD,
58         IDEV_DEVICE_CNT
59 };
60
61 /*
62  * Evdev Elements
63  */
64
65 struct idev_data_evdev {
66         struct input_event event;
67 };
68
69 /*
70  * Keyboard Devices
71  */
72
73 struct xkb_state;
74
75 enum {
76         IDEV_KBDMOD_IDX_SHIFT,
77         IDEV_KBDMOD_IDX_CTRL,
78         IDEV_KBDMOD_IDX_ALT,
79         IDEV_KBDMOD_IDX_LINUX,
80         IDEV_KBDMOD_IDX_CAPS,
81         IDEV_KBDMOD_CNT,
82
83         IDEV_KBDMOD_SHIFT               = 1 << IDEV_KBDMOD_IDX_SHIFT,
84         IDEV_KBDMOD_CTRL                = 1 << IDEV_KBDMOD_IDX_CTRL,
85         IDEV_KBDMOD_ALT                 = 1 << IDEV_KBDMOD_IDX_ALT,
86         IDEV_KBDMOD_LINUX               = 1 << IDEV_KBDMOD_IDX_LINUX,
87         IDEV_KBDMOD_CAPS                = 1 << IDEV_KBDMOD_IDX_CAPS,
88 };
89
90 enum {
91         IDEV_KBDLED_IDX_NUM,
92         IDEV_KBDLED_IDX_CAPS,
93         IDEV_KBDLED_IDX_SCROLL,
94         IDEV_KBDLED_CNT,
95
96         IDEV_KBDLED_NUM                 = 1 << IDEV_KBDLED_IDX_NUM,
97         IDEV_KBDLED_CAPS                = 1 << IDEV_KBDLED_IDX_CAPS,
98         IDEV_KBDLED_SCROLL              = 1 << IDEV_KBDLED_IDX_SCROLL,
99 };
100
101 struct idev_data_keyboard {
102         struct xkb_state *xkb_state;
103         int8_t ascii;
104         uint8_t value;
105         uint16_t keycode;
106         uint32_t mods;
107         uint32_t consumed_mods;
108         uint32_t n_syms;
109         uint32_t *keysyms;
110         uint32_t *codepoints;
111 };
112
113 static inline bool idev_kbdmatch(idev_data_keyboard *kdata,
114                                  uint32_t mods, uint32_t n_syms,
115                                  const uint32_t *syms) {
116         const uint32_t significant = IDEV_KBDMOD_SHIFT |
117                                      IDEV_KBDMOD_CTRL |
118                                      IDEV_KBDMOD_ALT |
119                                      IDEV_KBDMOD_LINUX;
120         uint32_t real;
121
122         if (n_syms != kdata->n_syms)
123                 return false;
124
125         real = kdata->mods & ~kdata->consumed_mods & significant;
126         if (real != mods)
127                 return false;
128
129         return !memcmp(syms, kdata->keysyms, n_syms * sizeof(*syms));
130 }
131
132 #define IDEV_KBDMATCH(_kdata, _mods, _sym) \
133         idev_kbdmatch((_kdata), (_mods), 1, (const uint32_t[]){ (_sym) })
134
135 /*
136  * Data Packets
137  */
138
139 enum {
140         IDEV_DATA_RESYNC,
141         IDEV_DATA_EVDEV,
142         IDEV_DATA_KEYBOARD,
143         IDEV_DATA_CNT
144 };
145
146 struct idev_data {
147         unsigned int type;
148         bool resync : 1;
149
150         union {
151                 idev_data_evdev evdev;
152                 idev_data_keyboard keyboard;
153         };
154 };
155
156 /*
157  * Events
158  */
159
160 enum {
161         IDEV_EVENT_DEVICE_ADD,
162         IDEV_EVENT_DEVICE_REMOVE,
163         IDEV_EVENT_DEVICE_DATA,
164         IDEV_EVENT_CNT
165 };
166
167 struct idev_event {
168         unsigned int type;
169         union {
170                 struct {
171                         idev_device *device;
172                 } device_add, device_remove;
173
174                 struct {
175                         idev_device *device;
176                         idev_data data;
177                 } device_data;
178         };
179 };
180
181 typedef int (*idev_event_fn) (idev_session *s, void *userdata, idev_event *ev);
182
183 /*
184  * Devices
185  */
186
187 void idev_device_enable(idev_device *d);
188 void idev_device_disable(idev_device *d);
189
190 /*
191  * Sessions
192  */
193
194 enum {
195         IDEV_SESSION_CUSTOM                     = (1 << 0),
196         IDEV_SESSION_MANAGED                    = (1 << 1),
197 };
198
199 int idev_session_new(idev_session **out,
200                      idev_context *c,
201                      unsigned int flags,
202                      const char *name,
203                      idev_event_fn event_fn,
204                      void *userdata);
205 idev_session *idev_session_free(idev_session *s);
206
207 DEFINE_TRIVIAL_CLEANUP_FUNC(idev_session*, idev_session_free);
208
209 bool idev_session_is_enabled(idev_session *s);
210 void idev_session_enable(idev_session *s);
211 void idev_session_disable(idev_session *s);
212
213 int idev_session_add_evdev(idev_session *s, struct udev_device *ud);
214 int idev_session_remove_evdev(idev_session *s, struct udev_device *ud);
215
216 /*
217  * Contexts
218  */
219
220 int idev_context_new(idev_context **out, sd_event *event, sd_bus *sysbus);
221 idev_context *idev_context_ref(idev_context *c);
222 idev_context *idev_context_unref(idev_context *c);
223
224 DEFINE_TRIVIAL_CLEANUP_FUNC(idev_context*, idev_context_unref);