summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-09-20 22:17:21 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-09-20 22:17:21 +0000
commit7b67e852086ad3ccd98a622f890b245ab6a0a321 (patch)
treef7341709ff3119209cc69bb114aec5ff95447d8a
parent9cfafa755012bfd68c661996ddaea76e2e265f81 (diff)
downloadmana-7b67e852086ad3ccd98a622f890b245ab6a0a321.tar.gz
mana-7b67e852086ad3ccd98a622f890b245ab6a0a321.tar.bz2
mana-7b67e852086ad3ccd98a622f890b245ab6a0a321.tar.xz
mana-7b67e852086ad3ccd98a622f890b245ab6a0a321.zip
Added support for unicode charset in textfields and chat.
-rw-r--r--ChangeLog8
-rw-r--r--src/Makefile.am2
-rw-r--r--src/game.cpp3
-rw-r--r--src/gui/browserbox.cpp8
-rw-r--r--src/gui/gui.cpp24
-rw-r--r--src/gui/gui.h3
-rw-r--r--src/gui/sdlinput.cpp431
-rw-r--r--src/gui/sdlinput.h190
-rw-r--r--src/gui/textfield.cpp98
-rw-r--r--src/gui/textfield.h5
-rw-r--r--src/main.cpp8
11 files changed, 758 insertions, 22 deletions
diff --git a/ChangeLog b/ChangeLog
index 83d447bd..d528359a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,14 @@
* src/particle.h, src/particle.cpp: Moved function out of header file.
* src/net/chathandler.cpp: Removed useless include.
* src/utils/trim.h: Fixed storage qualifier.
+ * src/Makefile.am, src/gui/sdlinput.cpp, src/gui/sdlinput.h: Modified
+ Guichan SDL input handler, so that it supports high characters.
+ * src/gui/textfield.cpp, src/gui/textfield.h: Took over handling of
+ keypresses in textfields, so that utf8 characters are supported.
+ * src/gui/browserbox.cpp: Fixed improper splitting of characters.
+ * src/gui/gui.cpp, src/gui/gui.h, src/game.cpp, src/main.cpp: Changed
+ the input handler. Moved away from image font so that non-latin
+ characters are supported.
2007-09-16 Guillaume Melquiond <guillaume.melquiond@gmail.com>
diff --git a/src/Makefile.am b/src/Makefile.am
index 2f29e299..aaeb2949 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -94,6 +94,8 @@ tmw_SOURCES = gui/widgets/dropdown.cpp \
gui/register.h \
gui/scrollarea.cpp \
gui/scrollarea.h \
+ gui/sdlinput.cpp \
+ gui/sdlinput.h \
gui/selectionlistener.h \
gui/sell.cpp \
gui/sell.h \
diff --git a/src/game.cpp b/src/game.cpp
index a40bfa28..a56f10eb 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -28,7 +28,6 @@
#include <sstream>
#include <string>
-#include <guichan/sdl/sdlinput.hpp>
#include <guichan/exception.hpp>
#include "beingmanager.h"
@@ -61,6 +60,7 @@
#include "gui/ministatus.h"
#include "gui/npclistdialog.h"
#include "gui/npc_text.h"
+#include "gui/sdlinput.h"
#include "gui/sell.h"
#include "gui/setup.h"
#include "gui/skill.h"
@@ -83,7 +83,6 @@
#include "resources/imagewriter.h"
extern Graphics *graphics;
-extern gcn::SDLInput *guiInput;
class Map;
diff --git a/src/gui/browserbox.cpp b/src/gui/browserbox.cpp
index 717342de..9c31c752 100644
--- a/src/gui/browserbox.cpp
+++ b/src/gui/browserbox.cpp
@@ -273,6 +273,8 @@ BrowserBox::draw(gcn::Graphics *graphics)
std::string row = mTextRows[i];
x = 0;
+ /* FIXME: This code has to be rewritten from scratch, so that it does
+ not display strings one character at a time. */
for (j = 0; j < row.size(); j++)
{
if (mUseLinksAndUserColors || (!mUseLinksAndUserColors && (j == 0)))
@@ -354,7 +356,11 @@ BrowserBox::draw(gcn::Graphics *graphics)
// Draw each char
else
{
- std::string character = row.substr(j, 1);
+ unsigned j_end = j + 1;
+ while (j_end < row.size() && (row[j_end] & 192) == 128)
+ ++j_end;
+ std::string character = row.substr(j, j_end - j);
+ j = j_end - 1;
font->drawString(graphics, character, x, y);
x += font->getWidth(character.c_str());
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index 97dd4d44..50b891c0 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -28,10 +28,8 @@
#include <guichan/imagefont.hpp>
#include <SDL/SDL_ttf.h>
-// Should stay here because of Guichan being sensitive to headers order
-#include <guichan/sdl/sdlinput.hpp>
-
#include "focushandler.h"
+#include "sdlinput.h"
#include "truetypefont.h"
#include "viewport.h"
#include "window.h"
@@ -48,8 +46,8 @@
// Guichan stuff
Gui *gui;
-Viewport *viewport; /**< Viewport on the map. */
-gcn::SDLInput *guiInput; /**< GUI input. */
+Viewport *viewport;
+SDLInput *guiInput;
// Fonts used in showing hits
gcn::Font *hitRedFont;
@@ -90,12 +88,12 @@ Gui::Gui(Graphics *graphics):
gcn::Image::setImageLoader(&imageLoader);
// Set input
- guiInput = new gcn::SDLInput();
+ guiInput = new SDLInput;
setInput(guiInput);
// Set focus handler
delete mFocusHandler;
- mFocusHandler = new FocusHandler();
+ mFocusHandler = new FocusHandler;
// Initialize top GUI widget
WindowContainer *guiTop = new WindowContainer();
@@ -117,16 +115,14 @@ Gui::Gui(Graphics *graphics):
}
// Set speech font
- try {
- speechFont = new gcn::ImageFont("graphics/gui/rpgfont_wider.png",
- " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789.,!?-+/():;%&`'*#=[]\"<>{}^~|_@$\\"
- "áÁéÉíÍóÓúÚç륣¢¡¿àãõêñÑöüäÖÜÄßøèÈåÅ"
- );
+ try
+ {
+ // FIXME: use another font?
+ speechFont = new TrueTypeFont("data/fonts/dejavusans.ttf", 11);
}
catch (gcn::Exception e)
{
- logger->log("Unable to load rpgfont_wider.png: %s",
+ logger->log("Unable to load dejavusans.ttf: %s",
e.getMessage().c_str());
throw;
}
diff --git a/src/gui/gui.h b/src/gui/gui.h
index 1e4b9348..84f52a31 100644
--- a/src/gui/gui.h
+++ b/src/gui/gui.h
@@ -31,6 +31,7 @@
class GuiConfigListener;
class Graphics;
class ImageSet;
+class SDLInput;
class Viewport;
/**
@@ -106,7 +107,7 @@ class Gui : public gcn::Gui
extern Gui *gui; /**< The GUI system */
extern Viewport *viewport; /**< The viewport */
-extern gcn::SDLInput *guiInput; /**< GUI input */
+extern SDLInput *guiInput; /**< GUI input */
/**
* Fonts used in showing hits
diff --git a/src/gui/sdlinput.cpp b/src/gui/sdlinput.cpp
new file mode 100644
index 00000000..cef53697
--- /dev/null
+++ b/src/gui/sdlinput.cpp
@@ -0,0 +1,431 @@
+/* _______ __ __ __ ______ __ __ _______ __ __
+ * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
+ * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
+ * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
+ * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
+ * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
+ * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
+ *
+ * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson
+ * Copyright 2007 The Mana World Development Team
+ *
+ * Js_./
+ * Per Larsson a.k.a finalman _RqZ{a<^_aa
+ * Olof Naessén a.k.a jansem/yakslem _asww7!uY`> )\a//
+ * _Qhm`] _f "'c 1!5m
+ * Visit: http://guichan.darkbits.org )Qk<P ` _: :+' .' "{[
+ * .)j(] .d_/ '-( P . S
+ * License: (BSD) <Td/Z <fP"5(\"??"\a. .L
+ * Redistribution and use in source and _dV>ws?a-?' ._/L #'
+ * binary forms, with or without )4d[#7r, . ' )d`)[
+ * modification, are permitted provided _Q-5'5W..j/?' -?!\)cam'
+ * that the following conditions are met: j<<WP+k/);. _W=j f
+ * 1. Redistributions of source code must .$%w\/]Q . ."' . mj$
+ * retain the above copyright notice, ]E.pYY(Q]>. a J@\
+ * this list of conditions and the j(]1u<sE"L,. . ./^ ]{a
+ * following disclaimer. 4'_uomm\. )L);-4 (3=
+ * 2. Redistributions in binary form must )_]X{Z('a_"a7'<a"a, ]"[
+ * reproduce the above copyright notice, #}<]m7`Za??4,P-"'7. ).m
+ * this list of conditions and the ]d2e)Q(<Q( ?94 b- LQ/
+ * following disclaimer in the <B!</]C)d_, '(<' .f. =C+m
+ * documentation and/or other materials .Z!=J ]e []('-4f _ ) -.)m]'
+ * provided with the distribution. .w[5]' _[ /.)_-"+? _/ <W"
+ * 3. Neither the name of Guichan nor the :$we` _! + _/ . j?
+ * names of its contributors may be used =3)= _f (_yQmWW$#( "
+ * to endorse or promote products derived - W, sQQQQmZQ#Wwa]..
+ * from this software without specific (js, \[QQW$QWW#?!V"".
+ * prior written permission. ]y:.<\.. .
+ * -]n w/ ' [.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT )/ )/ !
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY < (; sac , '
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ]^ .- %
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF c < r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR aga< <La
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 5% )P'-3L
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR _bQf` y`..)a
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ,J?4P'.P"_(\?d'.,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES _Pa,)!f/<[]/ ?"
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT _2-..:. .r+_,.. .
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ?a.<%"' " -'.a_ _,
+ * 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.
+ *
+ * $Id$
+ */
+
+#include "sdlinput.h"
+
+#include <guichan/exception.hpp>
+
+SDLInput::SDLInput()
+{
+ mMouseInWindow = true;
+ mMouseDown = false;
+}
+
+bool SDLInput::isKeyQueueEmpty()
+{
+ return mKeyInputQueue.empty();
+}
+
+gcn::KeyInput SDLInput::dequeueKeyInput()
+{
+ gcn::KeyInput keyInput;
+
+ if (mKeyInputQueue.empty())
+ {
+ throw GCN_EXCEPTION("The queue is empty.");
+ }
+
+ keyInput = mKeyInputQueue.front();
+ mKeyInputQueue.pop();
+
+ return keyInput;
+}
+
+bool SDLInput::isMouseQueueEmpty()
+{
+ return mMouseInputQueue.empty();
+}
+
+gcn::MouseInput SDLInput::dequeueMouseInput()
+{
+ gcn::MouseInput mouseInput;
+
+ if (mMouseInputQueue.empty())
+ {
+ throw GCN_EXCEPTION("The queue is empty.");
+ }
+
+ mouseInput = mMouseInputQueue.front();
+ mMouseInputQueue.pop();
+
+ return mouseInput;
+}
+
+void SDLInput::pushInput(SDL_Event event)
+{
+ gcn::KeyInput keyInput;
+ gcn::MouseInput mouseInput;
+
+ switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ keyInput.setKey(gcn::Key(convertKeyCharacter(event)));
+ keyInput.setType(gcn::KeyInput::PRESSED);
+ keyInput.setShiftPressed(event.key.keysym.mod & KMOD_SHIFT);
+ keyInput.setControlPressed(event.key.keysym.mod & KMOD_CTRL);
+ keyInput.setAltPressed(event.key.keysym.mod & KMOD_ALT);
+ keyInput.setMetaPressed(event.key.keysym.mod & KMOD_META);
+ keyInput.setNumericPad(event.key.keysym.sym >= SDLK_KP0
+ && event.key.keysym.sym <= SDLK_KP_EQUALS);
+
+ mKeyInputQueue.push(keyInput);
+ break;
+
+ case SDL_KEYUP:
+ keyInput.setKey(gcn::Key(convertKeyCharacter(event)));
+ keyInput.setType(gcn::KeyInput::RELEASED);
+ keyInput.setShiftPressed(event.key.keysym.mod & KMOD_SHIFT);
+ keyInput.setControlPressed(event.key.keysym.mod & KMOD_CTRL);
+ keyInput.setAltPressed(event.key.keysym.mod & KMOD_ALT);
+ keyInput.setMetaPressed(event.key.keysym.mod & KMOD_META);
+ keyInput.setNumericPad(event.key.keysym.sym >= SDLK_KP0
+ && event.key.keysym.sym <= SDLK_KP_EQUALS);
+
+ mKeyInputQueue.push(keyInput);
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ mMouseDown = true;
+ mouseInput.setX(event.button.x);
+ mouseInput.setY(event.button.y);
+ mouseInput.setButton(convertMouseButton(event.button.button));
+
+ if (event.button.button == SDL_BUTTON_WHEELDOWN)
+ {
+ mouseInput.setType(gcn::MouseInput::WHEEL_MOVED_DOWN);
+ }
+ else if (event.button.button == SDL_BUTTON_WHEELUP)
+ {
+ mouseInput.setType(gcn::MouseInput::WHEEL_MOVED_UP);
+ }
+ else
+ {
+ mouseInput.setType(gcn::MouseInput::PRESSED);
+ }
+ mouseInput.setTimeStamp(SDL_GetTicks());
+ mMouseInputQueue.push(mouseInput);
+ break;
+
+ case SDL_MOUSEBUTTONUP:
+ mMouseDown = false;
+ mouseInput.setX(event.button.x);
+ mouseInput.setY(event.button.y);
+ mouseInput.setButton(convertMouseButton(event.button.button));
+ mouseInput.setType(gcn::MouseInput::RELEASED);
+ mouseInput.setTimeStamp(SDL_GetTicks());
+ mMouseInputQueue.push(mouseInput);
+ break;
+
+ case SDL_MOUSEMOTION:
+ mouseInput.setX(event.button.x);
+ mouseInput.setY(event.button.y);
+ mouseInput.setButton(gcn::MouseInput::EMPTY);
+ mouseInput.setType(gcn::MouseInput::MOVED);
+ mouseInput.setTimeStamp(SDL_GetTicks());
+ mMouseInputQueue.push(mouseInput);
+ break;
+
+ case SDL_ACTIVEEVENT:
+ /*
+ * This occurs when the mouse leaves the window and the Gui-chan
+ * application loses its mousefocus.
+ */
+ if ((event.active.state & SDL_APPMOUSEFOCUS)
+ && !event.active.gain)
+ {
+ mMouseInWindow = false;
+
+ if (!mMouseDown)
+ {
+ mouseInput.setX(-1);
+ mouseInput.setY(-1);
+ mouseInput.setButton(gcn::MouseInput::EMPTY);
+ mouseInput.setType(gcn::MouseInput::MOVED);
+ mMouseInputQueue.push(mouseInput);
+ }
+ }
+
+ if ((event.active.state & SDL_APPMOUSEFOCUS)
+ && event.active.gain)
+ {
+ mMouseInWindow = true;
+ }
+ break;
+
+ } // end switch
+}
+
+int SDLInput::convertMouseButton(int button)
+{
+ switch (button)
+ {
+ case SDL_BUTTON_LEFT:
+ return gcn::MouseInput::LEFT;
+ case SDL_BUTTON_RIGHT:
+ return gcn::MouseInput::RIGHT;
+ case SDL_BUTTON_MIDDLE:
+ return gcn::MouseInput::MIDDLE;
+ default:
+ // We have an unknown mouse type which is ignored.
+ return button;
+ }
+}
+
+int SDLInput::convertKeyCharacter(SDL_Event event)
+{
+ SDL_keysym keysym = event.key.keysym;
+
+ int value = keysym.unicode;
+
+ switch (keysym.sym)
+ {
+ case SDLK_TAB:
+ value = Key::TAB;
+ break;
+ case SDLK_LALT:
+ value = Key::LEFT_ALT;
+ break;
+ case SDLK_RALT:
+ value = Key::RIGHT_ALT;
+ break;
+ case SDLK_LSHIFT:
+ value = Key::LEFT_SHIFT;
+ break;
+ case SDLK_RSHIFT:
+ value = Key::RIGHT_SHIFT;
+ break;
+ case SDLK_LCTRL:
+ value = Key::LEFT_CONTROL;
+ break;
+ case SDLK_RCTRL:
+ value = Key::RIGHT_CONTROL;
+ break;
+ case SDLK_BACKSPACE:
+ value = Key::BACKSPACE;
+ break;
+ case SDLK_PAUSE:
+ value = Key::PAUSE;
+ break;
+ case SDLK_SPACE:
+ // Special characters like ~ (tilde) ends up
+ // with the keysym.sym SDLK_SPACE which
+ // without this check would be lost. The check
+ // is only valid on key down events in SDL.
+ if (event.type == SDL_KEYUP || keysym.unicode == ' ')
+ {
+ value = Key::SPACE;
+ }
+ break;
+ case SDLK_ESCAPE:
+ value = Key::ESCAPE;
+ break;
+ case SDLK_DELETE:
+ value = Key::DELETE;
+ break;
+ case SDLK_INSERT:
+ value = Key::INSERT;
+ break;
+ case SDLK_HOME:
+ value = Key::HOME;
+ break;
+ case SDLK_END:
+ value = Key::END;
+ break;
+ case SDLK_PAGEUP:
+ value = Key::PAGE_UP;
+ break;
+ case SDLK_PRINT:
+ value = Key::PRINT_SCREEN;
+ break;
+ case SDLK_PAGEDOWN:
+ value = Key::PAGE_DOWN;
+ break;
+ case SDLK_F1:
+ value = Key::F1;
+ break;
+ case SDLK_F2:
+ value = Key::F2;
+ break;
+ case SDLK_F3:
+ value = Key::F3;
+ break;
+ case SDLK_F4:
+ value = Key::F4;
+ break;
+ case SDLK_F5:
+ value = Key::F5;
+ break;
+ case SDLK_F6:
+ value = Key::F6;
+ break;
+ case SDLK_F7:
+ value = Key::F7;
+ break;
+ case SDLK_F8:
+ value = Key::F8;
+ break;
+ case SDLK_F9:
+ value = Key::F9;
+ break;
+ case SDLK_F10:
+ value = Key::F10;
+ break;
+ case SDLK_F11:
+ value = Key::F11;
+ break;
+ case SDLK_F12:
+ value = Key::F12;
+ break;
+ case SDLK_F13:
+ value = Key::F13;
+ break;
+ case SDLK_F14:
+ value = Key::F14;
+ break;
+ case SDLK_F15:
+ value = Key::F15;
+ break;
+ case SDLK_NUMLOCK:
+ value = Key::NUM_LOCK;
+ break;
+ case SDLK_CAPSLOCK:
+ value = Key::CAPS_LOCK;
+ break;
+ case SDLK_SCROLLOCK:
+ value = Key::SCROLL_LOCK;
+ break;
+ case SDLK_RMETA:
+ value = Key::RIGHT_META;
+ break;
+ case SDLK_LMETA:
+ value = Key::LEFT_META;
+ break;
+ case SDLK_LSUPER:
+ value = Key::LEFT_SUPER;
+ break;
+ case SDLK_RSUPER:
+ value = Key::RIGHT_SUPER;
+ break;
+ case SDLK_MODE:
+ value = Key::ALT_GR;
+ break;
+ case SDLK_UP:
+ value = Key::UP;
+ break;
+ case SDLK_DOWN:
+ value = Key::DOWN;
+ break;
+ case SDLK_LEFT:
+ value = Key::LEFT;
+ break;
+ case SDLK_RIGHT:
+ value = Key::RIGHT;
+ break;
+ case SDLK_RETURN:
+ value = Key::ENTER;
+ break;
+ case SDLK_KP_ENTER:
+ value = Key::ENTER;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!(keysym.mod & KMOD_NUM))
+ {
+ switch (keysym.sym)
+ {
+ case SDLK_KP0:
+ value = Key::INSERT;
+ break;
+ case SDLK_KP1:
+ value = Key::END;
+ break;
+ case SDLK_KP2:
+ value = Key::DOWN;
+ break;
+ case SDLK_KP3:
+ value = Key::PAGE_DOWN;
+ break;
+ case SDLK_KP4:
+ value = Key::LEFT;
+ break;
+ case SDLK_KP5:
+ value = 0;
+ break;
+ case SDLK_KP6:
+ value = Key::RIGHT;
+ break;
+ case SDLK_KP7:
+ value = Key::HOME;
+ break;
+ case SDLK_KP8:
+ value = Key::UP;
+ break;
+ case SDLK_KP9:
+ value = Key::PAGE_UP;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return value;
+}
diff --git a/src/gui/sdlinput.h b/src/gui/sdlinput.h
new file mode 100644
index 00000000..e23178fa
--- /dev/null
+++ b/src/gui/sdlinput.h
@@ -0,0 +1,190 @@
+/* _______ __ __ __ ______ __ __ _______ __ __
+ * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\
+ * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
+ * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / /
+ * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / /
+ * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
+ * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
+ *
+ * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessén and Per Larsson
+ * Copyright 2007 The Mana World Development Team
+ *
+ * Js_./
+ * Per Larsson a.k.a finalman _RqZ{a<^_aa
+ * Olof Naessén a.k.a jansem/yakslem _asww7!uY`> )\a//
+ * _Qhm`] _f "'c 1!5m
+ * Visit: http://guichan.darkbits.org )Qk<P ` _: :+' .' "{[
+ * .)j(] .d_/ '-( P . S
+ * License: (BSD) <Td/Z <fP"5(\"??"\a. .L
+ * Redistribution and use in source and _dV>ws?a-?' ._/L #'
+ * binary forms, with or without )4d[#7r, . ' )d`)[
+ * modification, are permitted provided _Q-5'5W..j/?' -?!\)cam'
+ * that the following conditions are met: j<<WP+k/);. _W=j f
+ * 1. Redistributions of source code must .$%w\/]Q . ."' . mj$
+ * retain the above copyright notice, ]E.pYY(Q]>. a J@\
+ * this list of conditions and the j(]1u<sE"L,. . ./^ ]{a
+ * following disclaimer. 4'_uomm\. )L);-4 (3=
+ * 2. Redistributions in binary form must )_]X{Z('a_"a7'<a"a, ]"[
+ * reproduce the above copyright notice, #}<]m7`Za??4,P-"'7. ).m
+ * this list of conditions and the ]d2e)Q(<Q( ?94 b- LQ/
+ * following disclaimer in the <B!</]C)d_, '(<' .f. =C+m
+ * documentation and/or other materials .Z!=J ]e []('-4f _ ) -.)m]'
+ * provided with the distribution. .w[5]' _[ /.)_-"+? _/ <W"
+ * 3. Neither the name of Guichan nor the :$we` _! + _/ . j?
+ * names of its contributors may be used =3)= _f (_yQmWW$#( "
+ * to endorse or promote products derived - W, sQQQQmZQ#Wwa]..
+ * from this software without specific (js, \[QQW$QWW#?!V"".
+ * prior written permission. ]y:.<\.. .
+ * -]n w/ ' [.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT )/ )/ !
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY < (; sac , '
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, ]^ .- %
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF c < r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR aga< <La
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 5% )P'-3L
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR _bQf` y`..)a
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ,J?4P'.P"_(\?d'.,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES _Pa,)!f/<[]/ ?"
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT _2-..:. .r+_,.. .
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ?a.<%"' " -'.a_ _,
+ * 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.
+ *
+ * $Id$
+ */
+
+#ifndef _TMW_SDLINPUT_
+#define _TMW_SDLINPUT_
+
+#include <queue>
+
+#include <SDL/SDL.h>
+
+#include <guichan/input.hpp>
+#include <guichan/keyinput.hpp>
+#include <guichan/mouseinput.hpp>
+#include <guichan/platform.hpp>
+
+namespace Key
+{
+ enum
+ {
+ SPACE = ' ',
+ TAB = '\t',
+ ENTER = '\n',
+ // Negative values, to avoid conflicts with higher character codes.
+ LEFT_ALT = -1000,
+ RIGHT_ALT,
+ LEFT_SHIFT,
+ RIGHT_SHIFT,
+ LEFT_CONTROL,
+ RIGHT_CONTROL,
+ LEFT_META,
+ RIGHT_META,
+ LEFT_SUPER,
+ RIGHT_SUPER,
+ INSERT,
+ HOME,
+ PAGE_UP,
+ DELETE,
+ END,
+ PAGE_DOWN,
+ ESCAPE,
+ CAPS_LOCK,
+ BACKSPACE,
+ F1,
+ F2,
+ F3,
+ F4,
+ F5,
+ F6,
+ F7,
+ F8,
+ F9,
+ F10,
+ F11,
+ F12,
+ F13,
+ F14,
+ F15,
+ PRINT_SCREEN,
+ SCROLL_LOCK,
+ PAUSE,
+ NUM_LOCK,
+ ALT_GR,
+ LEFT,
+ RIGHT,
+ UP,
+ DOWN
+ };
+}
+
+/**
+ * SDL implementation of Input.
+ */
+class SDLInput : public gcn::Input
+{
+public:
+
+ /**
+ * Constructor.
+ */
+ SDLInput();
+
+ /**
+ * Pushes an SDL event. It should be called at least once per frame to
+ * update input with user input.
+ *
+ * @param event an event from SDL.
+ */
+ virtual void pushInput(SDL_Event event);
+
+ /**
+ * Polls all input. It exists for input driver compatibility. If you
+ * only use SDL and plan sticking with SDL you can safely ignore this
+ * function as it in the SDL case does nothing.
+ */
+ virtual void _pollInput() { }
+
+
+ // Inherited from Input
+
+ virtual bool isKeyQueueEmpty();
+
+ virtual gcn::KeyInput dequeueKeyInput();
+
+ virtual bool isMouseQueueEmpty();
+
+ virtual gcn::MouseInput dequeueMouseInput();
+
+protected:
+ /**
+ * Converts a mouse button from SDL to a Guichan mouse button
+ * representation.
+ *
+ * @param button an SDL mouse button.
+ * @return a Guichan mouse button.
+ */
+ int convertMouseButton(int button);
+
+ /**
+ * Converts an SDL event key to a key value.
+ *
+ * @param event an SDL event with a key to convert.
+ * @return a key value.
+ * @see Key
+ */
+ int convertKeyCharacter(SDL_Event event);
+
+ std::queue<gcn::KeyInput> mKeyInputQueue;
+ std::queue<gcn::MouseInput> mMouseInputQueue;
+
+ bool mMouseDown;
+ bool mMouseInWindow;
+};
+
+#endif
diff --git a/src/gui/textfield.cpp b/src/gui/textfield.cpp
index ce7f6d5f..88d8fff9 100644
--- a/src/gui/textfield.cpp
+++ b/src/gui/textfield.cpp
@@ -25,6 +25,8 @@
#include <guichan/font.hpp>
+#include "sdlinput.h"
+
#include "../graphics.h"
#include "../resources/image.h"
@@ -100,3 +102,99 @@ void TextField::drawBorder(gcn::Graphics *graphics)
static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin);
}
+
+void TextField::keyPressed(gcn::KeyEvent &keyEvent)
+{
+ int val = keyEvent.getKey().getValue();
+
+ if (val >= 32)
+ {
+ int l;
+ if (val < 128) l = 1; // 0xxxxxxx
+ else if (val < 0x800) l = 2; // 110xxxxx 10xxxxxx
+ else if (val < 0x10000) l = 3; // 1110xxxx 10xxxxxx 10xxxxxx
+ else l = 4; // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+ char buf[4];
+ for (int i = 0; i < l; ++i)
+ {
+ buf[i] = val >> (6 * (l - i - 1));
+ if (i > 0) buf[i] = (buf[i] & 63) | 128;
+ }
+
+ if (l > 1) buf[0] |= 255 << (8 - l);
+
+ mText.insert(mCaretPosition, std::string(buf, buf + l));
+ mCaretPosition += l;
+ }
+
+ /* In UTF-8, 10xxxxxx is only used for inner parts of characters. So skip
+ them when processing key presses. */
+
+ switch (val)
+ {
+ case Key::LEFT:
+ {
+ while (mCaretPosition > 0)
+ {
+ --mCaretPosition;
+ if ((mText[mCaretPosition] & 192) != 128)
+ break;
+ }
+ } break;
+
+ case Key::RIGHT:
+ {
+ unsigned sz = mText.size();
+ while (mCaretPosition < sz)
+ {
+ ++mCaretPosition;
+ if (mCaretPosition == sz ||
+ (mText[mCaretPosition] & 192) != 128)
+ break;
+ }
+ } break;
+
+ case Key::DELETE:
+ {
+ unsigned sz = mText.size();
+ while (mCaretPosition < sz)
+ {
+ --sz;
+ mText.erase(mCaretPosition, 1);
+ if (mCaretPosition == sz ||
+ (mText[mCaretPosition] & 192) != 128)
+ break;
+ }
+ } break;
+
+ case Key::BACKSPACE:
+ {
+ while (mCaretPosition > 0)
+ {
+ --mCaretPosition;
+ int v = mText[mCaretPosition];
+ mText.erase(mCaretPosition, 1);
+ if ((v & 192) != 128) break;
+ }
+ } break;
+
+ case Key::ENTER:
+ generateAction();
+ break;
+
+ case Key::HOME:
+ mCaretPosition = 0;
+ break;
+
+ case Key::END:
+ mCaretPosition = mText.size();
+ break;
+
+ case Key::TAB:
+ return;
+ }
+
+ keyEvent.consume();
+ fixScroll();
+}
diff --git a/src/gui/textfield.h b/src/gui/textfield.h
index 4748830c..e36380e3 100644
--- a/src/gui/textfield.h
+++ b/src/gui/textfield.h
@@ -55,6 +55,11 @@ class TextField : public gcn::TextField {
*/
void drawBorder(gcn::Graphics *graphics);
+ /**
+ * Processes one keypress.
+ */
+ void keyPressed(gcn::KeyEvent &keyEvent);
+
private:
static int instances;
static ImageRect skin;
diff --git a/src/main.cpp b/src/main.cpp
index 30fb7c1c..19fa9150 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -31,7 +31,6 @@
#include <SDL_image.h>
#include <guichan/actionlistener.hpp>
-#include <guichan/sdl/sdlinput.hpp>
#include <guichan/widgets/label.hpp>
#include <libxml/parser.h>
@@ -64,14 +63,15 @@
#include "gui/char_select.h"
#include "gui/connection.h"
#include "gui/gui.h"
-#include "gui/serverdialog.h"
#include "gui/login.h"
-#include "gui/quitdialog.h"
#include "gui/ok_dialog.h"
#include "gui/progressbar.h"
+#include "gui/quitdialog.h"
#include "gui/register.h"
-#include "gui/updatewindow.h"
+#include "gui/sdlinput.h"
+#include "gui/serverdialog.h"
#include "gui/textfield.h"
+#include "gui/updatewindow.h"
#include "net/charserverhandler.h"
#include "net/connection.h"