Ejemplo n.º 1
0
static int input_callback(int fd, short revents, void *data)
{
    struct input_event ev;
    int ret;
    int fake_key = 0;
    gr_surface surface = gVirtualKeys;

    ret = ev_get_input(fd, revents, &ev);
    if (ret)
        return -1;

#ifdef BOARD_TOUCH_RECOVERY
    if (touch_handle_input(fd, ev))
      return 0;
#endif

    if (ev.type == EV_SYN) {
        return 0;
    } else if (ev.type == EV_REL) {
        if (ev.code == REL_Y) {
            // accumulate the up or down motion reported by
            // the trackball.  When it exceeds a threshold
            // (positive or negative), fake an up/down
            // key event.
            rel_sum += ev.value;
            if (rel_sum > 3) {
                fake_key = 1;
                ev.type = EV_KEY;
                ev.code = KEY_DOWN;
                ev.value = 1;
                rel_sum = 0;
            } else if (rel_sum < -3) {
                fake_key = 1;
                ev.type = EV_KEY;
                ev.code = KEY_UP;
                ev.value = 1;
                rel_sum = 0;
            }
        }
    } else {
        rel_sum = 0;
    }

    if (ev.type == 3 && ev.code == 48 && ev.value != 0) {
        if (in_touch == 0) {
            in_touch = 1; //starting to track touch...
            reset_gestures();
        }
    } else if (ev.type == 3 && ev.code == 48 && ev.value == 0) {
            //finger lifted! lets run with this
            ev.type = EV_KEY; //touch panel support!!!
            int keywidth = gr_get_width(surface) / 4;
            int keyoffset = (gr_fb_width() - gr_get_width(surface)) / 2;
            if (touch_y > (gr_fb_height() - gr_get_height(surface)) && touch_x > 0) {
                //they lifted in the touch panel region
                if (touch_x < (keywidth + keyoffset)) {
                    //down button
                    ev.code = KEY_DOWN;
                    reset_gestures();
                } else if (touch_x < ((keywidth * 2) + keyoffset)) {
                    //up button
                    ev.code = KEY_UP;
                    reset_gestures();
                } else if (touch_x < ((keywidth * 3) + keyoffset)) {
                    //back button
                    ev.code = KEY_BACK;
                    reset_gestures();
                } else {
                    //enter key
                    ev.code = KEY_ENTER;
                    reset_gestures();
                }
                vibrate(VIBRATOR_TIME_MS);
            }
            if (slide_right == 1) {
                ev.code = KEY_ENTER;
                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 == 3 && ev.code == 53) {
        old_x = touch_x;
        touch_x = ev.value;
        if (old_x != 0)
            diff_x += touch_x - old_x;

	if (touch_y < (gr_fb_height() - gr_get_height(surface))) {
            if (diff_x > (gr_fb_width() / 4)) {
                slide_right = 1;
                reset_gestures();
    } else if(diff_x < ((gr_fb_width() / 4) * -1)) {
                slide_left = 1;
                reset_gestures();
            }
        } else {
            input_buttons();
            //reset_gestures();
        }
    } else if (ev.type == 3 && ev.code == 54) {
        old_y = touch_y;
        touch_y = ev.value;
        if (old_y != 0)
            diff_y += touch_y - old_y;

    if (touch_y < (gr_fb_height() - gr_get_height(surface))) {
            if (diff_y > 25) {
                ev.code = KEY_DOWN;
                ev.type = EV_KEY;
                reset_gestures();
	} else if (diff_y < -25) {
                ev.code = KEY_UP;
                ev.type = EV_KEY;
                reset_gestures();
            }
        } else {
            input_buttons();
            //reset_gestures();
        }
    }

    if (ev.type != EV_KEY || ev.code > KEY_MAX)
        return 0;

    pthread_mutex_lock(&key_queue_mutex);
    if (!fake_key) {
        // our "fake" keys only report a key-down event (no
        // key-up), so don't record them in the key_pressed
        // table.
        key_pressed[ev.code] = ev.value;
    }
    const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
    if (ev.value > 0 && key_queue_len < queue_max) {
        key_queue[key_queue_len++] = ev.code;

        if (boardEnableKeyRepeat) {
            struct timeval now;
            gettimeofday(&now, NULL);

            key_press_time[ev.code] = (now.tv_sec * 1000) + (now.tv_usec / 1000);
            key_last_repeat[ev.code] = 0;
        }

        pthread_cond_signal(&key_queue_cond);
    }
    pthread_mutex_unlock(&key_queue_mutex);

    if (ev.value > 0 && device_toggle_display(key_pressed, ev.code)) {
        pthread_mutex_lock(&gUpdateMutex);
        show_text = !show_text;
        if (show_text) show_text_ever = 1;
        update_screen_locked();
        pthread_mutex_unlock(&gUpdateMutex);
    }

    if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) {
        android_reboot(ANDROID_RB_RESTART, 0, 0);
    }

    return 0;
}
Ejemplo n.º 2
0
// handle the user input events (mainly the touch events) inside the ui handler
static void ui_handle_mouse_input(int* curPos)
{
	pthread_mutex_lock(&key_queue_mutex);
	//In this case MENU_SELECT icon has maximum possible height.
	int menu_max_height = gr_get_height(gMenuIcon[MENU_SELECT]);
	struct { int x; int y; int xL; int xR; } MENU_ICON[] = {
		{  gr_fb_width() - menu_max_height, 7*gr_fb_height()/8, 3*gr_fb_height()/4, 4*gr_fb_height()/4  },
		{  gr_fb_width() - menu_max_height,	5*gr_fb_height()/8, 2*gr_fb_height()/4, 3*gr_fb_height()/4  },
		{  gr_fb_width() - menu_max_height,	3*gr_fb_height()/8, 1*gr_fb_height()/4, 2*gr_fb_height()/4  },
		{  gr_fb_width() - menu_max_height,	1*gr_fb_height()/8, 0*gr_fb_height()/4, 1*gr_fb_height()/4  },
	};

  if (show_menu) {
    if (curPos[0] > 0) {
		int position = gr_fb_height() - curPos[1];
		//ui_print("Pressure:%d\tX:%d\tY:%d\n",mousePos[0],mousePos[1],mousePos[2]);
		pthread_mutex_lock(&gUpdateMutex);
		if(position > MENU_ICON[MENU_BACK].xL && position < MENU_ICON[MENU_BACK].xR && selMenuIcon != MENU_BACK) {
			draw_icon_locked(gMenuIcon[selMenuIcon], MENU_ICON[selMenuIcon].x, MENU_ICON[selMenuIcon].y );
			draw_icon_locked(gMenuIcon[MENU_BACK_M], MENU_ICON[MENU_BACK].x, MENU_ICON[MENU_BACK].y );
			selMenuIcon = MENU_BACK;
			gr_flip();
		}
		else if(position > MENU_ICON[MENU_DOWN].xL && position < MENU_ICON[MENU_DOWN].xR && selMenuIcon != MENU_DOWN) {			
			draw_icon_locked(gMenuIcon[selMenuIcon], MENU_ICON[selMenuIcon].x, MENU_ICON[selMenuIcon].y );
			draw_icon_locked(gMenuIcon[MENU_DOWN_M], MENU_ICON[MENU_DOWN].x, MENU_ICON[MENU_DOWN].y);
			selMenuIcon = MENU_DOWN;
			gr_flip();
		}
		else if(position > MENU_ICON[MENU_UP].xL && position < MENU_ICON[MENU_UP].xR && selMenuIcon != MENU_UP) {
			draw_icon_locked(gMenuIcon[selMenuIcon], MENU_ICON[selMenuIcon].x, MENU_ICON[selMenuIcon].y );			
			draw_icon_locked(gMenuIcon[MENU_UP_M], MENU_ICON[MENU_UP].x, MENU_ICON[MENU_UP].y );
			selMenuIcon = MENU_UP;
			gr_flip();
		}
		else if(position > MENU_ICON[MENU_SELECT].xL && position < MENU_ICON[MENU_SELECT].xR && selMenuIcon != MENU_SELECT) {
			draw_icon_locked(gMenuIcon[selMenuIcon], MENU_ICON[selMenuIcon].x, MENU_ICON[selMenuIcon].y );			
			draw_icon_locked(gMenuIcon[MENU_SELECT_M], MENU_ICON[MENU_SELECT].x, MENU_ICON[MENU_SELECT].y );
			selMenuIcon = MENU_SELECT;
			gr_flip();
		}
		key_queue_len_back = key_queue_len;
		pthread_mutex_unlock(&gUpdateMutex);
     }
  }
  pthread_mutex_unlock(&key_queue_mutex);
}
Ejemplo n.º 3
0
// Redraw everything on the screen.  Does not flip pages.
// Should only be called with gUpdateMutex locked.
static void draw_screen_locked(void)
{
    if (!ui_has_initialized) return;
    draw_background_locked(gCurrentIcon);
    draw_progress_locked();

    if (show_text) {
        // don't "disable" the background anymore with this...
        // gr_color(0, 0, 0, 160);
        // gr_fill(0, 0, gr_fb_width(), gr_fb_height());

	gr_surface surface = gVirtualKeys;
        int total_rows = (gr_fb_height() / CHAR_HEIGHT) - (gr_get_height(surface) / CHAR_HEIGHT) - 1;
        int i = 0;
        int j = 0;
        int offset = 0;         // offset of separating bar under menus
        int row = 0;            // current row that we are drawing on
	if (show_menu) {
            gr_color(MENU_TEXT_COLOR);
            int batt_level = 0;
            batt_level = get_batt_stats();
            if (batt_level < 21) {
                gr_color(255, 0, 0, 255);
            }
            char batt_text[40];
            sprintf(batt_text, "[%d%%]", batt_level);
            draw_text_line(0, batt_text, RIGHT_ALIGN);

            gr_color(MENU_TEXT_COLOR);
            gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
                    gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);

            gr_color(HEADER_TEXT_COLOR);
            for (i = 0; i < menu_top; ++i) {
                draw_text_line(i, menu[i], LEFT_ALIGN);
                row++;
            }

            if (menu_items - menu_show_start + menu_top >= max_menu_rows)
                j = max_menu_rows - menu_top;
            else
                j = menu_items - menu_show_start;

            gr_color(MENU_TEXT_COLOR);
            for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                if (i == menu_top + menu_sel) {
                    gr_color(255, 255, 255, 255);
                    draw_text_line(i - menu_show_start , menu[i], LEFT_ALIGN);
                    gr_color(MENU_TEXT_COLOR);
                } else {
                    gr_color(MENU_TEXT_COLOR);
                    draw_text_line(i - menu_show_start, menu[i], LEFT_ALIGN);
                }
                row++;
                if (row >= max_menu_rows)
                    break;
            }

            if (menu_items <= max_menu_rows)
                offset = 0;

            gr_fill(0, (row-offset)*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
                    gr_fb_width(), (row-offset)*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
        }

        gr_color(NORMAL_TEXT_COLOR);
        int cur_row = text_row;
        int available_rows = total_rows - row - 1;
        int start_row = row + 1;
        if (available_rows < MAX_ROWS)
            cur_row = (cur_row + (MAX_ROWS - available_rows)) % MAX_ROWS;
        else
            start_row = total_rows - MAX_ROWS;

        int r;
        for (r = 0; r < (available_rows < MAX_ROWS ? available_rows : MAX_ROWS); r++) {
            draw_text_line(start_row + r, text[(cur_row + r) % MAX_ROWS], LEFT_ALIGN);
        }
    }
    draw_virtualkeys_locked(); //added to draw the virtual keys
}
Ejemplo n.º 4
0
static int input_callback(int fd, short revents, void *data) {
    struct input_event ev;
    int ret;
    int fake_key = 0;

    ret = ev_get_input(fd, revents, &ev);
    if (ret)
        return -1;

    input_device dev;
    dev.fd = fd;
    if(!dev.touch_calibrated)
        dev.touch_calibrated = calibrate_touch(&dev);

    if (ev.type == EV_SYN) {
        if (ev.code == SYN_MT_REPORT) {
            dev.saw_mt_report = 1;
            if (!dev.saw_mt_tracking_id) {
                if (dev.saw_pos_x && dev.saw_pos_y) {
                    dev.saw_pos_x = 0;
                    dev.saw_pos_y = 0;
                } else
                    handle_release(&dev, &ev);
            }
        }
    } else if (ev.type == EV_REL) {
        if (ev.code == REL_Y) {
            // accumulate the up or down motion reported by
            // the trackball.  When it exceeds a threshold
            // (positive or negative), fake an up/down
            // key event.
            rel_sum += ev.value;
            if (rel_sum > 3) {
                fake_key = 1;
                ev.type = EV_KEY;
                ev.code = KEY_DOWN;
                ev.value = 1;
                rel_sum = 0;
            } else if (rel_sum < -3) {
                fake_key = 1;
                ev.type = EV_KEY;
                ev.code = KEY_UP;
                ev.value = 1;
                rel_sum = 0;
            }
        }
    } else if (ev.type == EV_ABS) {
        switch(ev.code){
            case ABS_MT_SLOT:
                dev.slot_current = ev.value;
                break;
            case ABS_MT_TRACKING_ID:
                dev.saw_mt_tracking_id = 1;
                dev.tracking_id = ev.value;
                if (dev.tracking_id == -1 && dev.slot_current == 0)
                    handle_release(&dev, &ev);
                break;
            case ABS_MT_POSITION_X:
                dev.saw_pos_x = 1;
                if (dev.slot_current != 0) break;
                if(dev.touch_start.x == 0)
                    dev.touch_start.x = dev.touch_pos.x;
                float touch_rel = (float)ev.value / ((float)dev.touch_max.x - (float)dev.touch_min.x);
                dev.touch_pos.x = touch_rel * gr_fb_width();
                if (dev.touch_start.x == 0) break; //first touch.
                diff_x += dev.touch_pos.x - dev.touch_start.x;
                if (abs(diff_x) > abs(diff_y) && dev.touch_pos.y < (gr_fb_height() - virtualkey_h)) {
                    if(diff_x > min_x_swipe_px) {
                        dev.slide_right = 1;
                    } else if (diff_x < -min_x_swipe_px) {
                        dev.slide_left = 1;
                    }
                }
                break;
            case ABS_MT_POSITION_Y:
                dev.saw_pos_y = 1;
                if (dev.slot_current != 0) break;
                if(dev.touch_start.y == 0)
                    dev.touch_start.y = dev.touch_pos.y;
                touch_rel = (float)ev.value / ((float)dev.touch_max.y - (float)dev.touch_min.y);
                dev.touch_pos.y = touch_rel * gr_fb_height();
#ifdef USE_VIRTUAL_KEY
                ui_get_virtualkey_pressed(&dev);
#endif
                if (dev.touch_start.y == 0) break; //first touch.
                diff_y += dev.touch_pos.y - dev.touch_start.y;
                if (abs(diff_y) >= abs(diff_x) && dev.touch_pos.y < (gr_fb_height() - virtualkey_h)) {
                    if (diff_y > min_y_swipe_px) {
                        ev.type = EV_KEY;
                        ev.code = KEY_VOLUMEDOWN;
                        ev.value = 2;
                        reset_touch(&dev);
                    } else if (diff_y < -min_y_swipe_px) {
                        ev.type = EV_KEY;
                        ev.code = KEY_VOLUMEUP;
                        ev.value = 2;
                        reset_touch(&dev);
                    }
                }
                break;
            default:
                break;
        }
    } else if (ev.type == EV_KEY) {
        if (dev.saw_mt_report && dev.saw_mt_tracking_id && ev.code == BTN_TOUCH && ev.value == 0)
            handle_release(&dev, &ev);
    } else {
        rel_sum = 0;
    }

    if (ev.type != EV_KEY || ev.code > KEY_MAX)
        return 0;

    if (ev.value == 2) {
        boardEnableKeyRepeat = 0;
    }

    pthread_mutex_lock(&key_queue_mutex);
    if (!fake_key) {
        // our "fake" keys only report a key-down event (no
        // key-up), so don't record them in the key_pressed
        // table.
        key_pressed[ev.code] = ev.value;
    }
    const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
    if (ev.value > 0 && key_queue_len < queue_max) {
        key_queue[key_queue_len++] = ev.code;

        if (boardEnableKeyRepeat) {
            struct timeval now;
            gettimeofday(&now, NULL);

            key_press_time[ev.code] = (now.tv_sec * 1000) + (now.tv_usec / 1000);
            key_last_repeat[ev.code] = 0;
        }

        pthread_cond_signal(&key_queue_cond);
    }
    pthread_mutex_unlock(&key_queue_mutex);

    if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) {
        reboot_main_system(ANDROID_RB_RESTART, 0, 0);
    }

    return 0;
}
Ejemplo n.º 5
0
// Redraw everything on the screen.  Does not flip pages.
// Should only be called with gUpdateMutex locked.
static void draw_screen_locked(void)
{
    if (!ui_has_initialized) return;

	//In this case MENU_SELECT icon has maximum possible height.
	int menu_max_height = gr_get_height(gMenuIcon[MENU_SELECT]);
	struct { int x; int y; } MENU_ICON[] = {
		{  gr_fb_width() - menu_max_height, 7*gr_fb_height()/8 },
		{  gr_fb_width() - menu_max_height,	5*gr_fb_height()/8 },
		{  gr_fb_width() - menu_max_height,	3*gr_fb_height()/8 },
		{  gr_fb_width() - menu_max_height,	1*gr_fb_height()/8 }, 
	};

    draw_background_locked(gCurrentIcon);
    draw_progress_locked();

    if (show_text) {
        gr_color(0, 0, 0, 160);
        gr_fill(0, 0, gr_fb_width(), gr_fb_height());

        int i = 0;
        int j = 0;
        int row = 0;            // current row that we are drawing on
        if (show_menu) {

			draw_icon_locked(gMenuIcon[MENU_BACK], MENU_ICON[MENU_BACK].x, MENU_ICON[MENU_BACK].y );
			draw_icon_locked(gMenuIcon[MENU_DOWN], MENU_ICON[MENU_DOWN].x, MENU_ICON[MENU_DOWN].y);
			draw_icon_locked(gMenuIcon[MENU_UP], MENU_ICON[MENU_UP].x, MENU_ICON[MENU_UP].y );
			draw_icon_locked(gMenuIcon[MENU_SELECT], MENU_ICON[MENU_SELECT].x, MENU_ICON[MENU_SELECT].y );
            gr_color(MENU_TEXT_COLOR);
            gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
                    gr_fb_width()-menu_max_height*2, (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);

            gr_color(HEADER_TEXT_COLOR);
            for (i = 0; i < menu_top; ++i) {
                draw_text_line(i, menu[i]);
                row++;
            }

            if (menu_items - menu_show_start + menu_top >= MAX_ROWS)
                j = MAX_ROWS - menu_top;
            else
                j = menu_items - menu_show_start;

            gr_color(MENU_TEXT_COLOR);
            for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                if (i == menu_top + menu_sel) {
                    gr_color(255, 255, 255, 255);
                    draw_text_line(i - menu_show_start , menu[i]);
                    gr_color(MENU_TEXT_COLOR);
                } else {
                    gr_color(MENU_TEXT_COLOR);
                    draw_text_line(i - menu_show_start, menu[i]);
                }
                row++;
            }
            gr_fill(0, row*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
                    gr_fb_width()-menu_max_height*2, row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
        }

        gr_color(NORMAL_TEXT_COLOR);
        for (; row < text_rows; ++row) {
            draw_text_line(row, text[(row+text_top) % text_rows]);
        }
    }
}
Ejemplo n.º 6
0
/* Returns non-zero when the event should be consumed */
static int vk_modify(struct ev *e, struct input_event *ev)
{
    static int downX = -1, downY = -1;
    static int discard = 0;
    static int last_virt_key = 0;
    static int lastWasSynReport = 0;
    static int touchReleaseOnNextSynReport = 0;
	static int use_tracking_id_negative_as_touch_release = 0; // On some devices, type: 3  code: 39  value: -1, aka EV_ABS ABS_MT_TRACKING_ID -1 indicates a true touch release
    int i;
    int x, y;

    // This is used to ditch useless event handlers, like an accelerometer
    if (e->ignored)     return 1;

    if (ev->type == EV_REL && ev->code == REL_Z)
    {
        // This appears to be an accelerometer or another strange input device. It's not the touchscreen.
#ifdef _EVENT_LOGGING
        printf("EV: Device disabled due to non-touchscreen messages.\n");
#endif
        e->ignored = 1;
        return 1;
    }

#ifdef _EVENT_LOGGING
    printf("EV: %s => type: %x  code: %x  value: %d\n", e->deviceName, ev->type, ev->code, ev->value);
#endif

	// Handle keyboard events, value of 1 indicates key down, 0 indicates key up
	if (ev->type == EV_KEY) {
		return 0;
	}

    if (ev->type == EV_ABS) {
        switch (ev->code) {

        case ABS_X: //00
            e->p.synced |= 0x01;
            e->p.x = ev->value;
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS  ABS_X  %d\n", e->deviceName, ev->value);
#endif
            break;

        case ABS_Y: //01
            e->p.synced |= 0x02;
            e->p.y = ev->value;
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS  ABS_Y  %d\n", e->deviceName, ev->value);
#endif
            break;

        case ABS_MT_POSITION: //2a
            e->mt_p.synced = 0x03;
            if (ev->value == (1 << 31))
            {
                e->mt_p.x = 0;
                e->mt_p.y = 0;
                lastWasSynReport = 1;
            }
            else
            {
                lastWasSynReport = 0;
                e->mt_p.x = (ev->value & 0x7FFF0000) >> 16;
                e->mt_p.y = (ev->value & 0xFFFF);
            }
            break;

        case ABS_MT_TOUCH_MAJOR: //30
            if (ev->value == 0)
            {
#ifndef TW_IGNORE_MAJOR_AXIS_0
                // We're in a touch release, although some devices will still send positions as well
                e->mt_p.x = 0;
                e->mt_p.y = 0;
                touchReleaseOnNextSynReport = 1;
#endif
            }
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS  ABS_MT_TOUCH_MAJOR  %d\n", e->deviceName, ev->value);
#endif
            break;

		case ABS_MT_PRESSURE: //3a
                    if (ev->value == 0)
            {
                // We're in a touch release, although some devices will still send positions as well
                e->mt_p.x = 0;
                e->mt_p.y = 0;
                touchReleaseOnNextSynReport = 1;
            }
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS  ABS_MT_PRESSURE  %d\n", e->deviceName, ev->value);
#endif
            break;

		case ABS_MT_POSITION_X: //35
            e->mt_p.synced |= 0x01;
            e->mt_p.x = ev->value;
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS  ABS_MT_POSITION_X  %d\n", e->deviceName, ev->value);
#endif
            break;

        case ABS_MT_POSITION_Y: //36
            e->mt_p.synced |= 0x02;
            e->mt_p.y = ev->value;
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS  ABS_MT_POSITION_Y  %d\n", e->deviceName, ev->value);
#endif
            break;

        case ABS_MT_TOUCH_MINOR: //31
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS ABS_MT_TOUCH_MINOR %d\n", e->deviceName, ev->value);
#endif
            break;

        case ABS_MT_WIDTH_MAJOR: //32
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS ABS_MT_WIDTH_MAJOR %d\n", e->deviceName, ev->value);
#endif
            break;

        case ABS_MT_WIDTH_MINOR: //33
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS ABS_MT_WIDTH_MINOR %d\n", e->deviceName, ev->value);
#endif
            break;

        case ABS_MT_TRACKING_ID: //39
            if (ev->value < 0) {
                e->mt_p.x = 0;
                e->mt_p.y = 0;
                touchReleaseOnNextSynReport = 2;
                use_tracking_id_negative_as_touch_release = 1;
#ifdef _EVENT_LOGGING
                if (use_tracking_id_negative_as_touch_release)
                    printf("using ABS_MT_TRACKING_ID value -1 to indicate touch releases\n");
#endif
            }
#ifdef _EVENT_LOGGING
            printf("EV: %s => EV_ABS ABS_MT_TRACKING_ID %d\n", e->deviceName, ev->value);
#endif
            break;

#ifdef _EVENT_LOGGING
        // These are for touch logging purposes only
        case ABS_MT_ORIENTATION: //34
            printf("EV: %s => EV_ABS ABS_MT_ORIENTATION %d\n", e->deviceName, ev->value);
			return 1;
            break;

		case ABS_MT_TOOL_TYPE: //37
            LOGI("EV: %s => EV_ABS ABS_MT_TOOL_TYPE %d\n", e->deviceName, ev->value);
			return 1;
            break;

        case ABS_MT_BLOB_ID: //38
            printf("EV: %s => EV_ABS ABS_MT_BLOB_ID %d\n", e->deviceName, ev->value);
			return 1;
            break;

		case ABS_MT_DISTANCE: //3b
            printf("EV: %s => EV_ABS ABS_MT_DISTANCE %d\n", e->deviceName, ev->value);
			return 1;
            break;
#endif

        default:
            // This is an unhandled message, just skip it
            return 1;
        }

        if (ev->code != ABS_MT_POSITION)
        {
            lastWasSynReport = 0;
            return 1;
        }
    }

    // Check if we should ignore the message
    if (ev->code != ABS_MT_POSITION && (ev->type != EV_SYN || (ev->code != SYN_REPORT && ev->code != SYN_MT_REPORT)))
    {
        lastWasSynReport = 0;
        return 0;
    }

#ifdef _EVENT_LOGGING
    if (ev->type == EV_SYN && ev->code == SYN_REPORT)       printf("EV: %s => EV_SYN  SYN_REPORT\n", e->deviceName);
    if (ev->type == EV_SYN && ev->code == SYN_MT_REPORT)    printf("EV: %s => EV_SYN  SYN_MT_REPORT\n", e->deviceName);
#endif

    // Discard the MT versions
    if (ev->code == SYN_MT_REPORT)      return 0;

    if (((lastWasSynReport == 1 || touchReleaseOnNextSynReport == 1) && !use_tracking_id_negative_as_touch_release) || (use_tracking_id_negative_as_touch_release && touchReleaseOnNextSynReport == 2))
    {
        // Reset the value
        touchReleaseOnNextSynReport = 0;

        // We are a finger-up state
        if (!discard)
        {
            // Report the key up
            ev->type = EV_ABS;
            ev->code = 0;
            ev->value = (downX << 16) | downY;
        }
        downX = -1;
        downY = -1;
        if (discard)
        {
            discard = 0;

            // Send the keyUp event
            ev->type = EV_KEY;
            ev->code = last_virt_key;
            ev->value = 0;
        }
        return 0;
    }
    lastWasSynReport = 1;

    // Retrieve where the x,y position is
    if (e->p.synced & 0x03)
    {
        vk_tp_to_screen(&e->p, &x, &y);
    }
    else if (e->mt_p.synced & 0x03)
    {
        vk_tp_to_screen(&e->mt_p, &x, &y);
    }
    else
    {
        // We don't have useful information to convey
        return 1;
    }

#ifdef RECOVERY_TOUCHSCREEN_SWAP_XY
    x ^= y;
    y ^= x;
    x ^= y;
#endif
#ifdef RECOVERY_TOUCHSCREEN_FLIP_X
    x = gr_fb_width() - x;
#endif
#ifdef RECOVERY_TOUCHSCREEN_FLIP_Y
    y = gr_fb_height() - y;
#endif

#ifdef _EVENT_LOGGING
    printf("EV: x: %d  y: %d\n", x, y);
#endif

    // Clear the current sync states
    e->p.synced = e->mt_p.synced = 0;

    // If we have nothing useful to report, skip it
    if (x == -1 || y == -1)     return 1;

    // On first touch, see if we're at a virtual key
    if (downX == -1)
    {
        // Attempt mapping to virtual key
        for (i = 0; i < e->vk_count; ++i)
        {
            int xd = ABS(e->vks[i].centerx - x);
            int yd = ABS(e->vks[i].centery - y);

            if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2)
            {
                ev->type = EV_KEY;
                ev->code = e->vks[i].scancode;
                ev->value = 1;

                last_virt_key = e->vks[i].scancode;

                vibrate(VIBRATOR_TIME_MS);

                // Mark that all further movement until lift is discard,
                // and make sure we don't come back into this area
                discard = 1;
                downX = 0;
                return 0;
            }
        }
    }

    // If we were originally a button press, discard this event
    if (discard)
    {
        return 1;
    }

    // Record where we started the touch for deciding if this is a key or a scroll
    downX = x;
    downY = y;

    ev->type = EV_ABS;
    ev->code = 1;
    ev->value = (x << 16) | y;
    return 0;
}
Ejemplo n.º 7
0
/* Returns non-zero when the event should be consumed */
static int vk_modify(struct ev *e, struct input_event *ev)
{
    int i;
    int x, y;

    if (ev->type == EV_KEY) {
        if (ev->code == BTN_TOUCH)
            e->p.pressed = ev->value;
        return 0;
    }

    if (ev->type == EV_ABS) {
        switch (ev->code) {
        case ABS_X:
            e->p.x = ev->value;
            return !vk_inside_display(e->p.x, &e->p.xi, gr_fb_width());
        case ABS_Y:
            e->p.y = ev->value;
            return !vk_inside_display(e->p.y, &e->p.yi, gr_fb_height());
        case ABS_MT_POSITION_X:
            if (e->mt_idx) return 1;
            e->mt_p.x = ev->value;
            return !vk_inside_display(e->mt_p.x, &e->mt_p.xi, gr_fb_width());
        case ABS_MT_POSITION_Y:
            if (e->mt_idx) return 1;
            e->mt_p.y = ev->value;
            return !vk_inside_display(e->mt_p.y, &e->mt_p.yi, gr_fb_height());
        case ABS_MT_TOUCH_MAJOR:
            if (e->mt_idx) return 1;
            if (e->sent)
                e->mt_p.pressed = (ev->value > 0);
            else
                e->mt_p.pressed = (ev->value > PRESS_THRESHHOLD);
            return 0;
        }

        return 0;
    }

    if (ev->type != EV_SYN)
        return 0;

    if (ev->code == SYN_MT_REPORT) {
        /* Ignore the rest of the points */
        ++e->mt_idx;
        return 1;
    }
    if (ev->code != SYN_REPORT)
        return 0;

    /* Report complete */

    e->mt_idx = 0;

    if (!e->p.pressed && !e->mt_p.pressed) {
        /* No touch */
        e->sent = 0;
        return 0;
    }

    if (!(e->p.pressed && vk_tp_to_screen(&e->p, &x, &y)) &&
            !(e->mt_p.pressed && vk_tp_to_screen(&e->mt_p, &x, &y))) {
        /* No touch inside vk area */
        return 0;
    }

    if (e->sent) {
        /* We've already sent a fake key for this touch */
        return 1;
    }

    /* The screen is being touched on the vk area */
    e->sent = 1;

    for (i = 0; i < e->vk_count; ++i) {
        int xd = ABS(e->vks[i].centerx - x);
        int yd = ABS(e->vks[i].centery - y);
        if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2) {
            /* Fake a key event */
            ev->type = EV_KEY;
            ev->code = e->vks[i].scancode;
            ev->value = 1;

            vibrate(VIBRATOR_TIME_MS);
            return 0;
        }
    }

    return 1;
}
Ejemplo n.º 8
0
void gr_noclip()
{
    GGLContext *gl = gr_context;
    gl->scissor(gl, 0, 0, gr_fb_width(), gr_fb_height());
    gl->disable(gl, GGL_SCISSOR_TEST);
}
Ejemplo n.º 9
0
// Redraw everything on the screen.  Does not flip pages.
// Should only be called with gUpdateMutex locked.
static void draw_screen_locked(void)
{
    if (!ui_has_initialized) return;
    draw_background_locked(gCurrentIcon);
    draw_progress_locked();

    if (show_text) {
        // don't "disable" the background anymore with this...
        // gr_color(0, 0, 0, 160);
        // gr_fill(0, 0, gr_fb_width(), gr_fb_height());

        int total_rows = gr_fb_height() / CHAR_HEIGHT;
        int i = 0;
        int j = 0;
        int row = 0;            // current row that we are drawing on
        if (show_menu) {
#ifndef BOARD_TOUCH_RECOVERY
            gr_color(MENU_TEXT_COLOR);

    // 添加电量时间显示
    int batt_level = 0;
        batt_level = get_batt_stats();
            
            if(batt_level < 20) {
                gr_color(255, 0, 0, 255);
            }
            
      struct tm *current;
      time_t now;
      now = time(NULL) + (3600 * 8); // add 8 hours
      current = localtime(&now);
            
            char batt_text[40];
            sprintf(batt_text, "[%d%% %02D:%02D]", batt_level, current->tm_hour, current->tm_min);
            if (now == NULL) { // just in case
        sprintf(batt_text, "[%d%%]", batt_level);
      }

            gr_color(MENU_TEXT_COLOR);
            draw_text_line(0, batt_text, RIGHT_ALIGN);

            gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
                    gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);

            gr_color(HEADER_TEXT_COLOR);
            for (i = 0; i < menu_top; ++i) {

                // 添加电量时间显示
                // draw_text_line(i, menu[i]);
                draw_text_line(i, menu[i], LEFT_ALIGN);

                row++;
            }

            if (menu_items - menu_show_start + menu_top >= max_menu_rows)
                j = max_menu_rows - menu_top;
            else
                j = menu_items - menu_show_start;

            gr_color(MENU_TEXT_COLOR);
            for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                if (i == menu_top + menu_sel) {
                    gr_color(255, 255, 255, 255);

                    // 添加电量时间显示
                    // draw_text_line(i - menu_show_start , menu[i]);
                    draw_text_line(i - menu_show_start , menu[i], LEFT_ALIGN);

                    gr_color(MENU_TEXT_COLOR);
                } else {
                    gr_color(MENU_TEXT_COLOR);

                    // 添加电量时间显示
                    // draw_text_line(i - menu_show_start, menu[i]);
                    draw_text_line(i - menu_show_start, menu[i], LEFT_ALIGN);

                }
                row++;
                if (row >= max_menu_rows)
                    break;
            }

            gr_fill(0, row*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
                    gr_fb_width(), row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
#else
            row = draw_touch_menu(menu, menu_items, menu_top, menu_sel, menu_show_start);
#endif
        }

        gr_color(NORMAL_TEXT_COLOR);
        int cur_row = text_row;
        int available_rows = total_rows - row - 1;
        int start_row = row + 1;
        if (available_rows < MAX_ROWS)
            cur_row = (cur_row + (MAX_ROWS - available_rows)) % MAX_ROWS;
        else
            start_row = total_rows - MAX_ROWS;

        int r;
        for (r = 0; r < (available_rows < MAX_ROWS ? available_rows : MAX_ROWS); r++) {

        // 添加电量时间显示
        // draw_text_line(start_row + r, text[(cur_row + r) % MAX_ROWS]);
           draw_text_line(start_row + r, text[(cur_row + r) % MAX_ROWS], LEFT_ALIGN);

        }
    }
}
int ScreenRecoveryUI::GetProgressBaseline() {
    return gr_fb_height() - PixelsFromDp(is_large_ ? 340 : 194) - gr_get_height(progressBarFill);
}
Ejemplo n.º 11
0
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;
}
// Redraw everything on the screen.  Does not flip pages.
// Should only be called with gUpdateMutex locked.
// joeykrim-all the LOGI help me keep my sanity
static void draw_screen_locked(void)
{
    draw_background_locked(gCurrentIcon);
    draw_progress_locked();

    if (show_text) {
        gr_color(0, 0, 0, 160);
        gr_fill(0, 0, gr_fb_width(), gr_fb_height());

        int i = 0, j = 0;
        int k = menu_top + 1; //counter for bottom horizontal text line location
        if (show_menu) {

        //LOGI("text_rows: %i\n", text_rows);
        //LOGI("menu_items: %i\n", menu_items);
        //LOGI("menu_top: %i\n", menu_top);
        //LOGI("menu_show_start: %i\n", menu_show_start);
            //menu line item selection highlight draws
            gr_color(mihc.r, mihc.g, mihc.b, mihc.a);
            gr_fill(0, (menu_top + menu_sel - menu_show_start+1) * CHAR_HEIGHT,
                    gr_fb_width(), (menu_top + menu_sel - menu_show_start + 2)*CHAR_HEIGHT+1);

            //draw semi-static headers
            for (i = 0; i < menu_top; ++i) {
                gr_color(htc.r, htc.g, htc.b, htc.a);
                draw_text_line(i, menu[i]);
                //LOGI("Semi-static headers internal counter i: %i\n", i);
            }

            //LOGI("Drawing horizontal start bar at k and k = %i\n", k);
            gr_color(mhebc.r, mhebc.g, mhebc.b, mhebc.a);
            //draws horizontal line at bottom of the menu
            gr_fill(0, (k-1)*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
                    gr_fb_width(), (k-1)*CHAR_HEIGHT+CHAR_HEIGHT/2+1);

            //adjust counter for current position of selection and menu display starting point
            if (menu_items - menu_show_start + menu_top >= text_rows){
                j = text_rows - menu_top;
                //LOGI("j = text_rows - mneu_top and j = %i\n", j);
           } else {
                j = menu_items - menu_show_start;
                //LOGI("j = mneu_items - menu_show_start and j = %i\n", j);
           }
            //LOGI("outside draw menu items for loop and i goes until limit. limit-menu_show_start + menu_top + j = %i\n", menu_show_start + menu_top + j);
            //draw menu items dynamically based on current menu starting position, menu selection point and headers
             for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                //LOGI("inside draw menu items for loop and i = %i\n", i);
                if (i == menu_top + menu_sel) {
                    gr_color(miwhc.r, miwhc.g, miwhc.b, miwhc.a);
                    //LOGI("draw_text_line -menu_item_when_highlighted_color- at i + 1= %i\n", i+1);
                    draw_text_line(i - menu_show_start +1, menu[i]);
                } else {
                    gr_color(mtc.r, mtc.g, mtc.b, mtc.a);
                    //LOGI("draw_text_line -menu_item_color- at i + 1= %i\n", i+1);
                    draw_text_line(i - menu_show_start +1, menu[i]);
                }
                //LOGI("inside draw menu items for loop and k = %i\n", k);
                k++;
            }
            //LOGI("drawing horizontal end bar at k and k = %i\n", k);
            gr_color(mhebc.r, mhebc.g, mhebc.b, mhebc.a);
            //draws horizontal line at bottom of the menu
            gr_fill(0, k*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
                    gr_fb_width(), k*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
        }

        k++; //keep ui_print below menu items display
        gr_color(upc.r, upc.g, upc.b, upc.a); //called by at least ui_print
        for (; k < text_rows; ++k) {
            draw_text_line(k, text[(k+text_top) % text_rows]);
        }
    }
}
// Redraw everything on the screen.  Does not flip pages.
// Should only be called with gUpdateMutex locked.
static void draw_screen_locked(void)
{
    draw_background_locked(gCurrentIcon);
    draw_progress_locked();

    if (show_text) {
        gr_color(0, 0, 0, 160);
        gr_fill(0, 0, gr_fb_width(), gr_fb_height());

        int i = 0;
        int j = 0;
        int row = 0;
        if (show_menu) {

            gr_color(MENU_TEXT_COLOR);

            gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
                    gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);

            for (i = 0; i < menu_top; ++i) {
                draw_text_line(i, menu[i]);
                row++;
            }

            if (menu_items - menu_show_start + menu_top >= MAX_ROWS)
                j = MAX_ROWS - menu_top;
            else
                j = menu_items - menu_show_start;

            gr_color(MENU_TEXT_COLOR);

            for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                if (i == menu_top + menu_sel) {

		    gr_color(SELECTED_TEXT_COLOR);

                    draw_text_line(i - menu_show_start, menu[i]);
	
	            gr_color(MENU_TEXT_COLOR);

                } else {

	            gr_color(MENU_TEXT_COLOR);

                    draw_text_line(i - menu_show_start, menu[i]);
                }
		row++;
            }
            gr_fill(0, row*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
                    gr_fb_width(), row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
        }

        gr_color(NORMAL_TEXT_COLOR);


	row++;
        for (; row < text_rows; ++row) {
            draw_text_line(row, text[(row+text_top) % text_rows]);
        }
    }
}
Ejemplo n.º 14
0
// Redraw everything on the screen.  Does not flip pages.
// Should only be called with gUpdateMutex locked.
void draw_screen_locked(void)
{
	if (!ui_has_initialized) return;
#ifdef BUILD_IN_LANDSCAPE
		//In this case MENU_SELECT icon has maximum possible height.
		int menu_max_height = gr_get_height(gMenuIcon[MENU_SELECT]);
		struct { int x; int y; } MENU_ICON[] = {
			{  gr_fb_width() - menu_max_height, 7*gr_fb_height()/8 },
			{  gr_fb_width() - menu_max_height,	5*gr_fb_height()/8 },
			{  gr_fb_width() - menu_max_height,	3*gr_fb_height()/8 },
			{  gr_fb_width() - menu_max_height,	1*gr_fb_height()/8 }, 
#else
//ToDo: Following structure should be global
		struct { int x; int y; int xL; int xR; } MENU_ICON[] = {
			{  get_menu_icon_info(MENU_BACK,MENU_ICON_X),	get_menu_icon_info(MENU_BACK,MENU_ICON_Y), get_menu_icon_info(MENU_BACK,MENU_ICON_XL), get_menu_icon_info(MENU_BACK,MENU_ICON_XR) },
			{  get_menu_icon_info(MENU_DOWN,MENU_ICON_X),	get_menu_icon_info(MENU_DOWN,MENU_ICON_Y), get_menu_icon_info(MENU_DOWN,MENU_ICON_XL), get_menu_icon_info(MENU_DOWN,MENU_ICON_XR) },
			{  get_menu_icon_info(MENU_UP,MENU_ICON_X),	get_menu_icon_info(MENU_UP,MENU_ICON_Y), get_menu_icon_info(MENU_UP,MENU_ICON_XL), get_menu_icon_info(MENU_UP,MENU_ICON_XR) },
			{  get_menu_icon_info(MENU_SELECT,MENU_ICON_X),	get_menu_icon_info(MENU_SELECT,MENU_ICON_Y), get_menu_icon_info(MENU_SELECT,MENU_ICON_XL), get_menu_icon_info(MENU_SELECT,MENU_ICON_XR) },
#endif
		};

    		draw_background_locked(gCurrentIcon);
    		draw_progress_locked();

		if (show_text) {
	        	gr_color(0, 0, 0, 160);
        		gr_fill(0, 0, gr_fb_width(), gr_fb_height());
        		
        		int total_rows = gr_fb_height() / CHAR_HEIGHT+1;
        		int i = 0;
        		int j = 0;
        		int row = 0;            // current row that we are drawing on
        		if (show_menu) {
				draw_icon_locked(gMenuIcon[MENU_BACK], MENU_ICON[MENU_BACK].x, MENU_ICON[MENU_BACK].y );
				draw_icon_locked(gMenuIcon[MENU_DOWN], MENU_ICON[MENU_DOWN].x, MENU_ICON[MENU_DOWN].y);
				draw_icon_locked(gMenuIcon[MENU_UP], MENU_ICON[MENU_UP].x, MENU_ICON[MENU_UP].y );
				draw_icon_locked(gMenuIcon[MENU_SELECT], MENU_ICON[MENU_SELECT].x, MENU_ICON[MENU_SELECT].y ); 
				            // Setup our text colors
            			    gr_color(UICOLOR0, UICOLOR1, UICOLOR2, 255);
				gr_color(UICOLOR0, UICOLOR1, UICOLOR2, 255);

            		gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
#ifdef BUILD_IN_LANDSCAPE
					gr_fb_width()-menu_max_height*2, (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);
#else
					gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);
#endif


            			gr_color(HEADER_TEXT_COLOR);
            			for (i = 0; i < menu_top; ++i) {
					draw_text_line(i, menu[i], LEFT_ALIGN);
                			row++;
            			}

	            		if (menu_items - menu_show_start + menu_top >= MAX_ROWS)
                			j = MAX_ROWS - menu_top;
            			else
                			j = menu_items - menu_show_start;

            			gr_color(UICOLOR0, UICOLOR1, UICOLOR2, 255);
            			for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                			if (i == menu_top + menu_sel) {
                    				gr_color(255, 255, 255, 255);
                    				draw_text_line(i - menu_show_start , menu[i], LEFT_ALIGN);
                    				gr_color(UICOLOR0, UICOLOR1, UICOLOR2, 255);
                		} else {
                    			gr_color(UICOLOR0, UICOLOR1, UICOLOR2, 255);
                    			draw_text_line(i - menu_show_start, menu[i], LEFT_ALIGN);
                		}
                		row++;
                		if (row >= max_menu_rows)
		                    break;
            		}
            		gr_fill(0, row*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
#ifdef BUILD_IN_LANDSCAPE
				gr_fb_width()-menu_max_height*2, row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
#else
				gr_fb_width(), row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
#endif
        	}

        	gr_color(NORMAL_TEXT_COLOR);
        	for (; row < text_rows; ++row) {
        		draw_text_line(row + 1, text[(row+text_top) % text_rows], LEFT_ALIGN);
        	}
    	}
}
Ejemplo n.º 15
0
// Redraw everything on the screen.  Does not flip pages.
// Should only be called with gUpdateMutex locked.
static void draw_screen_locked(void)
{
    if (!ui_has_initialized) return;
    draw_background_locked(gCurrentIcon);
    draw_progress_locked();

    if (show_text) {
        // don't "disable" the background anymore with this...
        // gr_color(0, 0, 0, 160);
        // gr_fill(0, 0, gr_fb_width(), gr_fb_height());

        int total_rows = gr_fb_height() / CHAR_HEIGHT;
        int i = 0;
        int j = 0;
        int row = 0;            // current row that we are drawing on
        if (show_menu) {
#ifndef BOARD_TOUCH_RECOVERY
            gr_color(MENU_TEXT_COLOR);
            gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
                    gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);

            gr_color(HEADER_TEXT_COLOR);
            for (i = 0; i < menu_top; ++i) {
                draw_text_line(i, menu[i]);
                row++;
            }

            if (menu_items - menu_show_start + menu_top >= max_menu_rows)
                j = max_menu_rows - menu_top;
            else
                j = menu_items - menu_show_start;

            gr_color(MENU_TEXT_COLOR);
            for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                if (i == menu_top + menu_sel) {
                    gr_color(255, 255, 255, 255);
                    draw_text_line(i - menu_show_start , menu[i]);
                    gr_color(MENU_TEXT_COLOR);
                } else {
                    gr_color(MENU_TEXT_COLOR);
                    draw_text_line(i - menu_show_start, menu[i]);
                }
                row++;
                if (row >= max_menu_rows)
                    break;
            }

            gr_fill(0, row*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
                    gr_fb_width(), row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
#else
            row = draw_touch_menu(menu, menu_items, menu_top, menu_sel, menu_show_start);
#endif
        }

        gr_color(NORMAL_TEXT_COLOR);
        int cur_row = text_row;
        int available_rows = total_rows - row - 1;
        int start_row = row + 1;
        if (available_rows < MAX_ROWS)
            cur_row = (cur_row + (MAX_ROWS - available_rows)) % MAX_ROWS;
        else
            start_row = total_rows - MAX_ROWS;

        int r;
        for (r = 0; r < (available_rows < MAX_ROWS ? available_rows : MAX_ROWS); r++) {
            draw_text_line(start_row + r, text[(cur_row + r) % MAX_ROWS]);
        }
    }
}
Ejemplo n.º 16
0
static void sensor_magnetometer_indication(module_info * mod, layout * layout) {
    int w = gr_fb_width();
    int h = gr_fb_height();

    int centre_x = w / 2;
    int centre_y = 2 * h / 3;
    int radius = w / 4;
    int origin_x = 0;
    int origin_y = 0;
    int i = 0;
    int temp = 0;
    char x[SIZE_1K] = { 0 };
    char y[SIZE_1K] = { 0 };
    char z[SIZE_1K] = { 0 };
    char angle[8] = { 0 };

    double x_temp = 0;
    double y_temp = 0;
    double z_temp = 0;

    rect_t rect;
    button *btn[ROUND_ANGLE];

    for(i = 0; i < ROUND_ANGLE; i++) {
        origin_x = radius * sin((i * M_PI / 180) + (M_PI / 2));
        origin_y = radius * cos((i * M_PI / 180) + (M_PI / 2));
        rect.x = centre_x + origin_x - ROUND_POINT_HALF_SIDE;
        rect.y = centre_y - origin_y - ROUND_POINT_HALF_SIDE;
        rect.w = ROUND_POINT_SIDE;
        rect.h = ROUND_POINT_SIDE;

        snprintf(angle, sizeof(angle), "%d", i);
        btn[i] = new button(angle, rect, "", NULL);
        btn[i]->set_color(COLOR_BLUE);
        layout->add_button_locked(btn[i]);
    }

    do {
        sem_wait(&g_data_print_sem);
        parse_sensors_xyz_value(mod->data, x, sizeof(x), y, sizeof(y), z, sizeof(z));
        x_temp = atof(x);
        y_temp = atof(y);
        i = convert_orientation(x_temp, y_temp);
        if((i >= 0) && (i <= 180) && (i != temp)) {
            origin_x = radius * sin((i * M_PI / 180) + (M_PI / 2));
            origin_y = radius * cos((i * M_PI / 180) + (M_PI / 2));
            rect.x = centre_x + origin_x - POINT_HALF_SIDE;
            rect.y = centre_y - origin_y - POINT_HALF_SIDE;
            rect.w = POINT_SIDE;
            rect.h = POINT_SIDE;
            btn[i]->set_rect(&rect);
            btn[i]->set_color(COLOR_RED);

            origin_x = radius * sin((temp * M_PI / 180) + (M_PI / 2));
            origin_y = radius * cos((temp * M_PI / 180) + (M_PI / 2));
            rect.x = centre_x + origin_x - ROUND_POINT_HALF_SIDE;
            rect.y = centre_y - origin_y - ROUND_POINT_HALF_SIDE;
            rect.w = ROUND_POINT_SIDE;
            rect.h = ROUND_POINT_SIDE;
            btn[temp]->set_rect(&rect);
            btn[temp]->set_color(COLOR_GREEN);
        } else if((i < 0) && (i >= -180) && (i != temp)) {
            i = i + ROUND_ANGLE;
            origin_x = radius * sin((i * M_PI / 180) + (M_PI / 2));
            origin_y = radius * cos((i * M_PI / 180) + (M_PI / 2));
            rect.x = centre_x + origin_x - POINT_HALF_SIDE;
            rect.y = centre_y - origin_y - POINT_HALF_SIDE;
            rect.w = POINT_SIDE;
            rect.h = POINT_SIDE;
            btn[i]->set_rect(&rect);
            btn[i]->set_color(COLOR_RED);
            origin_x = radius * sin((i * M_PI / 180) + (M_PI / 2));
            origin_y = radius * cos((i * M_PI / 180) + (M_PI / 2));
            rect.x = centre_x + origin_x - ROUND_POINT_HALF_SIDE;
            rect.y = centre_y - origin_y - ROUND_POINT_HALF_SIDE;
            rect.w = ROUND_POINT_SIDE;
            rect.h = ROUND_POINT_SIDE;
            btn[temp]->set_rect(&rect);
            btn[temp]->set_color(COLOR_GREEN);
        }
        temp = i;
    } while(1);
}
Ejemplo n.º 17
0
void ui_init(void)
{
    ui_has_initialized = 1;
    gr_init();
    ev_init(input_callback, NULL);
#ifdef BOARD_TOUCH_RECOVERY
    touch_init();
#endif

    text_col = text_row = 0;
    text_rows = gr_fb_height() / CHAR_HEIGHT;
    max_menu_rows = text_rows - MIN_LOG_ROWS;
#ifdef BOARD_TOUCH_RECOVERY
    max_menu_rows = get_max_menu_rows(max_menu_rows);
#endif
    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);
}
Ejemplo n.º 18
0
static int wifi_test_start(TestCase* thiz)
{
	DECLES_PRIV(priv, thiz);

	LOGE("%s: start wifi test...", __func__);
	FILE* fd;
	int cell_num = 0;
	char buffer[1024];
	char* ptr = NULL;
	struct wifi_cell cell;
	int start_y = 50;
	char cell_info[148];

	wifi_test(1);

	gr_color(0, 0, 0, 255);
	ui_draw_title(gr_fb_height()/2, WIFI_WAIT_PROMPT);

	fd = fopen("/data/wifi_test.txt", "r");
	if (fd == NULL) {
		LOGE("%s: open /data/wifi_test.txt fail", __func__);
		goto out;
	}

	gr_color(0, 255, 255, 255);

	do {
		char* tmp = NULL;
		ptr = fgets(buffer, 1024, fd);
		if (ptr == NULL)
			break;

		tmp = strstr(ptr, ADDRESS_WIFI);
		if (tmp != NULL) {
			tmp += strlen(ADDRESS_WIFI) + 1;
			memset(cell.address, 0, sizeof(cell.address));
			strncpy(cell.address, tmp, strlen(tmp) - 1);
		}

		tmp = strstr(ptr, ESSID_WIFI);
		if (tmp != NULL) {
			char* m;
			tmp += strlen(ESSID_WIFI) + 1;
			m = strchr(tmp, '"');
			memset(cell.ssid, 0, sizeof(cell.ssid));
			strncpy(cell.ssid, tmp, m - tmp);
			memset(cell_info, 0, sizeof(cell_info));
			sprintf(cell_info, "%s (%s)", cell.ssid, cell.address);
			gr_text(10, start_y, cell_info);
			start_y += CHAR_HEIGHT;
			cell_num ++;
		}

	} while(1);

	fclose(fd);
out:
	wifi_test(0);

	priv->passed = cell_num > 0 ? 1 : 0;

	if (priv->passed) {
		return 0;
	} else {
		return -1;
	}
}
Ejemplo n.º 19
0
void ScreenRecoveryUI::Init()
{
    gr_init();

    gr_font_size(&char_width, &char_height);

    text_col = text_row = 0;
    text_rows = gr_fb_height() / char_height;
    if (text_rows > kMaxRows) text_rows = kMaxRows;
    text_top = 1;

    text_cols = gr_fb_width() / char_width;
    if (text_cols > kMaxCols - 1) text_cols = kMaxCols - 1;

    backgroundIcon[NONE] = NULL;
    LoadBitmapArray("icon_installing", &installing_frames, &installation);
    backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : NULL;
    backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
    LoadBitmap("icon_error", &backgroundIcon[ERROR]);
    backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];

    LoadBitmap("progress_empty", &progressBarEmpty);
    LoadBitmap("progress_fill", &progressBarFill);
    LoadBitmap("stage_empty", &stageMarkerEmpty);
    LoadBitmap("stage_fill", &stageMarkerFill);

    LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);
    LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);
    LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]);
    LoadLocalizedBitmap("error_text", &backgroundText[ERROR]);

    // MStar Android Patch Begin
    //load title/tip bitmaps ,added by mstar semiconductor
    LoadBitmap("title_not_power_off",&titleNotPowerOff);
    LoadBitmap("title_not_unplug",&titleNotUnplug);
    LoadBitmap("tip_error", &tipTitle[TIP_TITLE_ERROR]);
    LoadBitmap("tip_ready", &tipTitle[TIP_TITLE_READY]);
    LoadBitmap("tip_success", &tipTitle[TIP_TITLE_SUCCESS]);
    LoadBitmap("tip_wipe_cache", &tipTitle[TIP_TITLE_WIPE_CACHE]);
    LoadBitmap("tip_wipe_data", &tipTitle[TIP_TITLE_WIPE_DATA]);
    LoadBitmap("tip_install_package", &tipTitle[TIP_TITLE_INSTALL_PACKAGE]);
    LoadBitmap("tip_backup_system", &tipTitle[TIP_TITLE_BACKUP_SYSTEM]);
    LoadBitmap("tip_restore_system", &tipTitle[TIP_TITLE_RESTORE_SYSTEM]);
    LoadBitmap("tip_blank_screen", &tipTitle[TIP_TITLE_BLANK_SCREEN]);

    // init exit recovery tip picture
    int j=0;
    char tipFileNmae[40];
    exitRecoveryTipTitle = (gr_surface*)malloc(exitRecoveryTipTitleNum *
                                                   sizeof(gr_surface));
    for (j = 0;j < exitRecoveryTipTitleNum;++j) {
        // "tip_exit_recovery_1.png", "tip_exit_recovery_2.png", ...
        sprintf(tipFileNmae, "tip_exit_recovery_%d", j+1);
        LoadBitmap(tipFileNmae, exitRecoveryTipTitle+j);
    }
    // MStar Android Patch End

    pthread_create(&progress_t, NULL, progress_thread, NULL);

    RecoveryUI::Init();
}
Ejemplo n.º 20
0
void ui_init(void)
{
    gr_init();
    ev_init(input_callback, NULL);

    text_col = text_row = 0;
    text_rows = gr_fb_height() / CHAR_HEIGHT;
    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;
    }

    pthread_t t;
    pthread_create(&t, NULL, progress_thread, NULL);
    pthread_create(&t, NULL, input_thread, NULL);
}
Ejemplo n.º 21
0
GUIConsole::GUIConsole(xml_node<>* node)
{
    xml_attribute<>* attr;
    xml_node<>* child;

    mFont = NULL;
    mCurrentLine = -1;
    memset(&mForegroundColor, 255, sizeof(COLOR));
    memset(&mBackgroundColor, 0, sizeof(COLOR));
    mBackgroundColor.alpha = 255;
    memset(&mScrollColor, 0x08, sizeof(COLOR));
    mScrollColor.alpha = 255;
    mLastCount = 0;
    mSlideout = 0;
    mSlideoutState = hidden;

    mRenderX = 0; mRenderY = 0; mRenderW = gr_fb_width(); mRenderH = gr_fb_height();

    if (!node)
    {
        mSlideoutX = 0; mSlideoutY = 0; mSlideoutW = 0; mSlideoutH = 0;
        mConsoleX = 0;  mConsoleY = 0;  mConsoleW = gr_fb_width();  mConsoleH = gr_fb_height();
    }
    else
    {
        child = node->first_node("font");
        if (child)
        {
            attr = child->first_attribute("resource");
            if (attr)
                mFont = PageManager::FindResource(attr->value());
        }

        child = node->first_node("color");
        if (child)
        {
            attr = child->first_attribute("foreground");
            if (attr)
            {
                std::string color = attr->value();
                ConvertStrToColor(color, &mForegroundColor);
            }
            attr = child->first_attribute("background");
            if (attr)
            {
                std::string color = attr->value();
                ConvertStrToColor(color, &mBackgroundColor);
            }
            attr = child->first_attribute("scroll");
            if (attr)
            {
                std::string color = attr->value();
                ConvertStrToColor(color, &mScrollColor);
            }
        }

        // Load the placement
        LoadPlacement(node->first_node("placement"), &mConsoleX, &mConsoleY, &mConsoleW, &mConsoleH);

        child = node->first_node("slideout");
        if (child)
        {
            mSlideout = 1;
            LoadPlacement(child, &mSlideoutX, &mSlideoutY);

            attr = child->first_attribute("resource");
            if (attr)   mSlideoutImage = PageManager::FindResource(attr->value());

            if (mSlideoutImage && mSlideoutImage->GetResource())
            {
                mSlideoutW = gr_get_width(mSlideoutImage->GetResource());
                mSlideoutH = gr_get_height(mSlideoutImage->GetResource());
            }
        }
    }

    gr_getFontDetails(mFont, &mFontHeight, NULL);
    SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
    SetRenderPos(mConsoleX, mConsoleY);
    return;
}
Ejemplo n.º 22
0
// Redraw everything on the screen.  Does not flip pages.
// Should only be called with gUpdateMutex locked.
static void draw_screen_locked(void) {
    if (!ui_has_initialized)
        return;

    draw_background_locked(gCurrentIcon);
    draw_progress_locked();

    if (show_text) {
        int total_rows = (gr_fb_height() - virtualkey_h) / CHAR_HEIGHT;
        int i = 0;
        int j = 0;
        int row = 0; // current row that we are drawing on
        if (show_menu) {
            int batt_level = 0;
            char batt_text[40];
            batt_level = get_batt_stats();

            /*struct tm *current;
            time_t now;
            now = time(NULL); // add 2 hours
            current = localtime(&now);
            sprintf(batt_text, "[%d%% %02D:%02D]", batt_level, current->tm_hour, current->tm_min);
            if (now == NULL)*/
            sprintf(batt_text, " [%d%%]", batt_level);

            gr_color(menuTextColor[0], menuTextColor[1], menuTextColor[2], menuTextColor[3]);
            //gr_color(0, 255, 0, 255);
            if (batt_level < 21)
                gr_color(255, 0, 0, 255);
            draw_text_line(0, batt_text, RIGHT_ALIGN);

            gr_color(menuTextColor[0], menuTextColor[1], menuTextColor[2], menuTextColor[3]);
            gr_fill(0, (menu_top + menu_sel - menu_show_start) * CHAR_HEIGHT,
                    gr_fb_width(), (menu_top + menu_sel - menu_show_start + 1)*CHAR_HEIGHT+1);

            gr_color(HEADER_TEXT_COLOR);
            for (i = 0; i < menu_top; ++i) {
                draw_text_line(i, menu[i], LEFT_ALIGN);
                row++;
            }

            if (menu_items - menu_show_start + menu_top >= max_menu_rows)
                j = max_menu_rows - menu_top;
            else
                j = menu_items - menu_show_start;

            gr_color(menuTextColor[0], menuTextColor[1], menuTextColor[2], menuTextColor[3]);
            for (i = menu_show_start + menu_top; i < (menu_show_start + menu_top + j); ++i) {
                if (i == menu_top + menu_sel) {
                    gr_color(255, 255, 255, 255);
                    draw_text_line(i - menu_show_start , menu[i], LEFT_ALIGN);
                    gr_color(menuTextColor[0], menuTextColor[1], menuTextColor[2], menuTextColor[3]);
                } else {
                    gr_color(menuTextColor[0], menuTextColor[1], menuTextColor[2], menuTextColor[3]);
                    draw_text_line(i - menu_show_start, menu[i], LEFT_ALIGN);
                }
                row++;
                if (row >= max_menu_rows)
                    break;
            }

            gr_fill(0, row*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
                    gr_fb_width(), row*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
        }

        gr_color(NORMAL_TEXT_COLOR);
        int cur_row = text_row;
        int available_rows = total_rows - row - 1;
        int start_row = row + 1;
        if (available_rows < MAX_ROWS)
            cur_row = (cur_row + (MAX_ROWS - available_rows)) % MAX_ROWS;
        else
            start_row = total_rows - MAX_ROWS;

        int r;
        for (r = 0; r < (available_rows < MAX_ROWS ? available_rows : MAX_ROWS); r++) {
            draw_text_line(start_row + r, text[(cur_row + r) % MAX_ROWS], LEFT_ALIGN);
        }
    }
#ifdef USE_VIRTUAL_KEY
    draw_virtualkeys_locked();
#endif
}