1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-07-03 20:27:45 +02:00

Add wide char support in toxic (issue #440)

Set current locale, use of get_wch instead of getch for reading, use
wctomb and friends to convert back from wchar_t, link with
cursesw. Unicode support is only added to chat windows.
This commit is contained in:
Manuel Argüelles 2013-08-21 16:19:35 -05:00
parent 46b69e6db1
commit 422a89d32d
7 changed files with 66 additions and 23 deletions

67
chat.c
View File

@ -2,12 +2,12 @@
* Toxic -- Tox Curses Client * Toxic -- Tox Curses Client
*/ */
#include <curses.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <limits.h>
#include "../../core/Messenger.h" #include "../../core/Messenger.h"
#include "../../core/network.h" #include "../../core/network.h"
@ -20,7 +20,7 @@
typedef struct { typedef struct {
int friendnum; int friendnum;
char line[MAX_STR_SIZE]; wchar_t line[MAX_STR_SIZE];
size_t pos; size_t pos;
WINDOW *history; WINDOW *history;
WINDOW *linewin; WINDOW *linewin;
@ -50,7 +50,6 @@ static void chat_onMessage(ToxWindow *self, Messenger *m, int num, uint8_t *msg,
getname(m, num, (uint8_t *) &nick); getname(m, num, (uint8_t *) &nick);
msg[len - 1] = '\0'; msg[len - 1] = '\0';
nick[MAX_NAME_LENGTH - 1] = '\0'; nick[MAX_NAME_LENGTH - 1] = '\0';
fix_name(msg);
fix_name(nick); fix_name(nick);
wattron(ctx->history, COLOR_PAIR(2)); wattron(ctx->history, COLOR_PAIR(2));
@ -140,7 +139,43 @@ int string_is_empty(char *string)
return rc; return rc;
} }
static void chat_onKey(ToxWindow *self, Messenger *m, int key) /* convert wide characters to null terminated string */
static char *wcs_to_char(wchar_t *string)
{
size_t len = 0;
char *ret = NULL;
len = wcstombs(NULL, string, 0);
if (len != (size_t) -1) {
len++;
ret = malloc(len);
wcstombs(ret, string, len);
} else {
ret = malloc(2);
ret[0] = ' ';
ret[1] = '\0';
}
return ret;
}
/* convert a wide char to null terminated string */
static char *wc_to_char(wchar_t ch)
{
int len = 0;
static char ret[MB_LEN_MAX + 1];
len = wctomb(ret, ch);
if (len == -1) {
ret[0] = ' ';
ret[1] = '\0';
} else {
ret[len] = '\0';
}
return ret;
}
static void chat_onKey(ToxWindow *self, Messenger *m, wint_t key)
{ {
ChatContext *ctx = (ChatContext *) self->x; ChatContext *ctx = (ChatContext *) self->x;
struct tm *timeinfo = get_time(); struct tm *timeinfo = get_time();
@ -150,18 +185,18 @@ static void chat_onKey(ToxWindow *self, Messenger *m, int key)
getmaxyx(self->window, y2, x2); getmaxyx(self->window, y2, x2);
/* Add printable chars to buffer and print on input space */ /* Add printable chars to buffer and print on input space */
if (isprint(key)) { if (iswprint(key)) {
if (ctx->pos != sizeof(ctx->line) - 1) { if (ctx->pos != sizeof(ctx->line) - 1) {
mvwaddch(self->window, y, x, key); mvwaddstr(self->window, y, x, wc_to_char(key));
ctx->line[ctx->pos++] = key; ctx->line[ctx->pos++] = key;
ctx->line[ctx->pos] = '\0'; ctx->line[ctx->pos] = L'\0';
} }
} }
/* BACKSPACE key: Remove one character from line */ /* BACKSPACE key: Remove one character from line */
else if (key == 0x107 || key == 0x8 || key == 0x7f) { else if (key == 0x107 || key == 0x8 || key == 0x7f) {
if (ctx->pos > 0) { if (ctx->pos > 0) {
ctx->line[--ctx->pos] = '\0'; ctx->line[--ctx->pos] = L'\0';
if (x == 0) if (x == 0)
mvwdelch(self->window, y - 1, x2 - 1); mvwdelch(self->window, y - 1, x2 - 1);
@ -172,15 +207,16 @@ static void chat_onKey(ToxWindow *self, Messenger *m, int key)
/* RETURN key: Execute command or print line */ /* RETURN key: Execute command or print line */
else if (key == '\n') { else if (key == '\n') {
char *line = wcs_to_char(ctx->line);
wclear(ctx->linewin); wclear(ctx->linewin);
wmove(self->window, y2 - CURS_Y_OFFSET, 0); wmove(self->window, y2 - CURS_Y_OFFSET, 0);
wclrtobot(self->window); wclrtobot(self->window);
if (ctx->line[0] == '/') if (line[0] == '/')
execute(self, ctx, m, ctx->line); execute(self, ctx, m, line);
else { else {
/* make sure the string has at least non-space character */ /* make sure the string has at least non-space character */
if (!string_is_empty(ctx->line)) { if (!string_is_empty(line)) {
uint8_t selfname[MAX_NAME_LENGTH]; uint8_t selfname[MAX_NAME_LENGTH];
getself_name(m, selfname, sizeof(selfname)); getself_name(m, selfname, sizeof(selfname));
fix_name(selfname); fix_name(selfname);
@ -191,9 +227,9 @@ static void chat_onKey(ToxWindow *self, Messenger *m, int key)
wattron(ctx->history, COLOR_PAIR(1)); wattron(ctx->history, COLOR_PAIR(1));
wprintw(ctx->history, "%s: ", selfname); wprintw(ctx->history, "%s: ", selfname);
wattroff(ctx->history, COLOR_PAIR(1)); wattroff(ctx->history, COLOR_PAIR(1));
wprintw(ctx->history, "%s\n", ctx->line); wprintw(ctx->history, "%s\n", line);
if (m_sendmessage(m, ctx->friendnum, (uint8_t *) ctx->line, strlen(ctx->line) + 1) == 0) { if (m_sendmessage(m, ctx->friendnum, (uint8_t *) line, strlen(line) + 1) == 0) {
wattron(ctx->history, COLOR_PAIR(3)); wattron(ctx->history, COLOR_PAIR(3));
wprintw(ctx->history, " * Failed to send message.\n"); wprintw(ctx->history, " * Failed to send message.\n");
wattroff(ctx->history, COLOR_PAIR(3)); wattroff(ctx->history, COLOR_PAIR(3));
@ -201,8 +237,9 @@ static void chat_onKey(ToxWindow *self, Messenger *m, int key)
} }
} }
ctx->line[0] = '\0'; ctx->line[0] = L'\0';
ctx->pos = 0; ctx->pos = 0;
free(line);
} }
} }
@ -331,7 +368,7 @@ void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd)
wprintw(ctx->history, "%s\n", id); wprintw(ctx->history, "%s\n", id);
} }
else if (strcmp(ctx->line, "/close") == 0) { else if (strcmp(cmd, "/close") == 0) {
int f_num = ctx->friendnum; int f_num = ctx->friendnum;
delwin(ctx->linewin); delwin(ctx->linewin);
del_window(self); del_window(self);

View File

@ -11,7 +11,7 @@ static void printip(ipbuf buf, IP ip)
sprintf((char *)buf, "%u.%u.%u.%u", ip.c[0], ip.c[1], ip.c[2], ip.c[3]); sprintf((char *)buf, "%u.%u.%u.%u", ip.c[0], ip.c[1], ip.c[2], ip.c[3]);
} }
static void dhtstatus_onKey(ToxWindow *self, Messenger *m, int key) static void dhtstatus_onKey(ToxWindow *self, Messenger *m, wint_t key)
{ {
switch (key) { switch (key) {
case KEY_UP: case KEY_UP:

View File

@ -2,7 +2,6 @@
* Toxic -- Tox Curses Client * Toxic -- Tox Curses Client
*/ */
#include <curses.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
#include <ctype.h> #include <ctype.h>
@ -84,7 +83,7 @@ int friendlist_onFriendAdded(Messenger *m, int num)
return 0; return 0;
} }
static void friendlist_onKey(ToxWindow *self, Messenger *m, int key) static void friendlist_onKey(ToxWindow *self, Messenger *m, wint_t key)
{ {
if (key == KEY_UP) { if (key == KEY_UP) {
if (--num_selected < 0) if (--num_selected < 0)

3
main.c
View File

@ -2,6 +2,7 @@
* Toxic -- Tox Curses Client * Toxic -- Tox Curses Client
*/ */
#define _XOPEN_SOURCE_EXTENDED
#include <curses.h> #include <curses.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@ -9,6 +10,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <signal.h> #include <signal.h>
#include <locale.h>
#ifdef _win32 #ifdef _win32
#include <direct.h> #include <direct.h>
@ -40,6 +42,7 @@ static void init_term()
{ {
/* Setup terminal */ /* Setup terminal */
signal(SIGWINCH, on_window_resize); signal(SIGWINCH, on_window_resize);
setlocale(LC_ALL, "");
initscr(); initscr();
cbreak(); cbreak();
keypad(stdscr, 1); keypad(stdscr, 1);

View File

@ -5,7 +5,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <curses.h>
#include "../../core/Messenger.h" #include "../../core/Messenger.h"
#include "../../core/network.h" #include "../../core/network.h"
@ -426,7 +425,7 @@ static void execute(ToxWindow *self, Messenger *m, char *u_cmd)
wprintw(self->window, "Invalid command.\n"); wprintw(self->window, "Invalid command.\n");
} }
static void prompt_onKey(ToxWindow *self, Messenger *m, int key) static void prompt_onKey(ToxWindow *self, Messenger *m, wint_t key)
{ {
/* Add printable characters to line */ /* Add printable characters to line */
if (isprint(key)) { if (isprint(key)) {

View File

@ -226,16 +226,18 @@ void draw_active_window(Messenger *m)
{ {
ToxWindow *a = active_window; ToxWindow *a = active_window;
wint_t ch = 0;
prepare_window(a->window); prepare_window(a->window);
a->blink = false; a->blink = false;
draw_bar(); draw_bar();
a->onDraw(a, m); a->onDraw(a, m);
/* Handle input */ /* Handle input */
int ch = getch(); get_wch(&ch);
if (ch == '\t' || ch == KEY_BTAB) if (ch == '\t' || ch == KEY_BTAB)
set_next_window(ch); set_next_window((int) ch);
else if (ch != ERR) else if (ch != ERR)
a->onKey(a, m, ch); a->onKey(a, m, ch);
} }

View File

@ -4,9 +4,12 @@
#ifndef _windows_h #ifndef _windows_h
#define _windows_h #define _windows_h
#define _XOPEN_SOURCE_EXTENDED
#include <curses.h> #include <curses.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <wctype.h>
#include <wchar.h>
#include "../../core/Messenger.h" #include "../../core/Messenger.h"
#define MAX_WINDOWS_NUM 32 #define MAX_WINDOWS_NUM 32
#define MAX_FRIENDS_NUM 100 #define MAX_FRIENDS_NUM 100
@ -23,7 +26,7 @@
typedef struct ToxWindow_ ToxWindow; typedef struct ToxWindow_ ToxWindow;
struct ToxWindow_ { struct ToxWindow_ {
void(*onKey)(ToxWindow *, Messenger *, int); void(*onKey)(ToxWindow *, Messenger *, wint_t);
void(*onDraw)(ToxWindow *, Messenger *); void(*onDraw)(ToxWindow *, Messenger *);
void(*onInit)(ToxWindow *, Messenger *); void(*onInit)(ToxWindow *, Messenger *);
void(*onFriendRequest)(ToxWindow *, uint8_t *, uint8_t *, uint16_t); void(*onFriendRequest)(ToxWindow *, uint8_t *, uint8_t *, uint16_t);