Exemple #1
0
/* main program */
int main(int argc, char **argv) {
  char *dir;

  setlocale(LC_ALL, "");

  if((dir = argv_parse(argc, argv)) == NULL)
    dir = ".";

  calc_init(dir, NULL);

  initscr();
  cbreak();
  noecho();
  curs_set(0);
  keypad(stdscr, TRUE);
  if(ncresize(min_rows, min_cols))
    min_rows = min_cols = 0;

  while(1) {
    if(pstate == ST_CALC && calc_process())
      break;
    else if(pstate == ST_DEL)
      delete_process();
    else if(input_handle(0))
      break;
  }

  erase();
  refresh();
  endwin();
  exclude_clear();

  return 0;
}
Exemple #2
0
/**
 * @brief Creates a secondary loop until loop_done is set to 1 or the toolkit closes.
 *
 * Almost identical to the main loop in naev.c.
 *
 * @TODO Fix this, we need proper threading as the music Lua and dialogue running Lua
 *       may be run in parallel and this will make everyone cry. So basically we have
 *       a race condition due to the "threading" effect this creates. Solved most of
 *       it by removing globals in the Lua event/mission code, but this doesn't mean
 *       it's solved. It just means it's extremely unlikely.
 *
 *    @return 0 on success.
 */
static int toolkit_loop( int *loop_done )
{
   SDL_Event event;

   /* Delay a toolkit iteration. */
   toolkit_delay();

   *loop_done = 0;
   while (!(*loop_done) && toolkit_isOpen()) {
      /* Loop first so exit condition is checked before next iteration. */
      main_loop( 0 );

      while (SDL_PollEvent(&event)) { /* event loop */
         if (event.type == SDL_QUIT) { /* pass quit event to main engine */
            if (menu_askQuit()) {
               naev_quit();
               *loop_done = 1;
               SDL_PushEvent(&event);
               return -1;
            }
         }

         input_handle(&event); /* handles all the events and player keybinds */
      }
   }

   return 0;
}
Exemple #3
0
/**
 * @brief Creates a secondary loop until loop_done is set to 1 or the toolkit closes.
 *
 * Almost identical to the main loop in naev.c.
 *
 * @TODO Fix this, we need proper threading as the music Lua and dialogue running Lua
 *       may be run in parallel and this will make everyone cry. So basically we have
 *       a race condition due to the "threading" effect this creates. Solved most of
 *       it by removing globals in the Lua event/mission code, but this doesn't mean
 *       it's solved. It just means it's extremely unlikely.
 *
 *    @return 0 on success.
 */
static int toolkit_loop( int *loop_done )
{
   SDL_Event event;

   /* Delay a toolkit iteration. */
   toolkit_delay();

   *loop_done = 0;
   while (!(*loop_done) && toolkit_isOpen()) {
      /* Loop first so exit condition is checked before next iteration. */
      main_loop( 0 );

      while (SDL_PollEvent(&event)) { /* event loop */
         if (event.type == SDL_QUIT) { /* pass quit event to main engine */
            if (menu_askQuit()) {
               naev_quit();
               *loop_done = 1;
               SDL_PushEvent(&event);
               return -1;
            }
         }
#if SDL_VERSION_ATLEAST(2,0,0)
         else if (event.type == SDL_WINDOWEVENT &&
               event.window.event == SDL_WINDOWEVENT_RESIZED) {
            naev_resize( event.window.data1, event.window.data2 );
            continue;
         }
#endif /* SDL_VERSION_ATLEAST(2,0,0) */

         input_handle(&event); /* handles all the events and player keybinds */
      }
   }

   return 0;
}
Exemple #4
0
static int process() {
  char *path;
  char *dir;
  int fail = 0;
  struct stat fs;
  struct dir *d;

  if((path = path_real(dir_curpath)) == NULL)
    dir_seterr("Error obtaining full path: %s", strerror(errno));
  else {
    dir_curpath_set(path);
    free(path);
  }

  if(!dir_fatalerr && path_chdir(dir_curpath) < 0)
    dir_seterr("Error changing directory: %s", strerror(errno));

  /* Can these even fail after a chdir? */
  if(!dir_fatalerr && lstat(".", &fs) != 0)
    dir_seterr("Error obtaining directory information: %s", strerror(errno));
  if(!dir_fatalerr && !S_ISDIR(fs.st_mode))
    dir_seterr("Not a directory");

  if(!dir_fatalerr && !(dir = dir_read(&fail)))
    dir_seterr("Error reading directory: %s", strerror(errno));

  if(!dir_fatalerr) {
    curdev = (uint64_t)fs.st_dev;
    d = dir_createstruct(dir_curpath);
    if(fail)
      d->flags |= FF_ERR;
    stat_to_dir(d, &fs);

    if(dir_output.item(d)) {
      dir_seterr("Output error: %s", strerror(errno));
      fail = 1;
    }
    if(!fail)
      fail = dir_walk(dir);
    if(!fail && dir_output.item(NULL)) {
      dir_seterr("Output error: %s", strerror(errno));
      fail = 1;
    }
  }

  while(dir_fatalerr && !input_handle(0))
    ;
  return dir_output.final(dir_fatalerr || fail);
}
Exemple #5
0
/* Scans and adds a single item. Recurses into dir_walk() again if this is a
 * directory. Assumes we're chdir'ed in the directory in which this item
 * resides, i.e. d->name is a valid relative path to the item. */
