/* add the recently connected client to the game as a player */ void join_player(struct socket_node *socket) { struct packet_version packet; struct packet_welcome packet2; int i; struct action_node *action; struct socket_node *p; socket->player = get_free_player(); init_player(socket->player, INIT_PLAYER_HUMAN); /* send version */ packet.version = swap_int(PROGRAM_VERSION); send_socket(socket, PACKET_VERSION, &packet, sizeof(struct packet_version)); /* send welcome */ packet2.player = swap_int(socket->player); send_socket(socket, PACKET_WELCOME, &packet2, sizeof(struct packet_welcome)); /* send all previous players to the new client */ for (i = 0; i < NUM_PLAYERS; i++) { if (IS_ACTIVE(i) && i != socket->player) { send_player_info(socket, i, 0); /* send any already selected action */ action = find_action(i, current_turn); if (action && action->action != ACTION_NOTHING) send_action(socket, i, current_turn); } } /* send the new player to ALL clients */ for (p = socket_list; p != NULL; p = p->next) { if (p->type == SOCKET_CLIENT) send_player_info(p, socket->player, 1); } telegram("\n%s has\nconnected to the server.\n", GET_NAME(socket->player)); }
static PyObject* send_action_python(PyObject* self, PyObject* args){ int action; PyObject* d; if (!PyArg_ParseTuple(args, "Oi", &d,&action)) return NULL; struct ms_control* data; data = (struct ms_control*)PyLong_AsVoidPtr(d); send_action(data,action); return Py_BuildValue("i",0); }
void Keyboard::Process() { while(!m_bStop && conn && dbus_connection_read_write_dispatch(conn, 0)) { int ch[8]; int chnum = 0; while ((ch[chnum] = getchar()) != EOF) chnum++; if (chnum > 1) ch[0] = ch[chnum - 1] | (ch[chnum - 2] << 8); if (m_keymap[ch[0]] != 0) send_action(m_keymap[ch[0]]); else Sleep(20); } }
//this function makes the robot avoid the obstacle running for a small distance in another direction //this direction depends on the current angle and position void obstacle_avoid(){ int quadrant = robot.t / 90; int right_left_n = robot.x / BORDER_X_MAX/2; int up_down_n = robot.y / BORDER_Y_MAX/2; int angles[4][2][2]; //first quadrant angles[0][0][0]=45; //down left angles[0][0][1]=-45; //down right angles[0][1][0]=45; //up left angles[0][1][1]=-45; //up right //second quadrant angles[1][0][0]=-45; //down left angles[1][0][1]=-45; //down right angles[1][1][0]=45; //up left angles[1][1][1]=45; //up right //third quadrant angles[2][0][0]=-45; //down left angles[2][0][1]=45; //down right angles[2][1][0]=-45; //up left angles[2][1][1]=45; //up right //fourth quadrant angles[3][0][0]=45; //down left angles[3][0][1]=45; //down right angles[3][1][0]=-45; //up left angles[3][1][1]=-45; //up right int angle=(robot.t+angles[quadrant][up_down_n][right_left_n])%360; if(robot_rank ==0 && send_action_flag) send_action(next,angle,40,NORMAL_SPEED/2); set_motors_speed(NORMAL_SPEED); turn_absolute_fb(angle,get_cal_location(robot.x,robot.y)); robot.t=angle; run_relative((int)40*360.0/18); while(!command_finish()); robot.x= robot.x + 40*sin(robot.t*M_PI/180); robot.y= robot.y + 40*cos(robot.t*M_PI/180); printf("\n\n>>>>>>>>pos %d %d %d\n\n",robot.x,robot.y,robot.t); }
void Keyboard::Process() { while(!m_bStop) { CLog::Log(LOGDEBUG, "Keyboard: Process() m_bStop %d", m_bStop); if (conn) dbus_connection_read_write_dispatch(conn, 0); int ch[8]; int chnum = 0; while ((ch[chnum] = getchar()) != EOF) chnum++; if (chnum > 1) ch[0] = ch[chnum - 1] | (ch[chnum - 2] << 8); if (chnum > 0) CLog::Log(LOGDEBUG, "Keyboard: character %c", ch[0]); if (m_keymap[ch[0]] != 0) send_action(m_keymap[ch[0]]); else Sleep(20); } }
int main(int argc, char **argv) { XmrApp *app; GOptionContext *context; GError *error = NULL; PlayerAction player_action = ActionNone; gchar *tmp_dir = NULL; #if !GLIB_CHECK_VERSION(2, 32, 0) g_thread_init(NULL); #endif // !!! glib manual says since version 2.36 // but ubuntu 13.04 !!! #if !GLIB_CHECK_VERSION(2, 35, 7) g_type_init(); #endif setlocale(LC_ALL, NULL); #ifdef ENABLE_NLS /* initialize i18n */ bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain(GETTEXT_PACKAGE); #endif context = g_option_context_new(NULL); g_option_context_add_main_entries(context, options, GETTEXT_PACKAGE); g_option_context_add_group(context, gtk_get_option_group(TRUE)); g_option_context_add_group(context, gst_init_get_option_group()); if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) { g_print(_("%s\nRun '%s --help' to see a full list of available command line options.\n"), error->message, argv[0]); g_error_free(error); g_option_context_free(context); exit(1); } g_option_context_free(context); if (action_play){ player_action = ActionPlay; }else if (action_pause){ player_action = ActionPause; }else if(action_next){ player_action = ActionNext; }else if(action_love){ player_action = ActionLove; }else if(action_hate){ player_action = ActionHate; } if (player_action != ActionNone) { DBusConnection *bus; DBusError dbus_error; dbus_error_init(&dbus_error); bus = dbus_bus_get(DBUS_BUS_SESSION, &dbus_error); if (!bus) { g_warning ("Failed to connect to the D-BUS daemon: %s", dbus_error.message); dbus_error_free(&dbus_error); exit(1); } dbus_connection_setup_with_g_main(bus, NULL); send_action(bus, player_action); // exit directly return 0; } xmr_debug_enable(debug); gst_init(&argc, &argv); curl_global_init(CURL_GLOBAL_ALL); // this make our XmrRadio always works g_object_set(gtk_settings_get_default(), "gtk-button-images", TRUE, NULL); // ensure folder exists tmp_dir = g_strdup_printf("%s/%s", g_get_tmp_dir(), PACKAGE); g_mkdir_with_parents(tmp_dir, 0755); app = xmr_app_instance(); g_application_run(G_APPLICATION(app), argc, argv); // remove ... list_file(tmp_dir, FALSE, remove_file, NULL); g_free(tmp_dir); g_object_unref(app); curl_global_cleanup(); return 0; }
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key) { ChatContext *ctx = (ChatContext *) self->chatwin; StatusBar *statusbar = (StatusBar *) self->stb; int x, y, y2, x2; getyx(self->window, y, x); getmaxyx(self->window, y2, x2); /* BACKSPACE key: Remove one character from line */ if (key == 0x107 || key == 0x8 || key == 0x7f) { if (ctx->pos > 0) { ctx->line[--ctx->pos] = L'\0'; if (x == 0) mvwdelch(self->window, y - 1, x2 - 1); else mvwdelch(self->window, y, x - 1); } } else /* Add printable chars to buffer and print on input space */ #if HAVE_WIDECHAR if (iswprint(key)) { #else if (isprint(key)) { #endif if (ctx->pos < (MAX_STR_SIZE-1)) { mvwaddstr(self->window, y, x, wc_to_char(key)); ctx->line[ctx->pos++] = key; ctx->line[ctx->pos] = L'\0'; } } /* RETURN key: Execute command or print line */ else if (key == '\n') { uint8_t *line = wcs_to_char(ctx->line); line[ctx->pos+1] = '\0'; wclear(ctx->linewin); wmove(self->window, y2 - CURS_Y_OFFSET, 0); wclrtobot(self->window); bool close_win = false; if (line[0] == '/') { if (close_win = !strncmp(line, "/close", strlen("/close"))) { int f_num = self->num; delwin(ctx->linewin); delwin(statusbar->topline); del_window(self); disable_chatwin(f_num); } else if (!strncmp(line, "/me ", strlen("/me "))) send_action(self, ctx, m, line + strlen("/me ")); else if (!strncmp(line, "/help", strlen("/help"))) print_chat_help(ctx); else if (!strncmp(line, "/invite", strlen("/invite"))) chat_groupinvite(self, ctx, m, line + strlen("/invite ")); else if(!strncmp(line, "/sendfile ", strlen("/sendfile "))) chat_sendfile(self, ctx, m, line + strlen("/sendfile ")); else execute(ctx->history, self->prompt, m, line, ctx->pos); } else { /* make sure the string has at least non-space character */ if (!string_is_empty(line)) { uint8_t selfname[TOX_MAX_NAME_LENGTH]; tox_getselfname(m, selfname, TOX_MAX_NAME_LENGTH); print_time(ctx->history); wattron(ctx->history, COLOR_PAIR(GREEN)); wprintw(ctx->history, "%s: ", selfname); wattroff(ctx->history, COLOR_PAIR(GREEN)); if (line[0] == '>') { wattron(ctx->history, COLOR_PAIR(GREEN)); wprintw(ctx->history, "%s\n", line); wattroff(ctx->history, COLOR_PAIR(GREEN)); } else wprintw(ctx->history, "%s\n", line); if (!statusbar->is_online || tox_sendmessage(m, self->num, line, strlen(line) + 1) == 0) { wattron(ctx->history, COLOR_PAIR(RED)); wprintw(ctx->history, " * Failed to send message.\n"); wattroff(ctx->history, COLOR_PAIR(RED)); } } } if (close_win) { free(ctx); free(statusbar); } else { ctx->line[0] = L'\0'; ctx->pos = 0; } free(line); } } static void chat_onDraw(ToxWindow *self, Tox *m) { curs_set(1); int x, y; getmaxyx(self->window, y, x); ChatContext *ctx = (ChatContext *) self->chatwin; /* Draw status bar */ StatusBar *statusbar = (StatusBar *) self->stb; mvwhline(statusbar->topline, 1, 0, '-', x); wmove(statusbar->topline, 0, 0); /* Draw name, status and note in statusbar */ if (statusbar->is_online) { char *status_text = "Unknown"; int colour = WHITE; TOX_USERSTATUS status = statusbar->status; switch(status) { case TOX_USERSTATUS_NONE: status_text = "Online"; colour = GREEN; break; case TOX_USERSTATUS_AWAY: status_text = "Away"; colour = YELLOW; break; case TOX_USERSTATUS_BUSY: status_text = "Busy"; colour = RED; break; } wattron(statusbar->topline, A_BOLD); wprintw(statusbar->topline, " %s ", self->name); wattroff(statusbar->topline, A_BOLD); wattron(statusbar->topline, COLOR_PAIR(colour) | A_BOLD); wprintw(statusbar->topline, "[%s]", status_text); wattroff(statusbar->topline, COLOR_PAIR(colour) | A_BOLD); } else { wattron(statusbar->topline, A_BOLD); wprintw(statusbar->topline, " %s ", self->name); wattroff(statusbar->topline, A_BOLD); wprintw(statusbar->topline, "[Offline]"); } /* Reset statusbar->statusmsg on window resize */ if (x != self->x) { uint8_t statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH] = {'\0'}; tox_copy_statusmessage(m, self->num, statusmsg, TOX_MAX_STATUSMESSAGE_LENGTH); snprintf(statusbar->statusmsg, sizeof(statusbar->statusmsg), "%s", statusmsg); statusbar->statusmsg_len = tox_get_statusmessage_size(m, self->num); } self->x = x; /* Truncate note if it doesn't fit in statusbar */ uint16_t maxlen = x - getcurx(statusbar->topline) - 6; if (statusbar->statusmsg_len > maxlen) { statusbar->statusmsg[maxlen] = '\0'; statusbar->statusmsg_len = maxlen; } if (statusbar->statusmsg[0]) { wattron(statusbar->topline, A_BOLD); wprintw(statusbar->topline, " | %s | ", statusbar->statusmsg); wattroff(statusbar->topline, A_BOLD); } wprintw(statusbar->topline, "\n"); mvwhline(ctx->linewin, 0, 0, '_', x); wrefresh(self->window); }
//return REACHED if position reached, OBSTACLE if stopped because of obstacle A CUSTOM STOP MESSAGE MUST BE SENT, CUSTOM_STOP_MESSAGE if stopped because a custom message was sent //robot position is updated //position is reached running for distance in steps <=200 (first the dist%200 than n steps dist/200) //it sleeps 1s after each step int go_to_position(pos_t target_pos, int margin, int speed){ int32_t tacho_dist, start_tacho, end_tacho; int angle, dist; int i; if(robot_rank == 0) while(wait); compute_polar_coord(target_pos, &dist, &angle,margin); target_pos.x = robot.x + dist*sin(angle*M_PI/180); target_pos.y = robot.y + dist*cos(angle*M_PI/180); //start movement, in two steps if bigger than 200 int div = dist/200; int mod = dist%200; int step; for(i = 0; i < div+1 ; i++){ if(i == div) step = mod; else step = 200; if(robot_rank == 0 && send_action_flag) send_action(next, angle, step, speed/2); //vado alla posizione set_motors_speed(SLOW_SPEED); turn_absolute_fb(angle, get_cal_location(robot.x,robot.y)); //aggiorno posizione final; robot.t = angle;//get_gyro_value(); printf("robot.t = %d\n",robot.t); //save initial tacho counts start_tacho=get_motorR_position(); set_motors_speed(speed); run_relative((int)(step*360.0/18)); while(!command_finish()){ if(cancel){ //cancel = 0; run_relative(0); end_tacho = get_motorR_position(); tacho_dist = end_tacho-start_tacho; dist = tacho_dist/20.0; robot.x = robot.x + dist*sin(robot.t*M_PI/180); robot.y = robot.y + dist*cos(robot.t*M_PI/180); printf("\n\n>>>>>>>>pos %d %d %d\n\n",robot.x,robot.y,robot.t); if(send_action_flag) send_cancel(next, dist); // Send to ourself an action in order came closer act_val.dist = cancel - dist; act_val.angle = robot.t; act++; return CUSTOM_STOP_MESSAGE; } if(obstacle()){ run_relative(0); end_tacho = get_motorR_position(); tacho_dist = end_tacho-start_tacho; dist = tacho_dist/20.0; printf("step %d dist %d\n",step,dist); if(step-dist < STOP_DIST*18/360.0){ set_motors_speed(speed); run_relative((int)((step-dist)*360.0/18)); return REACHED; } printf("tacho dist %ld dist %ld\n",tacho_dist,dist); robot.x = robot.x + dist*sin(robot.t*M_PI/180); robot.y = robot.y + dist*cos(robot.t*M_PI/180); printf("\n\n>>>>>>>>pos %d %d %d\n\n",robot.x,robot.y,robot.t); if(send_action_flag) send_cancel(next,dist); // HERE WE MUST SEND A CUSTOM MESSAGE STOP TO FOLLOWING ROBOT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // HERE WE MUST SEND A CUSTOM MESSAGE STOP TO FOLLOWING ROBOT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! return OBSTACLE; } } sleep(1); } //update pos robot.x = target_pos.x; robot.y = target_pos.y; printf("\n\n>>>>>>>>pos %d %d %d\n\n",robot.x,robot.y,robot.t); return REACHED; }
/* SIGALRM handler: extract and send first command in commandlist */ void sigalrm_handler() { sigprocmask(SIG_BLOCK, &sigiomask, NULL); if ( Mem->LastInterruptTime != Mem->CurrentTime ){ if ( !Mem->ClockStopped && Mem->CurrentTime-1 != Mem->LastInterruptTime ) my_error("Missed a cycle??"); if ( !Mem->ClockStopped && Mem->InterruptsThisCycle < Mem->CP_interrupts_per_cycle-1 ) my_error("Only %d interrupts last cycle",Mem->InterruptsThisCycle); Mem->LastInterruptTime = Mem->CurrentTime; Mem->InterruptsThisCycle = 0; } Mem->InterruptsThisCycle++; /* Don't act until near the end of a cycle */ /* there's some leeway in case there aren't enough interrupts in the cycle */ Bool behave_time = TRUE; if ( Mem->CP_interrupts_per_cycle - Mem->InterruptsThisCycle > Mem->CP_interrupts_left_to_act){ behave_time = FALSE; } if (Mem->ClockStopped) Mem->StoppedClockMSec += Mem->TimerInterval; if (alrsigs_since_iosig++ > Mem->CP_interrupts_per_cycle * Mem->CP_max_cycles_since_io){ Mem->ServerAlive = FALSE; sigprocmask(SIG_UNBLOCK, &sigiomask, NULL); return; } /* If a sight is definitely coming every cycle, don't act until getting the sight */ /* Don't wait if we're in transition to a longer sight interval */ if ( Mem->CP_wait_for_sight && Mem->MySightInterval() < Mem->SP_simulator_step && Mem->LastSightTime < Mem->CurrentTime && !((Mem->ChangeView.valid() || Mem->ChangeView.valid(Mem->CurrentTime-1)) && (Mem->ChangeView.width > Mem->ViewWidth || Mem->ChangeView.qual > Mem->ViewQuality)) ) { LogAction4(200,"Waiting for sight... (%d %d)", Mem->ChangeView.valid(),Mem->ChangeView.valid(Mem->CurrentTime-1)); sigprocmask(SIG_UNBLOCK, &sigiomask, NULL); return; } if ( Mem->CurrentTime > Mem->LastActionOpTime && behave_time ){ if ( !Mem->ClockStopped && Mem->CurrentTime-1 != Mem->LastActionOpTime && Mem->LastActionOpTime != 0 ) my_error("Missed a cycle!! (%d %d)",Mem->LastActionOpTime.t,Mem->LastActionOpTime.s); if ( Mem->NewSight ) Mem->FirstActionOpSinceLastSight = TRUE; Mem->update(); behave(); //my_error("acting after %d interrupts",Mem->InterruptsThisCycle); Mem->LastActionOpTime = Mem->CurrentTime; Mem->FirstActionOpSinceLastSight = FALSE; } else if ( Mem->Tuned ){ sigprocmask(SIG_UNBLOCK, &sigiomask, NULL); return; } /* the server now accepts multiple commands together (after 5.23) if (0 && Mem->TooSoonForAnotherSend()) { LogAction2(200, "It's too soon to send another command. Waiting"); } else { */ /* However, dumping on the network all at once seems to cause some problems, so we'll still send one action per interrupt (we should be interrupting quite often now) */ sendbuf[0] = 0; /* do this before the action so it's processed first */ if ( Mem->PointTo.valid() ){ if ( Mem->PointTo.time < Mem->CurrentTime-1 ) my_error("old point_to"); //send_message( Mem->PointTo.command, Mem->sock ); if ( sendbuf[0] == 0 ) strcpy( sendbuf, Mem->PointTo.command ); else strcat( sendbuf, Mem->PointTo.command ); Mem->PointTo.type = CMD_none; /* so it's no longer valid */ } if ( Mem->Action->valid() ) { send_action(sendbuf); } //else if ( Mem->ResendNeeded() ){ resend_last_action(sendbuf); } //else if ( Mem->TurnNeck.valid() ){ if ( Mem->TurnNeck.time < Mem->CurrentTime-1 ) my_error("old turn_neck"); //send_message( Mem->TurnNeck.command, Mem->sock ); if ( sendbuf[0] == 0 ) strcpy( sendbuf, Mem->TurnNeck.command ); else strcat( sendbuf, Mem->TurnNeck.command ); Mem->turn_necks++; Mem->TurnNeck.type = CMD_none; /* so it's no longer valid */ } //else if ( Mem->ChangeView.valid() ){ if ( Mem->ChangeView.time < Mem->CurrentTime-1 && Mem->Tuned ) my_error("old change_view"); Bool send_change_view = TRUE; if ( Mem->LastChangeViewTime == Mem->CurrentTime ) send_change_view = FALSE; //already sent one this cycle if ( Mem->CP_tune_timing && send_change_view ){ if ( Mem->ChangeView.qual==VQ_High && Mem->ChangeView.width==VW_Normal ){ if ( Mem->SP_send_step / Mem->MySightInterval() == 4 ){ if ( Mem->SightsPrev2Cycle != 3 || Mem->SightsPrevCycle != 2 || Mem->SightsThisCycle != 1 ){ // my_error("Tuning Conditions not met 1 (%d %d %d)\n", // Mem->SightsPrev2Cycle, Mem->SightsPrevCycle, Mem->SightsThisCycle); send_change_view = FALSE; // don't do it until those conditions are met } else{ my_error("tuned"); Mem->Tuned = TRUE; } } else if ( Mem->SP_send_step / Mem->MySightInterval() == 2 ){ if ( Mem->SightsPrev2Cycle != 1 || Mem->SightsPrevCycle != 1 || Mem->SightsThisCycle != 1 ){ //my_error("TuningConditions not met 2 (%d %d %d)\n", // Mem->SightsPrev2Cycle, Mem->SightsPrevCycle, Mem->SightsThisCycle); send_change_view = FALSE; // don't do it until those conditions are met } else{ Mem->Tuned = TRUE; } } } if ( Mem->ChangeView.qual < VQ_High || Mem->ChangeView.width < VW_Normal ) Mem->Tuned = FALSE; } if ( send_change_view ){ //send_message( Mem->ChangeView.command, Mem->sock ); if ( sendbuf[0] == 0 ) strcpy( sendbuf, Mem->ChangeView.command ); else strcat( sendbuf, Mem->ChangeView.command ); Mem->ChangeView.type = CMD_none; /* so it's no longer valid */ Mem->LastChangeViewTime = Mem->CurrentTime; } } if ( Mem->AttentionTo.valid() ){ if ( Mem->AttentionTo.time < Mem->CurrentTime-1 ) my_error("old attention_to"); //send_message( Mem->AttentionTo.command, Mem->sock ); if ( sendbuf[0] == 0 ) strcpy( sendbuf, Mem->AttentionTo.command ); else strcat( sendbuf, Mem->AttentionTo.command ); Mem->AttentionTo.type = CMD_none; /* so it's no longer valid */ } if ( Mem->Ear.valid() ){ if ( Mem->Ear.time < Mem->CurrentTime-1 ) my_error("old ear"); //send_message( Mem->AttentionTo.command, Mem->sock ); if ( sendbuf[0] == 0 ) strcpy( sendbuf, Mem->Ear.command ); else strcat( sendbuf, Mem->Ear.command ); Mem->Ear.type = CMD_none; /* so it's no longer valid */ } //else // if ( Mem->Communicate() ){ // LogAction2(200,"saying something"); //send_message( Mem->SayBuffer(), Mem->sock ); // if ( sendbuf[0] == 0 ) // strcpy( sendbuf, Mem->SayBuffer() ); // else // strcat( sendbuf, Mem->SayBuffer() ); //} if ( sendbuf[0] != 0 ) send_message( sendbuf, Mem->sock ); sigprocmask(SIG_UNBLOCK, &sigiomask, NULL); }
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); }
static void chat_onKey(ToxWindow *self, Tox *m, wint_t key) { ChatContext *ctx = self->chatwin; StatusBar *statusbar = self->stb; int x, y, y2, x2; getyx(self->window, y, x); getmaxyx(self->window, y2, x2); int cur_len = 0; if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key: Remove character behind pos */ if (ctx->pos > 0) { cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1])); del_char_buf_bck(ctx->line, &ctx->pos, &ctx->len); if (x == 0) wmove(self->window, y-1, x2 - cur_len); else wmove(self->window, y, x - cur_len); } else { beep(); } } else if (key == KEY_DC) { /* DEL key: Remove character at pos */ if (ctx->pos != ctx->len) del_char_buf_frnt(ctx->line, &ctx->pos, &ctx->len); else beep(); } else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */ if (ctx->pos > 0) { discard_buf(ctx->line, &ctx->pos, &ctx->len); wmove(self->window, y2 - CURS_Y_OFFSET, 0); } else { beep(); } } else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */ if (ctx->pos != ctx->len) kill_buf(ctx->line, &ctx->pos, &ctx->len); else beep(); } else if (key == KEY_HOME) { /* HOME key: Move cursor to beginning of line */ if (ctx->pos > 0) { ctx->pos = 0; wmove(self->window, y2 - CURS_Y_OFFSET, 0); } } else if (key == KEY_END) { /* END key: move cursor to end of line */ if (ctx->pos != ctx->len) { ctx->pos = ctx->len; mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, (CHATBOX_HEIGHT-1)*x2)), y2, x2); } } else if (key == KEY_LEFT) { if (ctx->pos > 0) { --ctx->pos; cur_len = MAX(1, wcwidth(ctx->line[ctx->pos])); if (x == 0) wmove(self->window, y-1, x2 - cur_len); else wmove(self->window, y, x - cur_len); } else { beep(); } } else if (key == KEY_RIGHT) { if (ctx->pos < ctx->len) { cur_len = MAX(1, wcwidth(ctx->line[ctx->pos])); ++ctx->pos; if (x == x2-1) wmove(self->window, y+1, 0); else wmove(self->window, y, x + cur_len); } else { beep(); } } else if (key == KEY_UP) { /* fetches previous item in history */ fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot, &ctx->hst_pos, LN_HIST_MV_UP); mv_curs_end(self->window, ctx->len, y2, x2); } else if (key == KEY_DOWN) { /* fetches next item in history */ fetch_hist_item(ctx->line, &ctx->pos, &ctx->len, ctx->ln_history, ctx->hst_tot, &ctx->hst_pos, LN_HIST_MV_DWN); mv_curs_end(self->window, ctx->len, y2, x2); } else if (key == '\t') { /* TAB key: completes command */ if (ctx->len > 1 && ctx->line[0] == '/') { int diff = complete_line(ctx->line, &ctx->pos, &ctx->len, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE); if (diff != -1) { if (x + diff > x2 - 1) { int ofst = (x + diff - 1) - (x2 - 1); wmove(self->window, y+1, ofst); } else { wmove(self->window, y, x+diff); } } else { beep(); } } else { beep(); } } else #if HAVE_WIDECHAR if (iswprint(key)) #else if (isprint(key)) #endif { /* prevents buffer overflows and strange behaviour when cursor goes past the window */ if ( (ctx->len < MAX_STR_SIZE-1) && (ctx->len < (x2 * (CHATBOX_HEIGHT - 1)-1)) ) { add_char_to_buf(ctx->line, &ctx->pos, &ctx->len, key); if (x == x2-1) wmove(self->window, y+1, 0); else wmove(self->window, y, x + MAX(1, wcwidth(key))); } } /* RETURN key: Execute command or print line */ else if (key == '\n') { uint8_t line[MAX_STR_SIZE]; if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) memset(&line, 0, sizeof(line)); wclear(ctx->linewin); wmove(self->window, y2 - CURS_Y_OFFSET, 0); wclrtobot(self->window); bool close_win = false; if (!string_is_empty(line)) add_line_to_hist(ctx->line, ctx->len, ctx->ln_history, &ctx->hst_tot, &ctx->hst_pos); if (line[0] == '/') { if (close_win = !strcmp(line, "/close")) { int f_num = self->num; delwin(ctx->linewin); delwin(statusbar->topline); del_window(self); disable_chatwin(f_num); } 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)) { uint8_t selfname[TOX_MAX_NAME_LENGTH]; tox_get_self_name(m, selfname, TOX_MAX_NAME_LENGTH); print_time(ctx->history); wattron(ctx->history, COLOR_PAIR(GREEN)); wprintw(ctx->history, "%s: ", selfname); wattroff(ctx->history, COLOR_PAIR(GREEN)); if (line[0] == '>') { wattron(ctx->history, COLOR_PAIR(GREEN)); wprintw(ctx->history, "%s\n", line); wattroff(ctx->history, COLOR_PAIR(GREEN)); } else wprintw(ctx->history, "%s\n", line); if (!statusbar->is_online || tox_send_message(m, self->num, line, strlen(line) + 1) == 0) { wattron(ctx->history, COLOR_PAIR(RED)); wprintw(ctx->history, " * Failed to send message.\n"); wattroff(ctx->history, COLOR_PAIR(RED)); } } if (close_win) { free(ctx); free(statusbar); } else { reset_buf(ctx->line, &ctx->pos, &ctx->len); } } }