コード例 #1
0
ファイル: main.c プロジェクト: Tilka/ncdc
static gboolean screen_update_check(gpointer dat) {
  if(screen_resized) {
    endwin();
    doupdate();
    ui_draw();
    screen_resized = FALSE;
  } else if(ui_checkupdate())
    ui_draw();
  return TRUE;
}
コード例 #2
0
ファイル: race_select.c プロジェクト: XiaZhang0414/TuxRider
 /*! 
  Mode loop function
  \author  jfpatry
  \date    Created:  2000-09-24
  \date    Modified: 2000-09-24
  */
 static void race_select_loop( scalar_t time_step )
 {
     check_gl_error();
     
     update_audio();
     
     set_gl_options( GUI );
     
     clear_rendering_context();
     
     ui_setup_display();
     
     if (getparam_ui_snow()) {
         update_ui_snow( time_step, 
                        (bool_t) ( wind_ssbtn != NULL && 
                                  ssbutton_get_state( wind_ssbtn ) ) );
         draw_ui_snow();
     }
     
     ui_draw_menu_decorations();
     
     set_widget_positions_and_draw_decorations();
     
     ui_draw();
     
     reshape( getparam_x_resolution(), getparam_y_resolution() );
     
     winsys_swap_buffers();
 }
コード例 #3
0
ファイル: display.c プロジェクト: mtl/tmk_keyboard
void display_draw( bool sleep ) {

    // Turn on the busy LED:
    display_busy( true );

    // Blank the display if requested:
    if ( sleep ) {
        u8g_SleepOn( &u8g );
    }

    // Render the image:
    u8g_FirstPage( &u8g );
    do {
        // Stop if the draw function doesn't want to continue:
        if ( ! ui_draw( &u8g ) ) {
            break;
        }
    } while ( u8g_NextPage( &u8g ) );
    u8g_Delay( 100 );

    // Turn the display back on if blanking was requested:
    if ( sleep ) {
        u8g_SleepOff( &u8g );
    }

    // Turn off the busy LED:
    display_busy( false );
}
コード例 #4
0
ファイル: playstate.c プロジェクト: ratalaika/big-15
/**
 * Draw the current frame
 */
