#include "elput_private.h" static void _seat_caps_update(Elput_Seat *seat) { /* TODO: raise event for seat caps */ } static int _keyboard_fd_get(off_t size) { int fd = 0, blen = 0, len = 0; const char *path; char tmp[PATH_MAX]; long flags; blen = sizeof(tmp) - 1; if (!(path = getenv("XDG_RUNTIME_DIR"))) return -1; len = strlen(path); if (len < blen) { strcpy(tmp, path); strcat(tmp, "/elput-keymap-XXXXXX"); } else return -1; if ((fd = mkstemp(tmp)) < 0) return -1; flags = fcntl(fd, F_GETFD); if (flags < 0) { close(fd); return -1; } if (fcntl(fd, F_SETFD, (flags | FD_CLOEXEC)) == -1) { close(fd); return -1; } if (ftruncate(fd, size) < 0) { close(fd); return -1; } unlink(tmp); return fd; } static Elput_Keyboard_Info * _keyboard_info_create(struct xkb_keymap *keymap, Eina_Bool external) { Elput_Keyboard_Info *info; char *str; info = calloc(1, sizeof(Elput_Keyboard_Info)); if (!info) return NULL; info->keymap.map = xkb_keymap_ref(keymap); info->refs = 1; info->mods.super = 1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_LOGO); info->mods.shift = 1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_SHIFT); info->mods.caps = 1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_CAPS); info->mods.ctrl = 1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_CTRL); info->mods.alt = 1 << xkb_keymap_mod_get_index(info->keymap.map, XKB_MOD_NAME_ALT); info->mods.altgr = 1 << xkb_keymap_mod_get_index(info->keymap.map, "ISO_Level3_Shift"); /* if we are using an external keymap then we do not need go further */ if (external) return info; str = xkb_keymap_get_as_string(info->keymap.map, XKB_KEYMAP_FORMAT_TEXT_V1); if (!str) goto err; info->keymap.size = strlen(str) + 1; info->keymap.fd = _keyboard_fd_get(info->keymap.size); if (info->keymap.fd < 0) goto err_fd; info->keymap.area = mmap(NULL, info->keymap.size, PROT_READ | PROT_WRITE, MAP_SHARED, info->keymap.fd, 0); if (info->keymap.area == MAP_FAILED) goto err_map; strcpy(info->keymap.area, str); free(str); return info; err_map: close(info->keymap.fd); err_fd: free(str); err: xkb_keymap_unref(info->keymap.map); free(info); return NULL; } static void _keyboard_info_destroy(Elput_Keyboard_Info *info, Eina_Bool external) { if (--info->refs > 0) return; if (!external) { xkb_keymap_unref(info->keymap.map); if (info->keymap.area) munmap(info->keymap.area, info->keymap.size); if (info->keymap.fd >= 0) close(info->keymap.fd); } free(info); } static Eina_Bool _keyboard_global_build(Elput_Keyboard *kbd) { struct xkb_keymap *keymap; kbd->context = xkb_context_new(0); if (!kbd->context) return EINA_FALSE; if (!kbd->names.rules) kbd->names.rules = strdup("evdev"); if (!kbd->names.model) kbd->names.model = strdup("pc105"); if (!kbd->names.layout) kbd->names.layout = strdup("us"); keymap = xkb_keymap_new_from_names(kbd->context, &kbd->names, 0); if (!keymap) return EINA_FALSE; kbd->info = _keyboard_info_create(keymap, EINA_FALSE); xkb_keymap_unref(keymap); if (!kbd->info) return EINA_FALSE; return EINA_TRUE; } static Elput_Keyboard * _keyboard_create(Elput_Seat *seat) { Elput_Keyboard *kbd; kbd = calloc(1, sizeof(Elput_Keyboard)); if (!kbd) return NULL; kbd->seat = seat; return kbd; } static Eina_Bool _keyboard_init(Elput_Seat *seat, struct xkb_keymap *keymap) { Elput_Keyboard *kbd; if (seat->kbd) { seat->count.kbd += 1; if (seat->count.kbd == 1) { _seat_caps_update(seat); return EINA_TRUE; } } kbd = _keyboard_create(seat); if (!kbd) return EINA_FALSE; if (keymap) { kbd->info = _keyboard_info_create(keymap, EINA_TRUE); if (!kbd->info) goto err; } else { if (!_keyboard_global_build(kbd)) goto err; kbd->info->refs++; } kbd->state = xkb_state_new(kbd->info->keymap.map); if (!kbd->state) goto err; seat->kbd = kbd; seat->count.kbd = 1; _seat_caps_update(seat); return EINA_TRUE; err: if (kbd->info) _keyboard_info_destroy(kbd->info, kbd->external_map); free(kbd); return EINA_FALSE; } static void _keyboard_state_reset(Elput_Keyboard *kbd) { struct xkb_state *state; state = xkb_state_new(kbd->info->keymap.map); if (!state) return; xkb_state_unref(kbd->state); kbd->state = state; } static void _keyboard_release(Elput_Seat *seat) { seat->count.kbd--; if (seat->count.kbd == 0) { _keyboard_state_reset(seat->kbd); _seat_caps_update(seat); } } static Elput_Pointer * _pointer_create(Elput_Seat *seat) { Elput_Pointer *ptr; ptr = calloc(1, sizeof(Elput_Pointer)); if (!ptr) return NULL; ptr->seat = seat; return ptr; } static Eina_Bool _pointer_init(Elput_Seat *seat) { Elput_Pointer *ptr; if (seat->ptr) { seat->count.ptr += 1; if (seat->count.ptr == 1) { _seat_caps_update(seat); return EINA_TRUE; } } ptr = _pointer_create(seat); if (!ptr) return EINA_FALSE; seat->ptr = ptr; seat->count.ptr = 1; _seat_caps_update(seat); return EINA_TRUE; } static void _pointer_release(Elput_Seat *seat) { seat->count.ptr--; if (seat->count.ptr == 0) { seat->ptr->buttons = 0; _seat_caps_update(seat); } } static Elput_Touch * _touch_create(Elput_Seat *seat) { Elput_Touch *touch; touch = calloc(1, sizeof(Elput_Touch)); if (!touch) return NULL; touch->seat = seat; return touch; } static Eina_Bool _touch_init(Elput_Seat *seat) { Elput_Touch *touch; if (seat->touch) { seat->count.touch += 1; if (seat->count.touch == 1) { _seat_caps_update(seat); return EINA_TRUE; } } touch = _touch_create(seat); if (!touch) return EINA_FALSE; seat->touch = touch; seat->count.touch = 1; _seat_caps_update(seat); return EINA_TRUE; } static void _touch_release(Elput_Seat *seat) { seat->count.touch--; if (seat->count.touch == 0) { seat->touch->points = 0; _seat_caps_update(seat); } } int _evdev_event_process(struct libinput_event *event) { struct libinput_device *idev; int ret = 1; Eina_Bool frame = EINA_FALSE; idev = libinput_event_get_device(event); switch (libinput_event_get_type(event)) { case LIBINPUT_EVENT_KEYBOARD_KEY: break; case LIBINPUT_EVENT_POINTER_MOTION: break; case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: break; case LIBINPUT_EVENT_POINTER_BUTTON: break; case LIBINPUT_EVENT_POINTER_AXIS: break; case LIBINPUT_EVENT_TOUCH_DOWN: break; case LIBINPUT_EVENT_TOUCH_MOTION: break; case LIBINPUT_EVENT_TOUCH_UP: break; case LIBINPUT_EVENT_TOUCH_FRAME: default: ret = 0; break; } if (frame) { } return ret; } Elput_Device * _evdev_device_create(Elput_Seat *seat, struct libinput_device *device) { Elput_Device *edev; edev = calloc(1, sizeof(Elput_Device)); if (!edev) return NULL; edev->seat = seat; edev->device = device; if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD)) { _keyboard_init(seat, NULL); edev->caps |= EVDEV_SEAT_KEYBOARD; } if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) { _pointer_init(seat); edev->caps |= EVDEV_SEAT_POINTER; } if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH)) { _touch_init(seat); edev->caps |= EVDEV_SEAT_TOUCH; } libinput_device_set_user_data(device, edev); libinput_device_ref(edev->device); if (libinput_device_config_tap_get_finger_count(edev->device) > 0) { Eina_Bool enable = EINA_FALSE; enable = libinput_device_config_tap_get_default_enabled(edev->device); libinput_device_config_tap_set_enabled(edev->device, enable); } /* FIXME: Normally we would do a device calibration set here however * that requires Output support. Since this is just an input library, we * may need to add external facing APIs to do calibration. Then a user of * elput would handle outputs, and make calls to calibrate */ return edev; } void _evdev_device_destroy(Elput_Device *edev) { if (!edev) return; if (edev->caps & EVDEV_SEAT_POINTER) _pointer_release(edev->seat); if (edev->caps & EVDEV_SEAT_KEYBOARD) _keyboard_release(edev->seat); if (edev->caps & EVDEV_SEAT_TOUCH) _touch_release(edev->seat); libinput_device_unref(edev->device); eina_stringshare_del(edev->output_name); free(edev); } void _evdev_keyboard_destroy(Elput_Keyboard *kbd) { free((char *)kbd->names.rules); free((char *)kbd->names.model); free((char *)kbd->names.layout); free((char *)kbd->names.variant); free((char *)kbd->names.options); if (kbd->state) xkb_state_unref(kbd->state); if (kbd->info) _keyboard_info_destroy(kbd->info, kbd->external_map); xkb_context_unref(kbd->context); xkb_keymap_unref(kbd->pending_map); free(kbd); } void _evdev_pointer_destroy(Elput_Pointer *ptr) { /* FIXME: destroy any resources inside pointer structure */ free(ptr); } void _evdev_touch_destroy(Elput_Touch *touch) { /* FIXME: destroy any resources inside touch structure */ free(touch); }