/*
* Copyright (c) 2002-2008 Hypertriton, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Basic keyboard input processing in ASCII mode.
*/
#include
#include
#include "widget.h"
#include "editable.h"
#include "keymap.h"
#include "text.h"
#include
#include
/* Emulate "shift" key for US keyboard layout. */
/* XXX move to keymap */
static Uint32
EmulateShiftUSKBD(Uint32 key)
{
if (isalpha(key)) {
return (toupper(key));
} else {
switch (key) {
case SDLK_1: return ('!');
case SDLK_2: return ('@');
case SDLK_3: return ('#');
case SDLK_4: return ('$');
case SDLK_5: return ('%');
case SDLK_6: return ('^');
case SDLK_7: return ('&');
case SDLK_8: return ('*');
case SDLK_9: return ('(');
case SDLK_0: return (')');
case SDLK_BACKQUOTE: return ('~');
case SDLK_MINUS: return ('_');
case SDLK_EQUALS: return ('+');
case SDLK_LEFTBRACKET: return ('{');
case SDLK_RIGHTBRACKET: return ('}');
case SDLK_BACKSLASH: return ('|');
case SDLK_SEMICOLON: return (':');
case SDLK_QUOTE: return ('"');
case SDLK_COMMA: return ('<');
case SDLK_PERIOD: return ('>');
case SDLK_SLASH: return ('?');
}
}
return ('?');
}
/* Apply modifiers (when not using Unicode keyboard translation). */
Uint32
AG_ApplyModifiersASCII(Uint32 key, int kmod)
{
if (kmod & KMOD_CAPS) {
if (kmod & KMOD_SHIFT) {
return (Uint32)tolower((int)key);
} else {
return (EmulateShiftUSKBD(key));
}
} else {
if (kmod & KMOD_SHIFT) {
return (EmulateShiftUSKBD(key));
} else {
return (key);
}
}
}
static int
InsertASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 unicode,
char *s, int len, int lenMax)
{
Uint32 ins[3];
int nins, i;
char ch;
if (AG_WidgetDisabled(ed))
return (0);
if (keysym == 0 || !isascii(keysym))
return (0);
ch = (char)AG_ApplyModifiersASCII((Uint32)keysym, keymod);
if (ch == 0) { return (0); }
if (ch == '\r') { ch = '\n'; }
switch (ed->encoding) {
case AG_ENCODING_UTF8:
break;
case AG_ENCODING_ASCII:
if (!isascii((int)ch)) {
return (0);
}
break;
}
if (AG_GetBool(agConfig,"input.composition")) {
if ((nins = AG_KeyInputCompose(ed, (Uint32)ch, ins)) == 0)
return (0);
} else {
ins[0] = (Uint32)ch;
nins = 1;
}
if (len+nins >= lenMax) {
return (0);
}
ins[nins] = '\0';
if (ed->pos == len) { /* Append */
for (i = 0; i < nins+1; i++)
s[len+i] = ins[i];
} else { /* Insert */
char *p = &s[ed->pos];
memcpy(&p[nins], &p[0], (len - ed->pos));
for (i = 0; i < nins; i++) {
p[i] = ins[i];
}
s[len+1] = '\0';
}
ed->pos++;
return (1);
}
static int
DeleteASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 unicode,
char *s, int len, int lenMax)
{
char *c;
if (AG_WidgetDisabled(ed))
return (0);
if (len == 0)
return (0);
switch (keysym) {
case SDLK_BACKSPACE:
if (ed->pos == 0) {
return (0);
}
if (ed->pos == len) {
s[len-1] = '\0';
ed->pos--;
return (1);
}
ed->pos--;
break;
case SDLK_DELETE:
if (ed->pos == len) {
s[len-1] = '\0';
ed->pos--;
return (1);
}
break;
default:
break;
}
for (c = &s[ed->pos]; c[1] != '\0'; c++) {
*c = c[1];
}
*c = '\0';
return (1);
}
static int
KillASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
if (AG_WidgetDisabled(ed))
return (0);
/* TODO Save to a kill buffer, etc. */
s[ed->pos] = '\0';
return (1);
}
static int
YankASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
if (AG_WidgetDisabled(ed))
return (0);
/* TODO */
return (1);
}
static int
WordBackASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
/* TODO */
ed->flags |= AG_EDITABLE_MARKPREF;
return (0);
}
static int
WordForwASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
/* TODO */
ed->flags |= AG_EDITABLE_MARKPREF;
return (0);
}
static int
CursorHomeASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
ed->pos = 0;
ed->flags |= AG_EDITABLE_MARKPREF;
return (0);
}
static int
CursorEndASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
ed->pos = len;
ed->flags |= AG_EDITABLE_MARKPREF;
return (0);
}
static int
CursorLeftASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
if (--ed->pos < 1) {
ed->pos = 0;
}
ed->flags |= AG_EDITABLE_MARKPREF;
return (0);
}
static int
CursorRightASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
if (ed->pos < len) {
ed->pos++;
}
ed->flags |= AG_EDITABLE_MARKPREF;
return (0);
}
static int
CursorUpASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
char *p;
if ((p = strrchr(&s[ed->pos], '\n')) != NULL) {
ed->pos -= (s - p);
}
return (0);
}
static int
CursorDownASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
char *p;
if ((p = strchr(&s[ed->pos], '\n')) != NULL) {
ed->pos -= (p - s);
}
return (0);
}
static int
PageUpASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
AG_EditableMoveCursor(ed, ed->xCurs,
(ed->yCurs - ed->y - ed->yVis*2 + 2)*agTextFontLineSkip + 1,
1);
return (0);
}
static int
PageDownASCII(AG_Editable *ed, SDLKey keysym, int keymod, Uint32 uch,
char *s, int len, int lenMax)
{
AG_EditableMoveCursor(ed, ed->xCurs,
(ed->yCurs - ed->y + ed->yVis*2 - 2)*agTextFontLineSkip + 1,
1);
return (0);
}
const struct ag_keycode_ascii agKeymapASCII[] = {
{ SDLK_HOME, 0, CursorHomeASCII },
{ SDLK_a, KMOD_CTRL, CursorHomeASCII },
{ SDLK_END, 0, CursorEndASCII },
{ SDLK_e, KMOD_CTRL, CursorEndASCII },
{ SDLK_LEFT, 0, CursorLeftASCII },
{ SDLK_RIGHT, 0, CursorRightASCII },
{ SDLK_UP, 0, CursorUpASCII },
{ SDLK_DOWN, 0, CursorDownASCII },
{ SDLK_PAGEUP, 0, PageUpASCII },
{ SDLK_PAGEDOWN, 0, PageDownASCII },
{ SDLK_BACKSPACE, 0, DeleteASCII },
{ SDLK_DELETE, 0, DeleteASCII },
{ SDLK_k, KMOD_CTRL, KillASCII },
{ SDLK_y, KMOD_CTRL, YankASCII },
{ SDLK_b, KMOD_ALT, WordBackASCII },
{ SDLK_f, KMOD_ALT, WordForwASCII },
{ SDLK_LAST, 0, InsertASCII },
};