c1e11d385f6a48b0a196cc7de0a4b20adf6bd56c
[platform/upstream/libinput.git] / src / evdev.c
1 /*
2  * Copyright © 2010 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <linux/input.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <mtdev.h>
31 #include <assert.h>
32
33 #include "compositor.h"
34 #include "evdev.h"
35
36 #define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10)
37
38 void
39 evdev_led_update(struct evdev_device *device, enum weston_led leds)
40 {
41         static const struct {
42                 enum weston_led weston;
43                 int evdev;
44         } map[] = {
45                 { LED_NUM_LOCK, LED_NUML },
46                 { LED_CAPS_LOCK, LED_CAPSL },
47                 { LED_SCROLL_LOCK, LED_SCROLLL },
48         };
49         struct input_event ev[ARRAY_LENGTH(map) + 1];
50         unsigned int i;
51
52         if (!device->caps & EVDEV_KEYBOARD)
53                 return;
54
55         memset(ev, 0, sizeof(ev));
56         for (i = 0; i < ARRAY_LENGTH(map); i++) {
57                 ev[i].type = EV_LED;
58                 ev[i].code = map[i].evdev;
59                 ev[i].value = !!(leds & map[i].weston);
60         }
61         ev[i].type = EV_SYN;
62         ev[i].code = SYN_REPORT;
63
64         i = write(device->fd, ev, sizeof ev);
65         (void)i; /* no, we really don't care about the return value */
66 }
67
68 static void
69 transform_absolute(struct evdev_device *device, int32_t *x, int32_t *y)
70 {
71        if (!device->abs.apply_calibration) {
72                *x = device->abs.x;
73                *y = device->abs.y;
74                return;
75        } else {
76                *x = device->abs.x * device->abs.calibration[0] +
77                        device->abs.y * device->abs.calibration[1] +
78                        device->abs.calibration[2];
79
80                *y = device->abs.x * device->abs.calibration[3] +
81                        device->abs.y * device->abs.calibration[4] +
82                        device->abs.calibration[5];
83        }
84 }
85
86 static void
87 evdev_flush_pending_event(struct evdev_device *device, uint32_t time)
88 {
89         struct weston_seat *master = device->seat;
90         wl_fixed_t x, y;
91         int32_t cx, cy;
92         int slot;
93
94         slot = device->mt.slot;
95
96         switch (device->pending_event) {
97         case EVDEV_NONE:
98                 return;
99         case EVDEV_RELATIVE_MOTION:
100                 notify_motion(master, time, device->rel.dx, device->rel.dy);
101                 device->rel.dx = 0;
102                 device->rel.dy = 0;
103                 goto handled;
104         case EVDEV_ABSOLUTE_MT_DOWN:
105                 weston_output_transform_coordinate(device->output,
106                                                    device->mt.slots[slot].x,
107                                                    device->mt.slots[slot].y,
108                                                    &x, &y);
109                 notify_touch(master, time,
110                              slot, x, y, WL_TOUCH_DOWN);
111                 goto handled;
112         case EVDEV_ABSOLUTE_MT_MOTION:
113                 weston_output_transform_coordinate(device->output,
114                                                    device->mt.slots[slot].x,
115                                                    device->mt.slots[slot].y,
116                                                    &x, &y);
117                 notify_touch(master, time,
118                              slot, x, y, WL_TOUCH_MOTION);
119                 goto handled;
120         case EVDEV_ABSOLUTE_MT_UP:
121                 notify_touch(master, time, slot, 0, 0,
122                              WL_TOUCH_UP);
123                 goto handled;
124         case EVDEV_ABSOLUTE_MOTION:
125                 transform_absolute(device, &cx, &cy);
126                 weston_output_transform_coordinate(device->output,
127                                                    cx, cy, &x, &y);
128
129                 if (device->caps & EVDEV_TOUCH) {
130                         if (master->num_tp == 0)
131                                 notify_touch(master, time, 0,
132                                              x, y, WL_TOUCH_DOWN);
133                         else
134                                 notify_touch(master, time, 0,
135                                              x, y, WL_TOUCH_MOTION);
136                 } else
137                         notify_motion_absolute(master, time, x, y);
138                 goto handled;
139         }
140
141         assert(0 && "Unknown pending event type");
142
143 handled:
144         device->pending_event = EVDEV_NONE;
145 }
146
147 static inline void
148 evdev_process_key(struct evdev_device *device, struct input_event *e, int time)
149 {
150         /* ignore kernel key repeat */
151         if (e->value == 2)
152                 return;
153
154         evdev_flush_pending_event(device, time);
155
156         switch (e->code) {
157         case BTN_LEFT:
158         case BTN_RIGHT:
159         case BTN_MIDDLE:
160         case BTN_SIDE:
161         case BTN_EXTRA:
162         case BTN_FORWARD:
163         case BTN_BACK:
164         case BTN_TASK:
165                 notify_button(device->seat,
166                               time, e->code,
167                               e->value ? WL_POINTER_BUTTON_STATE_PRESSED :
168                                          WL_POINTER_BUTTON_STATE_RELEASED);
169                 break;
170
171         case BTN_TOUCH:
172                 if (e->value == 0 && !device->is_mt)
173                         notify_touch(device->seat, time, 0, 0, 0,
174                                      WL_TOUCH_UP);
175                 break;
176         default:
177                 notify_key(device->seat,
178                            time, e->code,
179                            e->value ? WL_KEYBOARD_KEY_STATE_PRESSED :
180                                       WL_KEYBOARD_KEY_STATE_RELEASED,
181                            STATE_UPDATE_AUTOMATIC);
182                 break;
183         }
184 }
185
186 static void
187 evdev_process_touch(struct evdev_device *device,
188                     struct input_event *e,
189                     uint32_t time)
190 {
191         const int screen_width = device->output->current_mode->width;
192         const int screen_height = device->output->current_mode->height;
193
194         switch (e->code) {
195         case ABS_MT_SLOT:
196                 evdev_flush_pending_event(device, time);
197                 device->mt.slot = e->value;
198                 break;
199         case ABS_MT_TRACKING_ID:
200                 if (device->pending_event != EVDEV_NONE &&
201                     device->pending_event != EVDEV_ABSOLUTE_MT_MOTION)
202                         evdev_flush_pending_event(device, time);
203                 if (e->value >= 0)
204                         device->pending_event = EVDEV_ABSOLUTE_MT_DOWN;
205                 else
206                         device->pending_event = EVDEV_ABSOLUTE_MT_UP;
207                 break;
208         case ABS_MT_POSITION_X:
209                 device->mt.slots[device->mt.slot].x =
210                         (e->value - device->abs.min_x) * screen_width /
211                         (device->abs.max_x - device->abs.min_x);
212                 if (device->pending_event == EVDEV_NONE)
213                         device->pending_event = EVDEV_ABSOLUTE_MT_MOTION;
214                 break;
215         case ABS_MT_POSITION_Y:
216                 device->mt.slots[device->mt.slot].y =
217                         (e->value - device->abs.min_y) * screen_height /
218                         (device->abs.max_y - device->abs.min_y);
219                 if (device->pending_event == EVDEV_NONE)
220                         device->pending_event = EVDEV_ABSOLUTE_MT_MOTION;
221                 break;
222         }
223 }
224
225 static inline void
226 evdev_process_absolute_motion(struct evdev_device *device,
227                               struct input_event *e)
228 {
229         const int screen_width = device->output->current_mode->width;
230         const int screen_height = device->output->current_mode->height;
231
232         switch (e->code) {
233         case ABS_X:
234                 device->abs.x =
235                         (e->value - device->abs.min_x) * screen_width /
236                         (device->abs.max_x - device->abs.min_x);
237                 if (device->pending_event == EVDEV_NONE)
238                         device->pending_event = EVDEV_ABSOLUTE_MOTION;
239                 break;
240         case ABS_Y:
241                 device->abs.y =
242                         (e->value - device->abs.min_y) * screen_height /
243                         (device->abs.max_y - device->abs.min_y);
244                 if (device->pending_event == EVDEV_NONE)
245                         device->pending_event = EVDEV_ABSOLUTE_MOTION;
246                 break;
247         }
248 }
249
250 static inline void
251 evdev_process_relative(struct evdev_device *device,
252                        struct input_event *e, uint32_t time)
253 {
254         switch (e->code) {
255         case REL_X:
256                 if (device->pending_event != EVDEV_RELATIVE_MOTION)
257                         evdev_flush_pending_event(device, time);
258                 device->rel.dx += wl_fixed_from_int(e->value);
259                 device->pending_event = EVDEV_RELATIVE_MOTION;
260                 break;
261         case REL_Y:
262                 if (device->pending_event != EVDEV_RELATIVE_MOTION)
263                         evdev_flush_pending_event(device, time);
264                 device->rel.dy += wl_fixed_from_int(e->value);
265                 device->pending_event = EVDEV_RELATIVE_MOTION;
266                 break;
267         case REL_WHEEL:
268                 evdev_flush_pending_event(device, time);
269                 switch (e->value) {
270                 case -1:
271                         /* Scroll down */
272                 case 1:
273                         /* Scroll up */
274                         notify_axis(device->seat,
275                                     time,
276                                     WL_POINTER_AXIS_VERTICAL_SCROLL,
277                                     -1 * e->value * DEFAULT_AXIS_STEP_DISTANCE);
278                         break;
279                 default:
280                         break;
281                 }
282                 break;
283         case REL_HWHEEL:
284                 evdev_flush_pending_event(device, time);
285                 switch (e->value) {
286                 case -1:
287                         /* Scroll left */
288                 case 1:
289                         /* Scroll right */
290                         notify_axis(device->seat,
291                                     time,
292                                     WL_POINTER_AXIS_HORIZONTAL_SCROLL,
293                                     e->value * DEFAULT_AXIS_STEP_DISTANCE);
294                         break;
295                 default:
296                         break;
297
298                 }
299         }
300 }
301
302 static inline void
303 evdev_process_absolute(struct evdev_device *device,
304                        struct input_event *e,
305                        uint32_t time)
306 {
307         if (device->is_mt) {
308                 evdev_process_touch(device, e, time);
309         } else {
310                 evdev_process_absolute_motion(device, e);
311         }
312 }
313
314 static void
315 fallback_process(struct evdev_dispatch *dispatch,
316                  struct evdev_device *device,
317                  struct input_event *event,
318                  uint32_t time)
319 {
320         switch (event->type) {
321         case EV_REL:
322                 evdev_process_relative(device, event, time);
323                 break;
324         case EV_ABS:
325                 evdev_process_absolute(device, event, time);
326                 break;
327         case EV_KEY:
328                 evdev_process_key(device, event, time);
329                 break;
330         case EV_SYN:
331                 evdev_flush_pending_event(device, time);
332                 break;
333         }
334 }
335
336 static void
337 fallback_destroy(struct evdev_dispatch *dispatch)
338 {
339         free(dispatch);
340 }
341
342 struct evdev_dispatch_interface fallback_interface = {
343         fallback_process,
344         fallback_destroy
345 };
346
347 static struct evdev_dispatch *
348 fallback_dispatch_create(void)
349 {
350         struct evdev_dispatch *dispatch = malloc(sizeof *dispatch);
351         if (dispatch == NULL)
352                 return NULL;
353
354         dispatch->interface = &fallback_interface;
355
356         return dispatch;
357 }
358
359 static void
360 evdev_process_events(struct evdev_device *device,
361                      struct input_event *ev, int count)
362 {
363         struct evdev_dispatch *dispatch = device->dispatch;
364         struct input_event *e, *end;
365         uint32_t time = 0;
366
367         e = ev;
368         end = e + count;
369         for (e = ev; e < end; e++) {
370                 time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
371
372                 dispatch->interface->process(dispatch, device, e, time);
373         }
374 }
375
376 static int
377 evdev_device_data(int fd, uint32_t mask, void *data)
378 {
379         struct weston_compositor *ec;
380         struct evdev_device *device = data;
381         struct input_event ev[32];
382         int len;
383
384         ec = device->seat->compositor;
385         if (!ec->focus)
386                 return 1;
387
388         /* If the compositor is repainting, this function is called only once
389          * per frame and we have to process all the events available on the
390          * fd, otherwise there will be input lag. */
391         do {
392                 if (device->mtdev)
393                         len = mtdev_get(device->mtdev, fd, ev,
394                                         ARRAY_LENGTH(ev)) *
395                                 sizeof (struct input_event);
396                 else
397                         len = read(fd, &ev, sizeof ev);
398
399                 if (len < 0 || len % sizeof ev[0] != 0) {
400                         /* FIXME: call evdev_device_destroy when errno is ENODEV. */
401                         return 1;
402                 }
403
404                 evdev_process_events(device, ev, len / sizeof ev[0]);
405
406         } while (len > 0);
407
408         return 1;
409 }
410
411 static int
412 evdev_handle_device(struct evdev_device *device)
413 {
414         struct input_absinfo absinfo;
415         unsigned long ev_bits[NBITS(EV_MAX)];
416         unsigned long abs_bits[NBITS(ABS_MAX)];
417         unsigned long rel_bits[NBITS(REL_MAX)];
418         unsigned long key_bits[NBITS(KEY_MAX)];
419         int has_key, has_abs;
420         unsigned int i;
421
422         has_key = 0;
423         has_abs = 0;
424         device->caps = 0;
425
426         ioctl(device->fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
427         if (TEST_BIT(ev_bits, EV_ABS)) {
428                 has_abs = 1;
429
430                 ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),
431                       abs_bits);
432
433                 if (TEST_BIT(abs_bits, ABS_WHEEL) ||
434                     TEST_BIT(abs_bits, ABS_GAS) ||
435                     TEST_BIT(abs_bits, ABS_BRAKE) ||
436                     TEST_BIT(abs_bits, ABS_HAT0X)) {
437                         weston_log("device %s is a joystick, ignoring\n",
438                                    device->devnode);
439                         return 0;
440                 }
441
442                 if (TEST_BIT(abs_bits, ABS_X)) {
443                         ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo);
444                         device->abs.min_x = absinfo.minimum;
445                         device->abs.max_x = absinfo.maximum;
446                         device->caps |= EVDEV_MOTION_ABS;
447                 }
448                 if (TEST_BIT(abs_bits, ABS_Y)) {
449                         ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo);
450                         device->abs.min_y = absinfo.minimum;
451                         device->abs.max_y = absinfo.maximum;
452                         device->caps |= EVDEV_MOTION_ABS;
453                 }
454                 /* We only handle the slotted Protocol B in weston.
455                    Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT
456                    require mtdev for conversion. */
457                 if (TEST_BIT(abs_bits, ABS_MT_POSITION_X) &&
458                     TEST_BIT(abs_bits, ABS_MT_POSITION_Y)) {
459                         ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_X),
460                               &absinfo);
461                         device->abs.min_x = absinfo.minimum;
462                         device->abs.max_x = absinfo.maximum;
463                         ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_Y),
464                               &absinfo);
465                         device->abs.min_y = absinfo.minimum;
466                         device->abs.max_y = absinfo.maximum;
467                         device->is_mt = 1;
468                         device->caps |= EVDEV_TOUCH;
469
470                         if (!TEST_BIT(abs_bits, ABS_MT_SLOT)) {
471                                 device->mtdev = mtdev_new_open(device->fd);
472                                 if (!device->mtdev) {
473                                         weston_log("mtdev required but failed to open for %s\n",
474                                                    device->devnode);
475                                         return 0;
476                                 }
477                                 device->mt.slot = device->mtdev->caps.slot.value;
478                         } else {
479                                 ioctl(device->fd, EVIOCGABS(ABS_MT_SLOT),
480                                       &absinfo);
481                                 device->mt.slot = absinfo.value;
482                         }
483                 }
484         }
485         if (TEST_BIT(ev_bits, EV_REL)) {
486                 ioctl(device->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)),
487                       rel_bits);
488                 if (TEST_BIT(rel_bits, REL_X) || TEST_BIT(rel_bits, REL_Y))
489                         device->caps |= EVDEV_MOTION_REL;
490         }
491         if (TEST_BIT(ev_bits, EV_KEY)) {
492                 has_key = 1;
493                 ioctl(device->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),
494                       key_bits);
495                 if (TEST_BIT(key_bits, BTN_TOOL_FINGER) &&
496                     !TEST_BIT(key_bits, BTN_TOOL_PEN) &&
497                     has_abs) {
498                         device->dispatch = evdev_touchpad_create(device);
499                         weston_log("input device %s, %s is a touchpad\n",
500                                    device->devname, device->devnode);
501                 }
502                 for (i = KEY_ESC; i < KEY_MAX; i++) {
503                         if (i >= BTN_MISC && i < KEY_OK)
504                                 continue;
505                         if (TEST_BIT(key_bits, i)) {
506                                 device->caps |= EVDEV_KEYBOARD;
507                                 break;
508                         }
509                 }
510                 for (i = BTN_MISC; i < KEY_OK; i++) {
511                         if (TEST_BIT(key_bits, i)) {
512                                 device->caps |= EVDEV_BUTTON;
513                                 break;
514                         }
515                 }
516                 if (TEST_BIT(key_bits, BTN_TOUCH)) {
517                         device->caps |= EVDEV_TOUCH;
518                 }
519
520         }
521         if (TEST_BIT(ev_bits, EV_LED)) {
522                 device->caps |= EVDEV_KEYBOARD;
523         }
524
525         /* This rule tries to catch accelerometer devices and opt out. We may
526          * want to adjust the protocol later adding a proper event for dealing
527          * with accelerometers and implement here accordingly */
528         if (has_abs && !has_key && !device->is_mt) {
529                 weston_log("input device %s, %s "
530                            "ignored: unsupported device type\n",
531                            device->devname, device->devnode);
532                 return 0;
533         }
534
535         return 1;
536 }
537
538 static int
539 evdev_configure_device(struct evdev_device *device)
540 {
541         if ((device->caps &
542              (EVDEV_MOTION_ABS | EVDEV_MOTION_REL | EVDEV_BUTTON))) {
543                 weston_seat_init_pointer(device->seat);
544                 weston_log("input device %s, %s is a pointer caps =%s%s%s\n",
545                            device->devname, device->devnode,
546                            device->caps & EVDEV_MOTION_ABS ? " absolute-motion" : "",
547                            device->caps & EVDEV_MOTION_REL ? " relative-motion": "",
548                            device->caps & EVDEV_BUTTON ? " button" : "");
549         }
550         if ((device->caps & EVDEV_KEYBOARD)) {
551                 if (weston_seat_init_keyboard(device->seat, NULL) < 0)
552                         return -1;
553                 weston_log("input device %s, %s is a keyboard\n",
554                            device->devname, device->devnode);
555         }
556         if ((device->caps & EVDEV_TOUCH)) {
557                 weston_seat_init_touch(device->seat);
558                 weston_log("input device %s, %s is a touch device\n",
559                            device->devname, device->devnode);
560         }
561
562         return 0;
563 }
564
565 struct evdev_device *
566 evdev_device_create(struct weston_seat *seat, const char *path, int device_fd)
567 {
568         struct evdev_device *device;
569         struct weston_compositor *ec;
570         char devname[256] = "unknown";
571
572         device = zalloc(sizeof *device);
573         if (device == NULL)
574                 return NULL;
575
576         ec = seat->compositor;
577         device->output =
578                 container_of(ec->output_list.next, struct weston_output, link);
579
580         device->seat = seat;
581         device->is_mt = 0;
582         device->mtdev = NULL;
583         device->devnode = strdup(path);
584         device->mt.slot = -1;
585         device->rel.dx = 0;
586         device->rel.dy = 0;
587         device->dispatch = NULL;
588         device->fd = device_fd;
589         device->pending_event = EVDEV_NONE;
590         wl_list_init(&device->link);
591
592         ioctl(device->fd, EVIOCGNAME(sizeof(devname)), devname);
593         devname[sizeof(devname) - 1] = '\0';
594         device->devname = strdup(devname);
595
596         if (!evdev_handle_device(device)) {
597                 evdev_device_destroy(device);
598                 return EVDEV_UNHANDLED_DEVICE;
599         }
600
601         if (evdev_configure_device(device) == -1)
602                 goto err;
603
604         /* If the dispatch was not set up use the fallback. */
605         if (device->dispatch == NULL)
606                 device->dispatch = fallback_dispatch_create();
607         if (device->dispatch == NULL)
608                 goto err;
609
610         device->source = wl_event_loop_add_fd(ec->input_loop, device->fd,
611                                               WL_EVENT_READABLE,
612                                               evdev_device_data, device);
613         if (device->source == NULL)
614                 goto err;
615
616         return device;
617
618 err:
619         evdev_device_destroy(device);
620         return NULL;
621 }
622
623 void
624 evdev_device_destroy(struct evdev_device *device)
625 {
626         struct evdev_dispatch *dispatch;
627
628         dispatch = device->dispatch;
629         if (dispatch)
630                 dispatch->interface->destroy(dispatch);
631
632         if (device->source)
633                 wl_event_source_remove(device->source);
634         wl_list_remove(&device->link);
635         if (device->mtdev)
636                 mtdev_close_delete(device->mtdev);
637         close(device->fd);
638         free(device->devname);
639         free(device->devnode);
640         free(device);
641 }
642
643 void
644 evdev_notify_keyboard_focus(struct weston_seat *seat,
645                             struct wl_list *evdev_devices)
646 {
647         struct evdev_device *device;
648         struct wl_array keys;
649         unsigned int i, set;
650         char evdev_keys[(KEY_CNT + 7) / 8];
651         char all_keys[(KEY_CNT + 7) / 8];
652         uint32_t *k;
653         int ret;
654
655         if (!seat->keyboard)
656                 return;
657
658         memset(all_keys, 0, sizeof all_keys);
659         wl_list_for_each(device, evdev_devices, link) {
660                 memset(evdev_keys, 0, sizeof evdev_keys);
661                 ret = ioctl(device->fd,
662                             EVIOCGKEY(sizeof evdev_keys), evdev_keys);
663                 if (ret < 0) {
664                         weston_log("failed to get keys for device %s\n",
665                                 device->devnode);
666                         continue;
667                 }
668                 for (i = 0; i < ARRAY_LENGTH(evdev_keys); i++)
669                         all_keys[i] |= evdev_keys[i];
670         }
671
672         wl_array_init(&keys);
673         for (i = 0; i < KEY_CNT; i++) {
674                 set = all_keys[i >> 3] & (1 << (i & 7));
675                 if (set) {
676                         k = wl_array_add(&keys, sizeof *k);
677                         *k = i;
678                 }
679         }
680
681         notify_keyboard_focus_in(seat, &keys, STATE_UPDATE_AUTOMATIC);
682
683         wl_array_release(&keys);
684 }