void swipe_handle_input(int fd, struct input_event *ev) {
    int abs_store[6] = {0};
    int k;
    set_min_swipe_lengths();

    ioctl(fd, EVIOCGABS(ABS_MT_POSITION_X), abs_store);
    int max_x_touch = abs_store[2];

    ioctl(fd, EVIOCGABS(ABS_MT_POSITION_Y), abs_store);
    int max_y_touch = abs_store[2];

    if(ev->type == EV_ABS && ev->code == ABS_MT_TRACKING_ID) {
        if(in_touch == 0) {
            in_touch = 1;
            reset_gestures();
        } else { // finger lifted
            ev->type = EV_KEY;
            if(slide_right == 1) {
                ev->code = KEY_POWER;
                slide_right = 0;
            } else if(slide_left == 1) {
                ev->code = KEY_BACK;
                slide_left = 0;
            }

            ev->value = 1;
            in_touch = 0;
            reset_gestures();
        }
    } else if(ev->type == EV_ABS && ev->code == ABS_MT_POSITION_X) {
        old_x = touch_x;
        float touch_x_rel = (float)ev->value / (float)max_x_touch;
        touch_x = touch_x_rel * gr_fb_width();

        if(old_x != 0) diff_x += touch_x - old_x;

        if(diff_x > min_x_swipe_px) {
            slide_right = 1;
            reset_gestures();
        } else if(diff_x < -min_x_swipe_px) {
            slide_left = 1;
            reset_gestures();
        }
    } else if(ev->type == EV_ABS && ev->code == ABS_MT_POSITION_Y) {
        old_y = touch_y;
        float touch_y_rel = (float)ev->value / (float)max_y_touch;
        touch_y = touch_y_rel * gr_fb_height();

        if(old_y != 0) diff_y += touch_y - old_y;

        if(diff_y > min_y_swipe_px) {
            ev->code = KEY_VOLUMEDOWN;
            ev->type = EV_KEY;
            reset_gestures();
        } else if(diff_y < -min_y_swipe_px) {
            ev->code = KEY_VOLUMEUP;
            ev->type = EV_KEY;
            reset_gestures();
        }
    }

    return;
}
void ui_init(void) {
    ui_has_initialized = 1;
    gr_init();
    set_min_swipe_lengths();
#ifdef USE_VIRTUAL_KEY
    ui_get_virtualkey_size();
#endif
    ev_init(input_callback, NULL);

    text_col = text_row = 0;
    text_rows = (gr_fb_height() - virtualkey_h) / CHAR_HEIGHT;
    max_menu_rows = text_rows - MIN_LOG_ROWS;
    if (max_menu_rows > MENU_MAX_ROWS)
        max_menu_rows = MENU_MAX_ROWS;
    if (text_rows > MAX_ROWS) text_rows = MAX_ROWS;
    text_top = 1;

    text_cols = gr_fb_width() / CHAR_WIDTH;
    if (text_cols > MAX_COLS - 1) text_cols = MAX_COLS - 1;

    int i;
    for (i = 0; BITMAPS[i].name != NULL; ++i) {
        int result = res_create_surface(BITMAPS[i].name, BITMAPS[i].surface);
        if (result < 0) {
            LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result);
        }
    }

    gProgressBarIndeterminate = malloc(ui_parameters.indeterminate_frames *
                                       sizeof(gr_surface));
    for (i = 0; i < ui_parameters.indeterminate_frames; ++i) {
        char filename[40];
        // "indeterminate01.png", "indeterminate02.png", ...
        sprintf(filename, "indeterminate%02d", i+1);
        int result = res_create_surface(filename, gProgressBarIndeterminate+i);
        if (result < 0) {
            LOGE("Missing bitmap %s\n(Code %d)\n", filename, result);
        }
    }

    if (ui_parameters.installing_frames > 0) {
        gInstallationOverlay = malloc(ui_parameters.installing_frames *
                                      sizeof(gr_surface));
        for (i = 0; i < ui_parameters.installing_frames; ++i) {
            char filename[40];
            // "icon_installing_overlay01.png",
            // "icon_installing_overlay02.png", ...
            sprintf(filename, "icon_installing_overlay%02d", i+1);
            int result = res_create_surface(filename, gInstallationOverlay+i);
            if (result < 0) {
                LOGE("Missing bitmap %s\n(Code %d)\n", filename, result);
            }
        }

        // Adjust the offset to account for the positioning of the
        // base image on the screen.
        if (gBackgroundIcon[BACKGROUND_ICON_INSTALLING] != NULL) {
            gr_surface bg = gBackgroundIcon[BACKGROUND_ICON_INSTALLING];
            ui_parameters.install_overlay_offset_x +=
                (gr_fb_width() - gr_get_width(bg)) / 2;
            ui_parameters.install_overlay_offset_y +=
                (gr_fb_height() - gr_get_height(bg)) / 2;
        }
    } else {
        gInstallationOverlay = NULL;
    }

    char enable_key_repeat[PROPERTY_VALUE_MAX];
    property_get("ro.cwm.enable_key_repeat", enable_key_repeat, "");
    if (!strcmp(enable_key_repeat, "true") || !strcmp(enable_key_repeat, "1")) {
        boardEnableKeyRepeat = 1;

        char key_list[PROPERTY_VALUE_MAX];
        property_get("ro.cwm.repeatable_keys", key_list, "");
        if (strlen(key_list) == 0) {
            boardRepeatableKeys[boardNumRepeatableKeys++] = KEY_UP;
            boardRepeatableKeys[boardNumRepeatableKeys++] = KEY_DOWN;
            boardRepeatableKeys[boardNumRepeatableKeys++] = KEY_VOLUMEUP;
            boardRepeatableKeys[boardNumRepeatableKeys++] = KEY_VOLUMEDOWN;
        } else {
            char *pch = strtok(key_list, ",");
            while (pch != NULL) {
                boardRepeatableKeys[boardNumRepeatableKeys++] = atoi(pch);
                pch = strtok(NULL, ",");
            }
        }
    }

    pthread_t t;
    pthread_create(&t, NULL, progress_thread, NULL);
    pthread_create(&t, NULL, input_thread, NULL);
}