static int dir_scan_item(struct dir *d) {
  struct stat st;
  int fail = 0;

#ifdef __CYGWIN__
  /* /proc/registry names may contain slashes */
  if(strchr(d->name, '/') || strchr(d->name,  '\\')) {
    d->flags |= FF_ERR;
    dir_setlasterr(dir_curpath);
  }
#endif

  if(exclude_match(dir_curpath))
    d->flags |= FF_EXL;

  if(!(d->flags & (FF_ERR|FF_EXL)) && lstat(d->name, &st)) {
    d->flags |= FF_ERR;
    dir_setlasterr(dir_curpath);
  }

  if(!(d->flags & (FF_ERR|FF_EXL)))
    stat_to_dir(d, &st);

  if(cachedir_tags && (d->flags & FF_DIR) && !(d->flags & (FF_ERR|FF_EXL|FF_OTHFS)))
    if(has_cachedir_tag(d->name)) {
      d->flags |= FF_EXL;
      d->size = d->asize = 0;
    }

  /* Recurse into the dir or output the item */
  if(d->flags & FF_DIR && !(d->flags & (FF_ERR|FF_EXL|FF_OTHFS)))
    fail = dir_scan_recurse(d);
  else if(d->flags & FF_DIR) {
    if(dir_output.item(d) || dir_output.item(NULL)) {
      dir_seterr("Output error: %s", strerror(errno));
      fail = 1;
    }
  } else if(dir_output.item(d)) {
    dir_seterr("Output error: %s", strerror(errno));
    fail = 1;
  }

  return fail || input_handle(1);
}
Exemple #6
0
int main(void)
{

	//	设定吃药方案,并上传到服务器
	//	设定吃药方案,并传给药盒	
	//	修改吃药方案,上传服务器
	//	接收服务器的信息
	//	过往吃药信息查询		
	//	手机注册


	int ret,fd,maxfd;
	struct sockaddr_in sin;
	char buf[BUFSIZ];
	fd_set rset;
	struct timeval tout;
	sqlite3 *db;
	sqlite3_open("./mdc.db", &db);//打开数据库文件
	create(db);
	show_welcome();
	/*1.创建一个套接字*/
	fd=socket(AF_INET,SOCK_STREAM,0);//ipV4的TCP编程
	if(fd<0)
	{
		perror("socket fail");
		exit(1);
	}	
	/*2.连接服务器*/
	/*2.1 填充要连接的服务器信息*/
	bzero(&sin,sizeof(sin));
	sin.sin_family=AF_INET;
	sin.sin_port=htons(SERV_PORT);//主机字节序转换为网络字节序
	//十进制点分形式字符串IP地址转换为32位二进制的网络字节
	sin.sin_addr.s_addr=inet_addr(SERV_IP1);
	/*2.2 连接服务器(在两个套接字之间创建连接)*/
	if(connect(fd,(struct sockaddr *)&sin,sizeof(sin))<0)
	{
		perror("connect fail");
		exit(1);
	}
	printf ("TCP client starting...OK!\n");
	/*3.和服务器进行数据交互*/
	while(1)
	{
		tout.tv_sec=5;
		tout.tv_usec=0;
		/*把rset清零*/
		FD_ZERO(&rset);
		/*依次把所有要监控的文件描述符加入到集合rset中*/
		FD_SET(0,&rset);
		FD_SET(fd,&rset);
		maxfd=fd;
		/*调用select函数*/
		ret=select(maxfd+1,&rset,NULL,NULL,&tout);
		/*依次判断被监控的文件描述符是否有数据*/
		if(FD_ISSET(0,&rset))//标准键盘上有输入
		{
			bzero(buf,BUFSIZ);
			input_handle(fd,buf,BUFSIZ-1,db);
		}
		if(FD_ISSET(fd,&rset))//套接字上有数据
		{
			bzero(buf,BUFSIZ);
			ser_data_handle(fd,buf,BUFSIZ-1);
		}
		/*确认是否是超时返回*/
		if(!ret||(tout.tv_sec==0&&tout.tv_usec==0))
			printf("timeout!\n");
	}

	sqlite3_close(db);//关闭数据库
	close(fd);

	return 0;
}
Exemple #7
0
static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{
    ChatContext *ctx = self->chatwin;

    int x, y, y2, x2;
    getyx(self->window, y, x);
    getmaxyx(self->window, y2, x2);

    if (x2 <= 0)
        return;

    /* ignore non-menu related input if active */
    if (self->help->active) {
        help_onKey(self, key);
        return;
    }

    if (ltr) {    /* char is printable */
        input_new_char(self, key, x, y, x2, y2);
        return;
    }

    if (line_info_onKey(self, key))
        return;

    input_handle(self, key, x, y, x2, y2);

    if (key == '\t') {    /* TAB key: auto-completes command */
        if (ctx->len > 1 && ctx->line[0] == '/') {
            int diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);

            if (diff != -1) {
                if (x + diff > x2 - 1) {
                    wmove(self->window, y, x + diff);
                    ctx->start += diff;
                } else {
                    wmove(self->window, y, x + diff);
                }
            } else {
                beep();
            }
        } else {
            beep();
        }
    } else if (key == '\n') {
        rm_trailing_spaces_buf(ctx);

        uint8_t line[MAX_STR_SIZE] = {0};

        if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
            memset(&line, 0, sizeof(line));

        if (!string_is_empty(line))
            add_line_to_hist(ctx);

        line_info_add(self, NULL, NULL, NULL, line, PROMPT, 0, 0);
        execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);

        wclear(ctx->linewin);
        wmove(self->window, y2 - CURS_Y_OFFSET, 0);
        reset_buf(ctx);
    }
}
Exemple #8
0
static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{
    ChatContext *ctx = self->chatwin;

    int x, y, y2, x2;
    getyx(self->window, y, x);
    getmaxyx(self->window, y2, x2);

    if (x2 <= 0 || y2 <= 0)
        return;

    if (self->help->active) {
        help_onKey(self, key);
        return;
    }

    if (ltr) {    /* char is printable */
        input_new_char(self, key, x, y, x2, y2);
        return;
    }

    if (line_info_onKey(self, key))
        return;

    if (input_handle(self, key, x, y, x2, y2))
        return;

    if (key == '\t') {  /* TAB key: auto-completes peer name or command */
        if (ctx->len > 0) {
            int diff;

            /* TODO: make this not suck */
            if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) {
                diff = complete_line(self, groupchats[self->num].peer_names, groupchats[self->num].num_peers,
                                     TOX_MAX_NAME_LENGTH);
            } else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
                diff = dir_match(self, m, ctx->line, L"/avatar");
            } else {
                diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE);
            }

            if (diff != -1) {
                if (x + diff > x2 - 1) {
                    int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
                    ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
                }
            } else {
                sound_notify(self, notif_error, 0, NULL);
            }
        } else {
            sound_notify(self, notif_error, 0, NULL);
        }
    } else if (key == user_settings->key_peer_list_down) {    /* Scroll peerlist up and down one position */
        int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST;

        if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L)
            ++groupchats[self->num].side_pos;
    } else if (key == user_settings->key_peer_list_up) {
        if (groupchats[self->num].side_pos > 0)
            --groupchats[self->num].side_pos;
    } else if (key == '\n') {
        rm_trailing_spaces_buf(ctx);

        char line[MAX_STR_SIZE];

        if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
            memset(&line, 0, sizeof(line));

        if (!string_is_empty(line))
            add_line_to_hist(ctx);

        if (line[0] == '/') {
            if (strcmp(line, "/close") == 0) {
                close_groupchat(self, m, self->num);
                return;
            } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
                send_group_action(self, ctx, m, line + strlen("/me "));
            } else {
                execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE);
            }
        } else if (!string_is_empty(line)) {
            if (tox_group_message_send(m, self->num, (uint8_t *) line, strlen(line)) == -1) {
                const char *errmsg = " * Failed to send message.";
                line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, errmsg);
            }
        }

        wclear(ctx->linewin);
        wmove(self->window, y2 - CURS_Y_OFFSET, 0);
        reset_buf(ctx);
    }
}
Exemple #9
0
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{
    ChatContext *ctx = self->chatwin;
    StatusBar *statusbar = self->stb;

    int x, y, y2, x2;
    getyx(self->window, y, x);
    getmaxyx(self->window, y2, x2);

    if (x2 <= 0)
        return;

    if (self->help->active) {
        help_onKey(self, key);
        return;
    }

    if (ltr) {    /* char is printable */
        input_new_char(self, key, x, y, x2, y2);

        if (ctx->line[0] != '/' && !ctx->self_is_typing && statusbar->is_online)
            set_self_typingstatus(self, m, 1);

        return;
    }

    if (line_info_onKey(self, key))
        return;

    input_handle(self, key, x, y, x2, y2);

    if (key == '\t' && ctx->len > 1 && ctx->line[0] == '/') {    /* TAB key: auto-complete */
        int diff = -1;

        if (wcsncmp(ctx->line, L"/sendfile \"", wcslen(L"/sendfile \"")) == 0) {
            diff = dir_match(self, m, ctx->line);
        } else {
            diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE);
        }

        if (diff != -1) {
            if (x + diff > x2 - 1) {
                int wlen = wcswidth(ctx->line, sizeof(ctx->line));
                ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
            }
        } else {
            notify(self, error, 0);
        }

    } else if (key == '\n') {
        rm_trailing_spaces_buf(ctx);

        char line[MAX_STR_SIZE];

        if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
            memset(&line, 0, sizeof(line));

        if (!string_is_empty(line))
            add_line_to_hist(ctx);

        if (line[0] == '/') {
            if (strcmp(line, "/close") == 0) {
                kill_chat_window(self);
                return;
            } else if (strncmp(line, "/me ", strlen("/me ")) == 0) {
                send_action(self, ctx, m, line + strlen("/me "));
            } else {
                execute(ctx->history, self, m, line, CHAT_COMMAND_MODE);
            }
        } else if (!string_is_empty(line)) {
            char selfname[TOX_MAX_NAME_LENGTH];
            uint16_t len = tox_get_self_name(m, (uint8_t *) selfname);
            selfname[len] = '\0';

            char timefrmt[TIME_STR_SIZE];
            get_time_str(timefrmt, sizeof(timefrmt));

            line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, line);

            if (!statusbar->is_online || tox_send_message(m, self->num, (uint8_t *) line, strlen(line)) == 0) {
                line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message.");
            } else {
                write_to_log(line, selfname, ctx->log, false);
            }
        }

        wclear(ctx->linewin);
        wmove(self->window, y2 - CURS_Y_OFFSET, 0);
        reset_buf(ctx);
    }

    if (ctx->len <= 0 && ctx->self_is_typing)
        set_self_typingstatus(self, m, 0);
}
Exemple #10
0
/**
 * @brief The entry point of NAEV.
 *
 *    @param[in] argc Number of arguments.
 *    @param[in] argv Array of argc arguments.
 *    @return EXIT_SUCCESS on success.
 */
