Add initial support for differing keyboard layouts
This is plain ugly though. It will have to be re-designed.
This commit is contained in:
parent
ceac882f17
commit
bf17f07bc3
237
src/keyboard.c
237
src/keyboard.c
@ -33,9 +33,11 @@ static char const _license[] =
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
#include <libintl.h>
|
#include <libintl.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <gdk/gdkkeysyms.h>
|
#include <gdk/gdkkeysyms.h>
|
||||||
@ -55,6 +57,10 @@ static char const _license[] =
|
|||||||
#define _(string) gettext(string)
|
#define _(string) gettext(string)
|
||||||
#define N_(string) (string)
|
#define N_(string) (string)
|
||||||
|
|
||||||
|
#ifndef PROGNAME_KEYBOARD
|
||||||
|
# define PROGNAME_KEYBOARD "keyboard"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Keyboard */
|
/* Keyboard */
|
||||||
/* private */
|
/* private */
|
||||||
@ -104,6 +110,21 @@ typedef struct _KeyboardLayoutDefinition
|
|||||||
KeyboardKeyDefinition const * keys;
|
KeyboardKeyDefinition const * keys;
|
||||||
} KeyboardLayoutDefinition;
|
} KeyboardLayoutDefinition;
|
||||||
|
|
||||||
|
typedef enum _KeyboardLayoutType
|
||||||
|
{
|
||||||
|
KLT_QWERTY = 0,
|
||||||
|
KLT_QWERTZ,
|
||||||
|
KLT_AZERTY
|
||||||
|
} KeyboardLayoutType;
|
||||||
|
#define KLT_LAST KLT_AZERTY
|
||||||
|
#define KLT_COUNT (KLT_LAST + 1)
|
||||||
|
|
||||||
|
typedef struct _KeyboardLayoutTypeName
|
||||||
|
{
|
||||||
|
KeyboardLayoutType type;
|
||||||
|
char const * name;
|
||||||
|
} KeyboardLayoutTypeName;
|
||||||
|
|
||||||
|
|
||||||
/* constants */
|
/* constants */
|
||||||
static char const * _authors[] =
|
static char const * _authors[] =
|
||||||
@ -112,6 +133,13 @@ static char const * _authors[] =
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const KeyboardLayoutTypeName _keyboard_layout_type_name[] =
|
||||||
|
{
|
||||||
|
{ KLT_QWERTY, "us" },
|
||||||
|
{ KLT_QWERTZ, "de" },
|
||||||
|
{ KLT_AZERTY, "fr" }
|
||||||
|
};
|
||||||
|
|
||||||
static const DesktopMenu _keyboard_menu_file[] =
|
static const DesktopMenu _keyboard_menu_file[] =
|
||||||
{
|
{
|
||||||
{ N_("_Quit"), G_CALLBACK(on_file_quit), GTK_STOCK_QUIT,
|
{ N_("_Quit"), G_CALLBACK(on_file_quit), GTK_STOCK_QUIT,
|
||||||
@ -146,7 +174,7 @@ static const DesktopMenubar _keyboard_menubar[] =
|
|||||||
|
|
||||||
|
|
||||||
/* variables */
|
/* variables */
|
||||||
static KeyboardKeyDefinition const _keyboard_layout_letters[] =
|
static KeyboardKeyDefinition const _keyboard_layout_letters_qwerty[] =
|
||||||
{
|
{
|
||||||
{ 0, 2, 0, XK_q, "q" },
|
{ 0, 2, 0, XK_q, "q" },
|
||||||
{ 0, 0, XK_Shift_L, XK_Q, "Q" },
|
{ 0, 0, XK_Shift_L, XK_Q, "Q" },
|
||||||
@ -216,6 +244,153 @@ static KeyboardKeyDefinition const _keyboard_layout_letters[] =
|
|||||||
{ 0, 0, 0, 0, NULL }
|
{ 0, 0, 0, 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static KeyboardKeyDefinition const _keyboard_layout_letters_qwertz[] =
|
||||||
|
{
|
||||||
|
{ 0, 2, 0, XK_q, "q" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_Q, "Q" },
|
||||||
|
{ 0, 2, 0, XK_w, "w" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_W, "W" },
|
||||||
|
{ 0, 2, 0, XK_e, "e" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_E, "E" },
|
||||||
|
{ 0, 2, 0, XK_r, "r" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_R, "R" },
|
||||||
|
{ 0, 2, 0, XK_t, "t" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_T, "T" },
|
||||||
|
{ 0, 2, 0, XK_z, "z" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_Z, "Z" },
|
||||||
|
{ 0, 2, 0, XK_u, "u" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_U, "U" },
|
||||||
|
{ 0, 2, 0, XK_i, "i" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_I, "I" },
|
||||||
|
{ 0, 2, 0, XK_o, "o" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_O, "O" },
|
||||||
|
{ 0, 2, 0, XK_p, "p" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_P, "P" },
|
||||||
|
{ 1, 1, 0, 0, NULL },
|
||||||
|
{ 1, 2, 0, XK_a, "a" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_A, "A" },
|
||||||
|
{ 1, 2, 0, XK_s, "s" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_S, "S" },
|
||||||
|
{ 1, 2, 0, XK_d, "d" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_D, "D" },
|
||||||
|
{ 1, 2, 0, XK_f, "f" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_F, "F" },
|
||||||
|
{ 1, 2, 0, XK_g, "g" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_G, "G" },
|
||||||
|
{ 1, 2, 0, XK_h, "h" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_H, "H" },
|
||||||
|
{ 1, 2, 0, XK_j, "j" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_J, "J" },
|
||||||
|
{ 1, 2, 0, XK_k, "k" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_K, "K" },
|
||||||
|
{ 1, 2, 0, XK_l, "l" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_L, "L" },
|
||||||
|
{ 2, 2, 0, XK_Shift_L, "\xe2\x87\xa7" },
|
||||||
|
{ 2, 2, 0, XK_y, "y" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_Y, "Y" },
|
||||||
|
{ 2, 2, 0, XK_x, "x" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_X, "X" },
|
||||||
|
{ 2, 2, 0, XK_c, "c" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_C, "C" },
|
||||||
|
{ 2, 2, 0, XK_v, "v" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_V, "V" },
|
||||||
|
{ 2, 2, 0, XK_b, "b" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_B, "B" },
|
||||||
|
{ 2, 2, 0, XK_n, "n" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_N, "N" },
|
||||||
|
{ 2, 2, 0, XK_m, "m" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_M, "M" },
|
||||||
|
{ 2, 2, 0, XK_comma, "," },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_comma, "<" },
|
||||||
|
{ 2, 2, 0, XK_period, "." },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_period, ">" },
|
||||||
|
{ 3, 3, 0, 0, NULL },
|
||||||
|
{ 3, 3, 0, XK_Control_L, "Ctrl" },
|
||||||
|
{ 3, 3, 0, XK_Alt_L, "Alt" },
|
||||||
|
{ 3, 5, 0, XK_space, " " },
|
||||||
|
{ 3, 0, XK_Shift_L, XK_space, " " },
|
||||||
|
{ 3, 3, 0, XK_Return, "\xe2\x86\xb2" },
|
||||||
|
{ 3, 3, 0, XK_BackSpace, "\xe2\x8c\xab" },
|
||||||
|
{ 0, 0, 0, 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static KeyboardKeyDefinition const _keyboard_layout_letters_azerty[] =
|
||||||
|
{
|
||||||
|
{ 0, 2, 0, XK_a, "a" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_A, "A" },
|
||||||
|
{ 0, 2, 0, XK_z, "z" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_Z, "Z" },
|
||||||
|
{ 0, 2, 0, XK_e, "e" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_E, "E" },
|
||||||
|
{ 0, 2, 0, XK_r, "r" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_R, "R" },
|
||||||
|
{ 0, 2, 0, XK_t, "t" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_T, "T" },
|
||||||
|
{ 0, 2, 0, XK_y, "y" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_Y, "Y" },
|
||||||
|
{ 0, 2, 0, XK_u, "u" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_U, "U" },
|
||||||
|
{ 0, 2, 0, XK_i, "i" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_I, "I" },
|
||||||
|
{ 0, 2, 0, XK_o, "o" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_O, "O" },
|
||||||
|
{ 0, 2, 0, XK_p, "p" },
|
||||||
|
{ 0, 0, XK_Shift_L, XK_P, "P" },
|
||||||
|
{ 1, 1, 0, 0, NULL },
|
||||||
|
{ 1, 2, 0, XK_q, "q" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_Q, "Q" },
|
||||||
|
{ 1, 2, 0, XK_s, "s" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_S, "S" },
|
||||||
|
{ 1, 2, 0, XK_d, "d" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_D, "D" },
|
||||||
|
{ 1, 2, 0, XK_f, "f" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_F, "F" },
|
||||||
|
{ 1, 2, 0, XK_g, "g" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_G, "G" },
|
||||||
|
{ 1, 2, 0, XK_h, "h" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_H, "H" },
|
||||||
|
{ 1, 2, 0, XK_j, "j" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_J, "J" },
|
||||||
|
{ 1, 2, 0, XK_k, "k" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_K, "K" },
|
||||||
|
{ 1, 2, 0, XK_l, "l" },
|
||||||
|
{ 1, 0, XK_Shift_L, XK_L, "L" },
|
||||||
|
{ 2, 2, 0, XK_Shift_L, "\xe2\x87\xa7" },
|
||||||
|
{ 2, 2, 0, XK_z, "z" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_Z, "Z" },
|
||||||
|
{ 2, 2, 0, XK_x, "x" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_X, "X" },
|
||||||
|
{ 2, 2, 0, XK_c, "c" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_C, "C" },
|
||||||
|
{ 2, 2, 0, XK_v, "v" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_V, "V" },
|
||||||
|
{ 2, 2, 0, XK_b, "b" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_B, "B" },
|
||||||
|
{ 2, 2, 0, XK_n, "n" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_N, "N" },
|
||||||
|
{ 2, 2, 0, XK_m, "m" },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_M, "M" },
|
||||||
|
{ 2, 2, 0, XK_comma, "," },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_comma, "<" },
|
||||||
|
{ 2, 2, 0, XK_period, "." },
|
||||||
|
{ 2, 0, XK_Shift_L, XK_period, ">" },
|
||||||
|
{ 3, 3, 0, 0, NULL },
|
||||||
|
{ 3, 3, 0, XK_Control_L, "Ctrl" },
|
||||||
|
{ 3, 3, 0, XK_Alt_L, "Alt" },
|
||||||
|
{ 3, 5, 0, XK_space, " " },
|
||||||
|
{ 3, 0, XK_Shift_L, XK_space, " " },
|
||||||
|
{ 3, 3, 0, XK_Return, "\xe2\x86\xb2" },
|
||||||
|
{ 3, 3, 0, XK_BackSpace, "\xe2\x8c\xab" },
|
||||||
|
{ 0, 0, 0, 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static KeyboardKeyDefinition const * _keyboard_layout_letters_definition[KLT_COUNT] =
|
||||||
|
{
|
||||||
|
_keyboard_layout_letters_qwerty,
|
||||||
|
_keyboard_layout_letters_qwertz,
|
||||||
|
_keyboard_layout_letters_azerty
|
||||||
|
};
|
||||||
|
|
||||||
static KeyboardKeyDefinition const _keyboard_layout_keypad[] =
|
static KeyboardKeyDefinition const _keyboard_layout_keypad[] =
|
||||||
{
|
{
|
||||||
{ 0, 3, 0, XK_Num_Lock, "Num" },
|
{ 0, 3, 0, XK_Num_Lock, "Num" },
|
||||||
@ -327,19 +502,14 @@ static KeyboardKeyDefinition const _keyboard_layout_special[] =
|
|||||||
{ 0, 0, 0, 0, NULL }
|
{ 0, 0, 0, 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static KeyboardLayoutDefinition _keyboard_layout[KLS_COUNT] =
|
|
||||||
{
|
|
||||||
{ "Abc", _keyboard_layout_letters },
|
|
||||||
{ "123", _keyboard_layout_keypad },
|
|
||||||
{ ",./", _keyboard_layout_special }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
static GtkWidget * _keyboard_add_layout(Keyboard * keyboard,
|
static GtkWidget * _keyboard_add_layout(Keyboard * keyboard,
|
||||||
KeyboardLayoutDefinition * definitions,
|
KeyboardLayoutDefinition * definitions,
|
||||||
size_t definitions_cnt, KeyboardLayoutSection section);
|
size_t definitions_cnt, KeyboardLayoutSection section);
|
||||||
|
|
||||||
|
static void _keyboard_error(Keyboard * keyboard, char const * format, ...);
|
||||||
|
|
||||||
|
|
||||||
/* public */
|
/* public */
|
||||||
/* functions */
|
/* functions */
|
||||||
@ -365,6 +535,14 @@ Keyboard * keyboard_new(KeyboardPrefs * prefs)
|
|||||||
GdkColor gray = { 0x90909090, 0x9090, 0x9090, 0x9090 };
|
GdkColor gray = { 0x90909090, 0x9090, 0x9090, 0x9090 };
|
||||||
#endif
|
#endif
|
||||||
unsigned long id;
|
unsigned long id;
|
||||||
|
KeyboardLayoutDefinition layout[KLS_COUNT] =
|
||||||
|
{
|
||||||
|
{ "Abc", _keyboard_layout_letters_qwerty },
|
||||||
|
{ "123", _keyboard_layout_keypad },
|
||||||
|
{ ",./", _keyboard_layout_special }
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
KeyboardLayoutTypeName const * typename;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
fprintf(stderr, "DEBUG: %s()\n", __func__);
|
||||||
@ -423,14 +601,31 @@ Keyboard * keyboard_new(KeyboardPrefs * prefs)
|
|||||||
vbox = widget;
|
vbox = widget;
|
||||||
}
|
}
|
||||||
/* layouts */
|
/* layouts */
|
||||||
if((widget = _keyboard_add_layout(keyboard, _keyboard_layout,
|
if(prefs->layout != NULL)
|
||||||
KLS_COUNT, KLS_LETTERS)) != NULL)
|
{
|
||||||
|
for(i = 0; i < sizeof(_keyboard_layout_type_name)
|
||||||
|
/ sizeof(*_keyboard_layout_type_name); i++)
|
||||||
|
{
|
||||||
|
typename = &_keyboard_layout_type_name[i];
|
||||||
|
if(strcasecmp(prefs->layout, typename->name) == 0)
|
||||||
|
{
|
||||||
|
layout[0].keys = _keyboard_layout_letters_definition[typename->type];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
typename = NULL;
|
||||||
|
}
|
||||||
|
if(typename == NULL)
|
||||||
|
_keyboard_error(NULL, "%s: Unsupported layout",
|
||||||
|
prefs->layout);
|
||||||
|
}
|
||||||
|
if((widget = _keyboard_add_layout(keyboard, layout, KLS_COUNT,
|
||||||
|
KLS_LETTERS)) != NULL)
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
|
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
|
||||||
if((widget = _keyboard_add_layout(keyboard, _keyboard_layout,
|
if((widget = _keyboard_add_layout(keyboard, layout, KLS_COUNT,
|
||||||
KLS_COUNT, KLS_KEYPAD)) != NULL)
|
KLS_KEYPAD)) != NULL)
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
|
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
|
||||||
if((widget = _keyboard_add_layout(keyboard, _keyboard_layout,
|
if((widget = _keyboard_add_layout(keyboard, layout, KLS_COUNT,
|
||||||
KLS_COUNT, KLS_SPECIAL)) != NULL)
|
KLS_SPECIAL)) != NULL)
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
|
gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0);
|
||||||
gtk_widget_show(vbox);
|
gtk_widget_show(vbox);
|
||||||
if(prefs->mode == KEYBOARD_MODE_EMBEDDED)
|
if(prefs->mode == KEYBOARD_MODE_EMBEDDED)
|
||||||
@ -814,3 +1009,17 @@ static void _layout_clicked(GtkWidget * widget, gpointer data)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* keyboard_error */
|
||||||
|
static void _keyboard_error(Keyboard * keyboard, char const * format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/* TODO add support for error dialog messages */
|
||||||
|
va_start(ap, format);
|
||||||
|
fprintf(stderr, "%s: ", PROGNAME_KEYBOARD);
|
||||||
|
vfprintf(stderr, format, ap);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
@ -53,6 +53,7 @@ typedef struct _KeyboardPrefs
|
|||||||
{
|
{
|
||||||
int monitor;
|
int monitor;
|
||||||
char const * font;
|
char const * font;
|
||||||
|
char const * layout;
|
||||||
KeyboardMode mode;
|
KeyboardMode mode;
|
||||||
int wait;
|
int wait;
|
||||||
} KeyboardPrefs;
|
} KeyboardPrefs;
|
||||||
|
@ -89,8 +89,10 @@ static int _error(char const * message, int ret)
|
|||||||
/* usage */
|
/* usage */
|
||||||
static int _usage(void)
|
static int _usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("Usage: %s [-d|-p|-w|-x][-f font][-m monitor][-n]\n"
|
fprintf(stderr, _("Usage: %s [-d|-p|-w|-x][-f font][-l layout]"
|
||||||
|
"[-m monitor][-n]\n"
|
||||||
" -d Start in docked mode\n"
|
" -d Start in docked mode\n"
|
||||||
|
" -l Select a different layout\n"
|
||||||
" -p Start as a popup window\n"
|
" -p Start as a popup window\n"
|
||||||
" -w Start in windowed mode\n"
|
" -w Start in windowed mode\n"
|
||||||
" -x Start in embedded mode\n"
|
" -x Start in embedded mode\n"
|
||||||
@ -117,7 +119,7 @@ int main(int argc, char * argv[])
|
|||||||
textdomain(PACKAGE);
|
textdomain(PACKAGE);
|
||||||
memset(&prefs, 0, sizeof(prefs));
|
memset(&prefs, 0, sizeof(prefs));
|
||||||
gtk_init(&argc, &argv);
|
gtk_init(&argc, &argv);
|
||||||
while((o = getopt(argc, argv, "df:m:npwx")) != -1)
|
while((o = getopt(argc, argv, "df:l:m:npwx")) != -1)
|
||||||
switch(o)
|
switch(o)
|
||||||
{
|
{
|
||||||
case 'd':
|
case 'd':
|
||||||
@ -126,6 +128,9 @@ int main(int argc, char * argv[])
|
|||||||
case 'f':
|
case 'f':
|
||||||
prefs.font = optarg;
|
prefs.font = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'l':
|
||||||
|
prefs.layout = optarg;
|
||||||
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
prefs.monitor = strtol(optarg, &p, 10);
|
prefs.monitor = strtol(optarg, &p, 10);
|
||||||
if(optarg[0] == '\0' || *p != '\0')
|
if(optarg[0] == '\0' || *p != '\0')
|
||||||
|
Loading…
Reference in New Issue
Block a user