static void ps_draw() {
    GFraMe_event_draw_begin();
#ifdef DEBUG
        _drwCalls++;
#endif
        map_draw(m);
        rg_drawBullets();
        rg_drawObjects();
        rg_drawMobs();
        if (gv_nIsZero(SWITCH_MAP))
            transition_draw();
        ui_draw();
        player_draw(p2);
        player_draw(p1);
        if (gv_isZero(SWITCH_MAP))
            signal_draw();
        #ifdef QT_DEBUG_DRAW
            if (GFraMe_keys.f1 ||
                (GFraMe_controller_max > 0 && GFraMe_controllers[0].l2))
                qt_drawRootDebug();
        #endif 
        if (_ps_pause) {
            ps_drawPause();
        }
        if (_ps_isSpeedrun)
            timer_draw();
        if (_ps_text) {
            textWnd_draw();
        }
    GFraMe_event_draw_end();
}
コード例 #5
0
ファイル: preference.c プロジェクト: XiaZhang0414/TuxRider
static void preference_loop( scalar_t time_step )
{
    check_gl_error();
    
    update_audio();
    
    set_gl_options( GUI );
    
    clear_rendering_context();
    
    ui_setup_display();
    
    if (getparam_ui_snow()) {
        update_ui_snow( time_step, False );
        draw_ui_snow();
    }
    
    ui_draw_menu_decorations();
    
    draw_preference();
    
    ui_draw();
    
    reshape( getparam_x_resolution(), getparam_y_resolution() );
    
    winsys_swap_buffers();
}
コード例 #6
0
ファイル: ui-curses.c プロジェクト: EgoIncarnate/vis
static void ui_info_hide(Ui *ui) {
	UiCurses *uic = (UiCurses*)ui;
	if (uic->info[0]) {
		uic->info[0] = '\0';
		ui_draw(ui);
	}
}
コード例 #7
0
ファイル: credits.c プロジェクト: FeeJai/Tux-Racer-4-iOS
static void credits_loop( scalar_t time_step )
{
    int width, height;
    width = getparam_x_resolution();
    height = getparam_y_resolution();
    
    check_gl_error();
    
    update_audio();
    
    clear_rendering_context();
    
    set_gl_options( GUI );
    
    ui_setup_display();
    
    draw_credits_text( time_step );
    
    if (getparam_ui_snow()) {
        update_ui_snow( time_step, False );
        draw_ui_snow();
    }
    
    ui_draw_menu_decorations();
    
    ui_draw();
    
    reshape( width, height );
    
    winsys_swap_buffers();
} 
コード例 #8
0
ファイル: ui-curses.c プロジェクト: EgoIncarnate/vis
static void ui_window_options_set(UiWin *w, enum UiOption options) {
	UiCursesWin *win = (UiCursesWin*)w;
	win->options = options;
	if (options & (UI_OPTION_LINE_NUMBERS_ABSOLUTE|UI_OPTION_LINE_NUMBERS_RELATIVE)) {
		if (!win->winside)
			win->winside = newwin(1, 1, 1, 1);
	} else {
		if (win->winside) {
			delwin(win->winside);
			win->winside = NULL;
			win->sidebar_width = 0;
		}
	}
	if (options & UI_OPTION_STATUSBAR) {
		if (!win->winstatus)
			win->winstatus = newwin(1, 0, 0, 0);
	} else {
		if (win->winstatus)
			delwin(win->winstatus);
		win->winstatus = NULL;
	}

	if (options & UI_OPTION_ONELINE) {
		/* move the new window to the end of the list */
		UiCurses *uic = win->ui;
		UiCursesWin *last = uic->windows;
		while (last->next)
			last = last->next;
		if (last != win) {
			if (win->prev)
				win->prev->next = win->next;
			if (win->next)
				win->next->prev = win->prev;
			if (uic->windows == win)
				uic->windows = win->next;
			last->next = win;
			win->prev = last;
			win->next = NULL;
		}
	}

	ui_draw((Ui*)win->ui);
}
コード例 #9
0
ファイル: race_select.c プロジェクト: Jisby/TuxRacer-SDL2
/*! 
 Mode loop function
 \author  jfpatry
 \date    Created:  2000-09-24
 \date    Modified: 2000-09-24
 */