int main( int argc, char** argv )
{
   char buf[PATH_MAX];

   /* Save the binary path. */
   binary_path = argv[0];
   
   /* Print the version */
   LOG( " "APPNAME" v%s", naev_version(0) );
#ifdef GIT_COMMIT
   DEBUG( " git HEAD at " GIT_COMMIT );
#endif /* GIT_COMMIT */

   /* Initializes SDL for possible warnings. */
   SDL_Init(0);

   /* Set up debug signal handlers. */
   debug_sigInit();

   /* Create the home directory if needed. */
   if (nfile_dirMakeExist("%s", nfile_basePath()))
      WARN("Unable to create naev directory '%s'", nfile_basePath());

   /* Must be initialized before input_init is called. */
   if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
      WARN("Unable to initialize SDL Video: %s", SDL_GetError());
      return -1;
   }

   /* Get desktop dimensions. */
#if SDL_VERSION_ATLEAST(1,2,10)
   const SDL_VideoInfo *vidinfo = SDL_GetVideoInfo();
   gl_screen.desktop_w = vidinfo->current_w;
   gl_screen.desktop_h = vidinfo->current_h;
#else /* #elif SDL_VERSION_ATLEAST(1,2,10) */
   gl_screen.desktop_w = 0;
   gl_screen.desktop_h = 0;
