Home | History | Annotate | Download | only in minui
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      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 <stdio.h>
     18 #include <stdlib.h>
     19 #include <fcntl.h>
     20 #include <dirent.h>
     21 #include <sys/poll.h>
     22 
     23 #include <linux/input.h>
     24 
     25 #include "minui.h"
     26 
     27 #define MAX_DEVICES 16
     28 #define MAX_MISC_FDS 16
     29 
     30 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
     31 #define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
     32 
     33 #define test_bit(bit, array) \
     34     ((array)[(bit)/BITS_PER_LONG] & (1 << ((bit) % BITS_PER_LONG)))
     35 
     36 struct fd_info {
     37     ev_callback cb;
     38     void *data;
     39 };
     40 
     41 static struct pollfd ev_fds[MAX_DEVICES + MAX_MISC_FDS];
     42 static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
     43 
     44 static unsigned ev_count = 0;
     45 static unsigned ev_dev_count = 0;
     46 static unsigned ev_misc_count = 0;
     47 
     48 int ev_init(ev_callback input_cb, void *data)
     49 {
     50     DIR *dir;
     51     struct dirent *de;
     52     int fd;
     53 
     54     dir = opendir("/dev/input");
     55     if(dir != 0) {
     56         while((de = readdir(dir))) {
     57             unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
     58 
     59 //            fprintf(stderr,"/dev/input/%s\n", de->d_name);
     60             if(strncmp(de->d_name,"event",5)) continue;
     61             fd = openat(dirfd(dir), de->d_name, O_RDONLY);
     62             if(fd < 0) continue;
     63 
     64             /* read the evbits of the input device */
     65             if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
     66                 close(fd);
     67                 continue;
     68             }
     69 
     70             /* TODO: add ability to specify event masks. For now, just assume
     71              * that only EV_KEY and EV_REL event types are ever needed. */
     72             if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) {
     73                 close(fd);
     74                 continue;
     75             }
     76 
     77             ev_fds[ev_count].fd = fd;
     78             ev_fds[ev_count].events = POLLIN;
     79             ev_fdinfo[ev_count].cb = input_cb;
     80             ev_fdinfo[ev_count].data = data;
     81             ev_count++;
     82             ev_dev_count++;
     83             if(ev_dev_count == MAX_DEVICES) break;
     84         }
     85     }
     86 
     87     return 0;
     88 }
     89 
     90 int ev_add_fd(int fd, ev_callback cb, void *data)
     91 {
     92     if (ev_misc_count == MAX_MISC_FDS || cb == NULL)
     93         return -1;
     94 
     95     ev_fds[ev_count].fd = fd;
     96     ev_fds[ev_count].events = POLLIN;
     97     ev_fdinfo[ev_count].cb = cb;
     98     ev_fdinfo[ev_count].data = data;
     99     ev_count++;
    100     ev_misc_count++;
    101     return 0;
    102 }
    103 
    104 void ev_exit(void)
    105 {
    106     while (ev_count > 0) {
    107         close(ev_fds[--ev_count].fd);
    108     }
    109     ev_misc_count = 0;
    110     ev_dev_count = 0;
    111 }
    112 
    113 int ev_wait(int timeout)
    114 {
    115     int r;
    116 
    117     r = poll(ev_fds, ev_count, timeout);
    118     if (r <= 0)
    119         return -1;
    120     return 0;
    121 }
    122 
    123 void ev_dispatch(void)
    124 {
    125     unsigned n;
    126     int ret;
    127 
    128     for (n = 0; n < ev_count; n++) {
    129         ev_callback cb = ev_fdinfo[n].cb;
    130         if (cb && (ev_fds[n].revents & ev_fds[n].events))
    131             cb(ev_fds[n].fd, ev_fds[n].revents, ev_fdinfo[n].data);
    132     }
    133 }
    134 
    135 int ev_get_input(int fd, short revents, struct input_event *ev)
    136 {
    137     int r;
    138 
    139     if (revents & POLLIN) {
    140         r = read(fd, ev, sizeof(*ev));
    141         if (r == sizeof(*ev))
    142             return 0;
    143     }
    144     return -1;
    145 }
    146 
    147 int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data)
    148 {
    149     unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
    150     unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
    151     unsigned i;
    152     int ret;
    153 
    154     for (i = 0; i < ev_dev_count; i++) {
    155         int code;
    156 
    157         memset(key_bits, 0, sizeof(key_bits));
    158         memset(ev_bits, 0, sizeof(ev_bits));
    159 
    160         ret = ioctl(ev_fds[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
    161         if (ret < 0 || !test_bit(EV_KEY, ev_bits))
    162             continue;
    163 
    164         ret = ioctl(ev_fds[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits);
    165         if (ret < 0)
    166             continue;
    167 
    168         for (code = 0; code <= KEY_MAX; code++) {
    169             if (test_bit(code, key_bits))
    170                 set_key_cb(code, 1, data);
    171         }
    172     }
    173 
    174     return 0;
    175 }
    176