static void race_select_loop( scalar_t time_step )
{
    use_hud_program();
    
    check_gl_error();
    
    update_audio();
    
    set_gl_options( GUI );
    
    clear_rendering_context();
    
    ui_setup_display();
    
    if (getparam_ui_snow()) {
        update_ui_snow( time_step, False );
        draw_ui_snow();
    }
    
    ui_draw_menu_decorations(False);
	
	if (price_update)
	{
		update_text();
		price_update = False;
	}
    
	GameMenu_draw();

	draw_preview();
    
	winsys_update_joysticks();

    ui_draw();
    
    reshape( getparam_x_resolution(), getparam_y_resolution() );
    
    winsys_swap_buffers();
}
コード例 #10
0
ファイル: main.c プロジェクト: Tilka/ncdc
static gboolean one_second_timer(gpointer dat) {
  // TODO: ratecalc_calc() requires fairly precise timing, perhaps do this in a separate thread?
  ratecalc_calc();

  // Detect day change
  static char pday[11] = ""; // YYYY-MM-DD
  char *cday = localtime_fmt("%F");
  if(!pday[0])
    strcpy(pday, cday);
  if(strcmp(cday, pday) != 0) {
    ui_daychange(cday);
    strcpy(pday, cday);
  }
  g_free(cday);

  // Disconnect offline users
  cc_global_onlinecheck();

  // And draw the UI
  ui_draw();
  return TRUE;
}
コード例 #11
0
ファイル: main.c プロジェクト: laochailan/ngrav
int normal_loop(void) {
	UI ui;
	Parts p;
	
	if(parts_init(&p) != 0) {
		puts("Error initializing Particles");
		return 1;
	}
	if(ui_init(&ui,p.N) != 0) {
		puts("Error initializing UI.");
		return 1;
	}

	int frames = 0;
	double t = ui_time();

	srandom(time(0));
	while(!ui_should_quit(&ui)) {
		parts_step(&p);

		ui_draw(&ui, &p);
		ui_poll_events(&ui);

		frames++;
		if(frames > 10) {
			frames = 0;
			printf("frame time: %f s\n", ui_time()-t);

			t = ui_time();
		}
	}

	ui_deinit(&ui);
	parts_deinit(&p);

	return 0;
}
コード例 #12
0
ファイル: evilloop.c プロジェクト: pscha/tines
Node *evilloop (Node *pos)
{
	cli_outfun = set_status;

	while (!quit_tines) {
		Tbinding *binding;

		ui_draw (pos, inputbuf, 0);
		binding = parsekey (ui_input (), ui_current_scope);
		do {

			switch (binding->action) {
				case ui_action_quit:
					remove_temp (&pos);
					quit_tines = 1;
					break;
				case ui_action_command:
					if(!string_isoneof(binding->action_param, no_remove_temp_commands))
						remove_temp (&pos);
					pos = docmd (pos, binding->action_param);
					if(!string_isoneof(binding->action_param,keep_inputbuf))
						inputbuf[0] = 0;
					break;
				case ui_action_top:
					remove_temp (&pos);
					inputbuf[0] = 0;
					pos = node_top (pos);
					break;
				case ui_action_bottom:
					remove_temp (&pos);
					inputbuf[0] = 0;
					pos = node_bottom (pos);
					break;
				case ui_action_up:
					if (!remove_temp (&pos)) {
						if(forced_up){
							if (node_forced_up (pos)){
								pos = node_forced_up (pos);
							}
						} else {
							if (node_up (pos)){
								pos = node_up (pos);
							}
						}
					}
					inputbuf[0] = 0;
					break;
				case ui_action_down:
					if (!remove_temp (&pos)) {
						if(forced_down){
							if(node_forced_down(pos))
								pos = node_forced_down (pos);
						} else {
							if(node_down(pos))
								pos = node_down (pos);
						}							
						inputbuf[0] = 0;
						break;
					}
				case ui_action_pagedown:
					remove_temp (&pos);
					inputbuf[0] = 0;
					{
						int n;

						for (n = 0; n < tines_nodes_down; n++)
							if (node_down (pos)) {
								pos = node_down (pos);
							}
					}
					break;
				case ui_action_pageup:
					remove_temp (&pos);
					inputbuf[0] = 0;
					{
						int n;

						for (n = 0; n < tines_nodes_up; n++)
							if (node_up (pos))
								pos = node_up (pos);
					}
					break;
				case ui_action_left:
					if (!remove_temp (&pos)) {
						if (node_left (pos))
							pos = node_left (pos);
					}
					inputbuf[0] = 0;
					break;
				case ui_action_right:
					if (node_right (pos)) {
						pos = node_right (pos);
					} else {
						if (fixnullstring (node_get (pos, TEXT))[0]) {
							node_insert_right (pos);
							if (node_getflag (pos, F_temp))
								node_setflag (pos, F_temp, 0);
							if (!strcmp(fixnullstring(node_get(pos,"type")),"todo")){
								node_set (node_right (pos), "type","todo");
								node_set (node_right (pos), "done","no");
							}
							node_setflag (node_right (pos), F_temp, 1);
							pos = node_right (pos);
						}
					}
					inputbuf[0] = 0;
					break;
				case ui_action_complete:
					if (strcmp
						(inputbuf,
						 fixnullstring (node_get (pos, TEXT))) == 0) {
						if (node_right (pos)) {
							pos = node_right (pos);
						} else {
							if (fixnullstring (node_get (pos, TEXT))[0]) {
								node_insert_right (pos);
								if (node_getflag (pos, F_temp))
									node_setflag (pos, F_temp, 0);
								if (!strcmp(fixnullstring(node_get(pos,"type")),"todo")){
									node_set (node_right (pos), "type","todo");
									node_set (node_right (pos), "done","no");
								}
								node_setflag (node_right (pos), F_temp, 1);

								pos = node_right (pos);
							}
						}
						inputbuf[0] = 0;
					} else {
						strcpy (inputbuf,
								fixnullstring (node_get (pos, TEXT)));
					}
					break;
				case ui_action_cancel:
					if (node_getflag (pos, F_temp)) {
						pos = node_remove (pos);
					} else {
						/*stop = ui_quit (pos); */
					}
					inputbuf[0] = 0;
					break;
				case ui_action_backspace:
					if (!strlen (inputbuf)) {
						/*pos = ui_remove (pos); */
					} else {
						inputbuf[strlen (inputbuf) - 1] = 0;
						if (node_getflag (pos, F_temp))
							if (node_up (pos))
								pos = node_remove (pos);
					}
					break;
				case ui_action_unbound:
					undefined_key (ui_scope_names[ui_current_scope],
								   binding->key !=
								   1000 ? binding->key : *((int *) &binding->
														   action_param[0]));
				case ui_action_ignore:
					break;
				default:
					if (binding->action > 31 && binding->action < 255) {	/*  input for buffer */
						inputbuf[strlen (inputbuf) + 1] = 0;
						inputbuf[strlen (inputbuf)] = binding->action;
					} else
						undefined_key (ui_scope_names[ui_current_scope],
									   binding->key !=
									   1000 ? binding->
									   key : *((int *) &binding->
											   action_param[0]));
					break;
			}
		} while ((++binding)->key == 999);


		if (strlen (inputbuf)) {
			if (node_getflag (pos, F_temp)) {
				node_set (pos, TEXT, inputbuf);
			} else {
				if (node_match (inputbuf, pos)) {
					pos = node_match (inputbuf, pos);
				} else {
				  if (add_at_top) {
					pos = node_insert_up (node_top (pos));
				  } else {
					pos = node_insert_down (node_bottom (pos));
				  }
					node_setflag (pos, F_temp, 1);
					node_set (pos, TEXT, inputbuf);
					if (node_left (pos))
							if (!strcmp(fixnullstring(node_get(node_left(pos),"type")),"todo")){
								node_set (pos, "type","todo");
								node_set (pos, "done","no");
							}
				}
			}
		} else {
			docmd(pos, "autosave_check_timeout"); 
		}
	}
	return pos;
}
コード例 #13
0
ファイル: ui-curses.c プロジェクト: EgoIncarnate/vis
static void ui_resize_to(Ui *ui, int width, int height) {
	UiCurses *uic = (UiCurses*)ui;
	uic->width = width;
	uic->height = height;
	ui_draw(ui);
}
コード例 #14
0
ファイル: ui-curses.c プロジェクト: EgoIncarnate/vis
static void ui_redraw(Ui *ui) {
	clear();
	ui_draw(ui);
}
コード例 #15
0
ファイル: ui-curses.c プロジェクト: EgoIncarnate/vis
static void ui_info(Ui *ui, const char *msg, va_list ap) {
	UiCurses *uic = (UiCurses*)ui;
	vsnprintf(uic->info, sizeof(uic->info), msg, ap);
	ui_draw(ui);
}
コード例 #16
0
ファイル: game.c プロジェクト: hiltonm/nostos
void game_loop (GAME *game)
{
    if (!game)
        return;

    ALLEGRO_KEYBOARD_STATE keyboard_state;
    ALLEGRO_EVENT event;
    ALLEGRO_FONT *font = al_load_font ("data/fixed_font.tga", 0, 0);
    SCENE *scene;
    SPRITE_ACTOR *actor;
    LIST_ITEM *item;

    AABB_COLLISIONS collisions;
    aabb_init_collisions (&collisions);

    AABB_COLLISIONS portal_collisions;
    aabb_init_collisions (&portal_collisions);

    AABB_COLLISIONS npc_collisions;
    aabb_init_collisions (&npc_collisions);

    int i = 0;
    bool redraw = true;
    float times[NTIMES] = {0};

    double frame_time, current_time, new_time, mean_frame_time;
    double fixed_dt = 1.0 / FPS, dt;
    double curfps = 0.0;

    current_time = al_get_time ();
    al_start_timer (game->timer);

    float fadeout_duration = 0;
    float fadein_duration = 0;
    SCENE_PORTAL *dest_portal = NULL;

    char *arrow_path = get_resource_path_str ("data/ui/smallarrow_down.png");
    ALLEGRO_BITMAP *sel_arrow = al_load_bitmap (arrow_path);

    while (game->running) {
        scene = game->current_scene;
        actor = game->current_actor;

        if (redraw) {
            al_clear_depth_buffer (0);
            tiled_draw_map_back (scene->map, game->screen.tint,
                                 game->screen.position.x, game->screen.position.y,
                                 game->screen.width, game->screen.height, 0, 0, 0);

            al_draw_textf (font, al_map_rgba_f (0.9, 0, 0, 1), 5, 5, 0, "FPS: %.2f", curfps);

            al_set_render_state (ALLEGRO_ALPHA_TEST, true);
            al_set_render_state (ALLEGRO_DEPTH_TEST, true);
            al_set_render_state (ALLEGRO_DEPTH_FUNCTION, ALLEGRO_RENDER_GREATER);

            al_hold_bitmap_drawing (true);
            sprite_draw (actor, &game->screen);
            item = _al_list_front (scene->npcs);
            while (item) {
                SPRITE_ACTOR *npc_actor = (SPRITE_ACTOR *)_al_list_item_data (item);
                sprite_draw (npc_actor, &game->screen);
                item = _al_list_next (scene->npcs, item);
            }
            al_hold_bitmap_drawing (false);

            al_set_render_state (ALLEGRO_DEPTH_TEST, false);
            al_set_render_state (ALLEGRO_ALPHA_TEST, false);

            if (false) {
                item = _al_list_front (portal_collisions.boxes);
                while (item) {
                    BOX *box = _al_list_item_data (item);
                    box_draw (*box, game->screen.position, al_map_rgb_f (1, 0, 0));
                    item = _al_list_next (portal_collisions.boxes, item);
                }

                aabb_draw (scene->portal_tree, &game->screen, al_map_rgb_f (0, 0, 1));
            }

            tiled_draw_map_fore (scene->map, game->screen.tint,
                                 game->screen.position.x, game->screen.position.y,
                                 game->screen.width, game->screen.height, 0, 0, 0);

            if (game->current_npc) {
                float dx = game->current_npc->actor.box.center.x - game->screen.position.x;
                float dy = game->current_npc->actor.box.center.y - game->screen.position.y;
                dx -= al_get_bitmap_width (sel_arrow) * 0.5f;
                dy -= game->current_npc->actor.box.extent.y * 3.0f;
                al_draw_bitmap (sel_arrow, dx, dy, 0);
            }

            ui_draw (game->ui, &game->screen);
            if (game->force_vsync)
                al_wait_for_vsync ();

            al_flip_display ();
            redraw = false;
        }

        al_wait_for_event (game->event_queue, &event);

        switch (event.type) {
            case ALLEGRO_EVENT_TIMER:
                new_time = al_get_time ();
                frame_time = new_time - current_time;
                current_time = new_time;

                times[i] = frame_time;
                i = (i + 1) % NTIMES;

                mean_frame_time = 0.0;
                for (int j = 0; j < NTIMES; j++)
                    mean_frame_time += times[j];

                mean_frame_time /= NTIMES;
                curfps = 1.0 / mean_frame_time;

                dt = mean_frame_time / fixed_dt;

                if (fadeout_duration > 0.0f) {
                    float fadef = fadeout_duration / TRANS_TIME;
                    game->screen.tint = al_map_rgba_f (fadef, fadef, fadef, 1.0);
                    fadeout_duration -= mean_frame_time;
                    if (fadeout_duration <= 0.0f) {
                        fadein_duration = TRANS_TIME;
                        fadeout_duration = 0.0f;
                        game_enter_portal (game, dest_portal);
                    }
                }

                if (fadein_duration > 0.0f) {
                    float fadef = 1.0 - fadein_duration / TRANS_TIME;
                    game->screen.tint = al_map_rgba_f (fadef, fadef, fadef, 1.0);
                    fadein_duration -= mean_frame_time;
                    if (fadein_duration <= 0.0f) {
                        game->paused = false;
                        fadein_duration = 0.0f;
                    }
                }

                if (game->paused) {
                    redraw = true;
                    break;
                }

                al_get_keyboard_state (&keyboard_state);

                if (al_key_down (&keyboard_state, ALLEGRO_KEY_ESCAPE)) {
                    game->running = false;
                    continue;
                }

                if (al_key_down (&keyboard_state, ALLEGRO_KEY_ENTER)) {
                    ui_show_dialog (game->ui, NULL, NULL);
                }

                if (al_key_down (&keyboard_state, ALLEGRO_KEY_RIGHT)) {
                    actor->event->move_right (actor, dt);
                }
                if (al_key_down (&keyboard_state, ALLEGRO_KEY_LEFT)) {
                    actor->event->move_left (actor, dt);
                }
                if (al_key_down (&keyboard_state, ALLEGRO_KEY_UP)) {
                    actor->event->move_up (actor, dt);
                }
                if (al_key_down (&keyboard_state, ALLEGRO_KEY_DOWN)) {
                    actor->event->move_down (actor, dt);
                }

                BOX box = actor->box;
                box.center.x += actor->movement.x * dt;
                box.center.y += actor->movement.y * dt;

                aabb_collide_fill_cache (scene->collision_tree, &box, &collisions);
                if (scene->collision_tree->num_collisions > 0) {
                    item = _al_list_front (collisions.boxes);
                    while (item) {
                        if (box_lateral (*(BOX *)_al_list_item_data (item), actor->box))
                            actor->movement.x = 0;
                        else
                            actor->movement.y = 0;
                        item = _al_list_next (collisions.boxes, item);
                    }
                }

                aabb_collide_fill_cache (scene->portal_tree, &box, &portal_collisions);
                if (scene->portal_tree->num_collisions > 0) {
                    item = _al_list_front (portal_collisions.boxes);
                    while (item) {
                        BOX *colbox = _al_list_item_data (item);
                        TILED_OBJECT *obj = colbox->data;
                        SCENE_PORTAL *portal = scene_get_portal (game->scenes, obj->name);
                        if (portal && portal->destiny_portal) {
                            dest_portal = scene_get_portal (game->scenes, portal->destiny_portal);
                            if (dest_portal) {
                                fadeout_duration = TRANS_TIME;
                                game->paused = true;
                                actor->movement = (VECTOR2D){0, 0};
                                ui_show_dialog_cstr (game->ui, "Speaker:", "Entering portal.");
                                break;
                            }
                        }
                        item = _al_list_next (portal_collisions.boxes, item);
                    }
                }

                box = screen_box (&game->screen);

                game->current_npc = NULL;
                item = _al_list_front (scene->npcs);
                float max_dist = 0;
                while (item) {
                    SPRITE_NPC *npc = _al_list_item_data (item);
                    float dist = vsqdistance (npc->actor.box.center, game->current_actor->box.center);
                    if (dist < 128.0f * 128.0f && dist > max_dist) {
                        game->current_npc = npc;
                        max_dist = dist;
                    }
                    item = _al_list_next (scene->npcs, item);
                }

                //aabb_collide_fill_cache (scene->npc_tree, &box, &npc_collisions);
                //if (scene->npc_tree->num_collisions > 0) {
                //    item = _al_list_front (npc_collisions.boxes);
                //    float max_dist = 0;
                //    while (item) {
                //        BOX *colbox = _al_list_item_data (item);
                //        SPRITE_NPC *npc = colbox->data;
                //        float dist = vsqdistance (npc->actor.box.center, game->current_actor->box.center);
                //        if (dist < 128.0f * 128.0f && dist > max_dist) {
                //            game->current_npc = npc;
                //            max_dist = dist;
                //        }
                //        item = _al_list_next (npc_collisions.boxes, item);
                //    }
                //}

                screen_update (&game->screen, actor->position, scene->map, dt);
                sprite_update (actor, dt, mean_frame_time);

                item = _al_list_front (scene->npcs);
                while (item) {
                    SPRITE_ACTOR *npc_actor = (SPRITE_ACTOR *)_al_list_item_data (item);
                    sprite_update (npc_actor, dt, mean_frame_time);
                    item = _al_list_next (scene->npcs, item);
                }

                redraw = true;
                break;
            case ALLEGRO_EVENT_DISPLAY_CLOSE:
                game->running = false;
                break;
            default:
                fprintf (stderr, "Unsupported event received: %d\n", event.type);
                break;
        }
    }

    aabb_free_collisions (&collisions);
    aabb_free_collisions (&portal_collisions);
    aabb_free_collisions (&npc_collisions);
}
コード例 #17
0
ファイル: main.c プロジェクト: Tilka/ncdc
static void handle_input() {
  /* Mapping from get_wch() to input_key_t:
   *  KEY_CODE_YES -> KEY(code)
   *  KEY_CODE_NO:
   *    char == 127           -> KEY(KEY_BACKSPACE)
   *    char <= 31            -> CTRL(char)
   *    !'^['                 -> CHAR(char)
   *    ('^[', !)             -> KEY(KEY_ESCAPE)
   *    ('^[', !CHAR)         -> ignore both characters (1)
   *    ('^[', CHAR && '[')   -> ignore both characters and the character after that (2)
   *    ('^[', CHAR && !'[')  -> ALT(second char)
   *
   * 1. this is something like ctrl+alt+X, which we won't use
   * 2. these codes indicate a 'Key' that somehow wasn't captured with
   *    KEY_CODE_YES. We won't attempt to interpret these ourselves.
   *
   * There are still several unhandled issues:
   * - Ncurses does not catch all key codes, and there is no way of knowing how
   *   many bytes a key code spans. Things like ^[[1;3C won't be handled correctly. :-(
   * - Ncurses can actually return key codes > KEY_MAX, but does not provide
   *   any mechanism for figuring out which key it actually was.
   * - It may be useful to use define_key() for some special (and common) codes
   * - Modifier keys will always be a problem. Most alt+key things work, except
   *   for those that may start a control code. alt+[ is a famous one, but
   *   there are others (like alt+O on my system). This is system-dependent,
   *   and again we have no way of knowing these things. (except perhaps by
   *   reading termcap entries on our own?)
   */

  guint64 key;
  char buf[9];
  int r;
  wint_t code;
  int lastesc = 0, curignore = 0;
  while((r = get_wch(&code)) != ERR) {
    if(curignore) {
      curignore = 0;
      continue;
    }
    // we use SIGWINCH, so KEY_RESIZE can be ignored
    if(r == KEY_CODE_YES && code == KEY_RESIZE)
      continue;
    // backspace (outside of an escape sequence) is often sent as DEL control character, correct this
    if(!lastesc && r != KEY_CODE_YES && code == 127) {
      r = KEY_CODE_YES;
      code = KEY_BACKSPACE;
    }
    // backspace inside an escape sequence is also possible, convert the other way around
    if(lastesc && r == KEY_CODE_YES && code == KEY_BACKSPACE) {
      r = !KEY_CODE_YES;
      code = 127;
    }
    key = r == KEY_CODE_YES ? INPT_KEY(code) : code == 27 ? INPT_ALT(0) : code <= 31 ? INPT_CTRL(ctrl_to_ascii(code)) : INPT_CHAR(code);
    // convert wchar_t into gunichar
    if(INPT_TYPE(key) == 1) {
      if((r = wctomb(buf, code)) < 0)
        g_warning("Cannot encode character 0x%X", code);
      buf[r] = 0;
      key = INPT_CHAR(g_utf8_get_char_validated(buf, -1));
      if(INPT_CODE(key) == (gunichar)-1 || INPT_CODE(key) == (gunichar)-2) {
        g_warning("Invalid UTF-8 sequence in keyboard input. Are you sure you are running a UTF-8 locale?");
        continue;
      }
    }
    // check for escape sequence
    if(lastesc) {
      lastesc = 0;
      if(INPT_TYPE(key) != 1)
        continue;
      if(INPT_CODE(key) == '[') {
        curignore = 1;
        continue;
      }
      key |= (guint64)3<<32; // a not very nice way of saying "turn this key into a INPT_ALT"
      ui_input(key);
      continue;
    }
    if(INPT_TYPE(key) == 3) {
      lastesc = 1;
      continue;
    }
    ui_input(key);
  }
  if(lastesc)
    ui_input(INPT_KEY(KEY_ESCAPE));

  ui_draw();
}