#endif /* #elif SDL_VERSION_ATLEAST(1,2,10) */

   /* We'll be parsing XML. */
   LIBXML_TEST_VERSION
   xmlInitParser();

   /* Input must be initialized for config to work. */
   input_init(); 

   /* Set the configuration. */
   snprintf(buf, PATH_MAX, "%s"CONF_FILE, nfile_basePath());
   conf_setDefaults(); /* set the default config values */
   conf_loadConfig(buf); /* Lua to parse the configuration file */
   conf_parseCLI( argc, argv ); /* parse CLI arguments */

   /* Enable FPU exceptions. */
#if !(HAS_WIN32) && defined(DEBUGGING)
   if (conf.fpu_except)
      feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );
#endif /* DEBUGGING */

   /* Open data. */
   if (ndata_open() != 0)
      ERR("Failed to open ndata.");

   /* Load the data basics. */
   LOG(" %s", ndata_name());
   DEBUG();

   /* Display the SDL Version. */
   print_SDLversion();
   DEBUG();

   /* random numbers */
   rng_init();


   /*
    * OpenGL
    */
   if (gl_init()) { /* initializes video output */
      ERR("Initializing video output failed, exiting...");
      SDL_Quit();
      exit(EXIT_FAILURE);
   }
   window_caption();
   gl_fontInit( NULL, NULL, FONT_SIZE ); /* initializes default font to size */
   gl_fontInit( &gl_smallFont, NULL, FONT_SIZE_SMALL ); /* small font */

   /* Display the load screen. */
   loadscreen_load();
   loadscreen_render( 0., "Initializing subsystems..." );
   time = SDL_GetTicks();


   /*
    * Input
    */
   if ((conf.joystick_ind >= 0) || (conf.joystick_nam != NULL)) {
      if (joystick_init()) WARN("Error initializing joystick input");
      if (conf.joystick_nam != NULL) { /* use the joystick name to find a joystick */
         if (joystick_use(joystick_get(conf.joystick_nam))) {
            WARN("Failure to open any joystick, falling back to default keybinds");
            input_setDefault();
         }
         free(conf.joystick_nam);
      }
      else if (conf.joystick_ind >= 0) /* use a joystick id instead */
         if (joystick_use(conf.joystick_ind)) {
            WARN("Failure to open any joystick, falling back to default keybinds");
            input_setDefault();
         }
   }


   /*
    * OpenAL - Sound
    */
   if (conf.nosound) {
      LOG("Sound is disabled!");
      sound_disabled = 1;
      music_disabled = 1;
   }
   if (sound_init()) WARN("Problem setting up sound!");
   music_choose("load");


   /* Misc graphics init */
   if (nebu_init() != 0) { /* Initializes the nebula */
      /* An error has happened */
      ERR("Unable to initialize the Nebula subsystem!");
      /* Weirdness will occur... */
   }
   gui_init(); /* initializes the GUI graphics */
   toolkit_init(); /* initializes the toolkit */
   map_init(); /* initializes the map. */
   cond_init(); /* Initialize conditional subsystem. */

   /* Data loading */
   load_all();

   /* Unload load screen. */
   loadscreen_unload();

   /* Start menu. */
   menu_main();

   /* Force a minimum delay with loading screen */
   if ((SDL_GetTicks() - time) < NAEV_INIT_DELAY)
      SDL_Delay( NAEV_INIT_DELAY - (SDL_GetTicks() - time) );
   time = SDL_GetTicks(); /* initializes the time */
   /* 
    * main loop
    */
   SDL_Event event;
   /* flushes the event loop since I noticed that when the joystick is loaded it
    * creates button events that results in the player starting out acceling */
   while (SDL_PollEvent(&event));
   /* primary loop */
   while (!quit) {
      while (SDL_PollEvent(&event)) { /* event loop */
         if (event.type == SDL_QUIT)
            quit = 1; /* quit is handled here */

         input_handle(&event); /* handles all the events and player keybinds */
      }

      main_loop();
   }


   /* Save configuration. */
   conf_saveConfig(buf);

   /* cleanup some stuff */
   player_cleanup(); /* cleans up the player stuff */
   gui_free(); /* cleans up the player's GUI */
   weapon_exit(); /* destroys all active weapons */
   pilots_free(); /* frees the pilots, they were locked up :( */
   cond_exit(); /* destroy conditional subsystem. */
   land_exit(); /* Destroys landing vbo and friends. */

   /* data unloading */
   unload_all();

   /* cleanup opengl fonts */
   gl_freeFont(NULL);
   gl_freeFont(&gl_smallFont);

   /* Close data. */
   ndata_close();

   /* Destroy conf. */
   conf_cleanup(); /* Frees some memory the configuration allocated. */

   /* exit subsystems */
   map_exit(); /* destroys the map. */
   toolkit_exit(); /* kills the toolkit */
   ai_exit(); /* stops the Lua AI magic */
   joystick_exit(); /* releases joystick */
   input_exit(); /* cleans up keybindings */
   nebu_exit(); /* destroys the nebula */
   gl_exit(); /* kills video output */
   sound_exit(); /* kills the sound */
   news_exit(); /* destroys the news. */

   /* Free the icon. */
   if (naev_icon)
      free(naev_icon);

   SDL_Quit(); /* quits SDL */

   /* all is well */
   exit(EXIT_SUCCESS);
}
Exemple #11
0
static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
{
    ChatContext *ctx = self->chatwin;

    int x, y, y2, x2;
    getyx(self->window, y, x);
    getmaxyx(self->window, y2, x2);

    if (x2 <= 0)
        return;

    /* ignore non-menu related input if active */
    if (self->help->active) {
        help_onKey(self, key);
        return;
    }

    if (ltr) {    /* char is printable */
        input_new_char(self, key, x, y, x2, y2);
        return;
    }

    if (line_info_onKey(self, key))
        return;

    input_handle(self, key, x, y, x2, y2);

    if (key == '\t') {    /* TAB key: auto-completes command */
        if (ctx->len > 1 && ctx->line[0] == '/') {
            int diff = -1;

            if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
                diff = dir_match(self, m, ctx->line, L"/avatar");
            else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0){
                const char status_cmd_list[3][8] = {
                  {"online"},
                  {"away"},
                  {"busy"},
                };
                diff = complete_line(self, status_cmd_list, 3, 8);
            } else
                diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE);

            if (diff != -1) {
                if (x + diff > x2 - 1) {
                    int wlen = MAX(0, wcswidth(ctx->line, sizeof(ctx->line) / sizeof(wchar_t)));
                    ctx->start = wlen < x2 ? 0 : wlen - x2 + 1;
                }
            } else {
                sound_notify(self, notif_error, 0, NULL);
            }
        } else {
            sound_notify(self, notif_error, 0, NULL);
        }
    } else if (key == '\n') {
        rm_trailing_spaces_buf(ctx);

        char line[MAX_STR_SIZE] = {0};

        if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1)
            memset(&line, 0, sizeof(line));

        if (!string_is_empty(line))
            add_line_to_hist(ctx);

        line_info_add(self, NULL, NULL, NULL, PROMPT, 0, 0, "%s", line);
        execute(ctx->history, self, m, line, GLOBAL_COMMAND_MODE);

        wclear(ctx->linewin);
        wmove(self->window, y2 - CURS_Y_OFFSET, 0);
        reset_buf(ctx);
    }
}