mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Implemented SDL2 unicode input. Hotkeys are sill broken.
This commit is contained in:
parent
d50976bf4a
commit
ac2896da42
@ -1031,7 +1031,7 @@ static void listenForEvents()
|
||||
while(1) //main SDL events loop
|
||||
{
|
||||
SDL_Event ev;
|
||||
|
||||
|
||||
int ret = SDL_WaitEvent(&ev);
|
||||
if (ret == 0 || (ev.type==SDL_QUIT) ||
|
||||
(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4 && (ev.key.keysym.mod & KMOD_ALT)))
|
||||
|
@ -134,7 +134,7 @@ std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineWi
|
||||
|
||||
boost::algorithm::trim_right_if(text,boost::algorithm::is_any_of(std::string(" ")));
|
||||
|
||||
// each interation generates one output line
|
||||
// each iteration generates one output line
|
||||
while (text.length())
|
||||
{
|
||||
ui32 lineWidth = 0; //in characters or given char metric
|
||||
|
@ -481,7 +481,8 @@ void MusicEntry::load(std::string musicURI)
|
||||
|
||||
data = CResourceHandler::get()->load(ResourceID(musicURI, EResType::MUSIC))->readAll();
|
||||
musicFile = SDL_RWFromConstMem(data.first.get(), data.second);
|
||||
#if 0
|
||||
|
||||
#ifdef VCMI_SDL1
|
||||
music = Mix_LoadMUS_RW(musicFile);
|
||||
|
||||
if(!music)
|
||||
|
@ -1896,7 +1896,7 @@ CChatBox::CChatBox(const Rect &rect)
|
||||
{
|
||||
OBJ_CONSTRUCTION;
|
||||
pos += rect;
|
||||
addUsedEvents(KEYBOARD);
|
||||
addUsedEvents(KEYBOARD | TEXTINPUT);
|
||||
captureAllKeys = true;
|
||||
|
||||
const int height = graphics->fonts[FONT_SMALL]->getLineHeight();
|
||||
|
@ -2,29 +2,7 @@
|
||||
|
||||
#include "../Global.h"
|
||||
|
||||
#include <SDL_version.h>
|
||||
|
||||
#if (SDL_MAJOR_VERSION == 2)
|
||||
#define VCMI_SDL2
|
||||
|
||||
#include <SDL_keycode.h>
|
||||
typedef int SDLX_Coord;
|
||||
typedef int SDLX_Size;
|
||||
|
||||
typedef SDL_Keycode SDLKey;
|
||||
|
||||
#define SDL_SRCCOLORKEY SDL_TRUE
|
||||
|
||||
#define SDL_FULLSCREEN SDL_WINDOW_FULLSCREEN
|
||||
|
||||
#elif (SDL_MAJOR_VERSION == 1)
|
||||
#define VCMI_SDL1
|
||||
//SDL 1.x
|
||||
typedef Sint16 SDLX_Coord;
|
||||
typedef Uint16 SDLX_Size;
|
||||
#else
|
||||
#error "unkown or unsupported SDL version"
|
||||
#endif
|
||||
#include "gui/SDL_Compat.h"
|
||||
|
||||
// This header should be treated as a pre compiled header file(PCH) in the compiler building settings.
|
||||
|
||||
|
@ -60,6 +60,10 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std:
|
||||
processList(CIntObject::TIME,activityFlag,&timeinterested,cb);
|
||||
processList(CIntObject::WHEEL,activityFlag,&wheelInterested,cb);
|
||||
processList(CIntObject::DOUBLECLICK,activityFlag,&doubleClickInterested,cb);
|
||||
|
||||
#ifndef VCMI_SDL1
|
||||
processList(CIntObject::TEXTINPUT,activityFlag,&textInterested,cb);
|
||||
#endif // VCMI_SDL1
|
||||
}
|
||||
|
||||
void CGuiHandler::handleElementActivate(CIntObject * elem, ui16 activityFlag)
|
||||
@ -264,7 +268,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef VCMI_SDL1
|
||||
#ifdef VCMI_SDL1 //SDL1x only events
|
||||
else if(sEvent->button.button == SDL_BUTTON_WHEELDOWN || sEvent->button.button == SDL_BUTTON_WHEELUP)
|
||||
{
|
||||
std::list<CIntObject*> hlp = wheelInterested;
|
||||
@ -276,7 +280,7 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifndef VCMI_SDL1
|
||||
#ifndef VCMI_SDL1 //SDL2x only events
|
||||
else if ((sEvent->type == SDL_MOUSEWHEEL))
|
||||
{
|
||||
std::list<CIntObject*> hlp = wheelInterested;
|
||||
@ -286,6 +290,20 @@ void CGuiHandler::handleEvent(SDL_Event *sEvent)
|
||||
(*i)->wheelScrolled(sEvent->wheel.y < 0, isItIn(&(*i)->pos,sEvent->motion.x,sEvent->motion.y));
|
||||
}
|
||||
}
|
||||
else if(sEvent->type == SDL_TEXTINPUT)
|
||||
{
|
||||
for(auto it : textInterested)
|
||||
{
|
||||
it->textInputed(sEvent->text);
|
||||
}
|
||||
}
|
||||
else if(sEvent->type == SDL_TEXTEDITING)
|
||||
{
|
||||
for(auto it : textInterested)
|
||||
{
|
||||
it->textEdited(sEvent->edit);
|
||||
}
|
||||
}
|
||||
#endif // VCMI_SDL1
|
||||
else if ((sEvent->type==SDL_MOUSEBUTTONUP) && (sEvent->button.button == SDL_BUTTON_LEFT))
|
||||
{
|
||||
|
@ -58,6 +58,9 @@ private:
|
||||
timeinterested,
|
||||
wheelInterested,
|
||||
doubleClickInterested;
|
||||
#ifndef VCMI_SDL1
|
||||
CIntObjectList textInterested;
|
||||
#endif // VCMI_SDL1
|
||||
|
||||
void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
|
||||
public:
|
||||
|
@ -1,13 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include "Geometries.h"
|
||||
#include "../Graphics.h"
|
||||
|
||||
struct SDL_Surface;
|
||||
class CPicture;
|
||||
class CGuiHandler;
|
||||
|
||||
/*
|
||||
* CIntObject.h, part of VCMI engine
|
||||
*
|
||||
@ -17,6 +7,16 @@ class CGuiHandler;
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include "Geometries.h"
|
||||
#include "../Graphics.h"
|
||||
|
||||
struct SDL_Surface;
|
||||
class CPicture;
|
||||
class CGuiHandler;
|
||||
|
||||
using boost::logic::tribool;
|
||||
|
||||
@ -123,6 +123,11 @@ public:
|
||||
bool captureAllKeys; //if true, only this object should get info about pressed keys
|
||||
virtual void keyPressed(const SDL_KeyboardEvent & key){}
|
||||
virtual bool captureThisEvent(const SDL_KeyboardEvent & key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
|
||||
|
||||
#ifndef VCMI_SDL1
|
||||
virtual void textInputed(const SDL_TextInputEvent & event){};
|
||||
virtual void textEdited(const SDL_TextEditingEvent & event){};
|
||||
#endif // VCMI_SDL1
|
||||
|
||||
//mouse movement handling
|
||||
bool strongInterest; //if true - report all mouse movements, if not - only when hovered
|
||||
@ -138,7 +143,7 @@ public:
|
||||
//double click
|
||||
virtual void onDoubleClick(){}
|
||||
|
||||
enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, ALL=0xffff};
|
||||
enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, TEXTINPUT=512, ALL=0xffff};
|
||||
const ui16 & active;
|
||||
void addUsedEvents(ui16 newActions);
|
||||
void removeUsedEvents(ui16 newActions);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "../GUIClasses.h"
|
||||
#include "CGuiHandler.h"
|
||||
#include "../CAdvmapInterface.h"
|
||||
#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff
|
||||
|
||||
CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
|
||||
{
|
||||
@ -1545,7 +1546,7 @@ CTextInput::CTextInput(const Rect &Pos, EFonts font, const CFunctionList<void(co
|
||||
pos.w = Pos.w;
|
||||
captureAllKeys = true;
|
||||
bg = nullptr;
|
||||
addUsedEvents(LCLICK | KEYBOARD);
|
||||
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
|
||||
giveFocus();
|
||||
}
|
||||
|
||||
@ -1557,7 +1558,7 @@ CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::strin
|
||||
captureAllKeys = true;
|
||||
OBJ_CONSTRUCTION;
|
||||
bg = new CPicture(bgName, bgOffset.x, bgOffset.y);
|
||||
addUsedEvents(LCLICK | KEYBOARD);
|
||||
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
|
||||
giveFocus();
|
||||
}
|
||||
|
||||
@ -1576,13 +1577,35 @@ CTextInput::CTextInput(const Rect &Pos, SDL_Surface *srf)
|
||||
pos.w = bg->pos.w;
|
||||
pos.h = bg->pos.h;
|
||||
bg->pos = pos;
|
||||
addUsedEvents(LCLICK | KEYBOARD);
|
||||
addUsedEvents(LCLICK | KEYBOARD | TEXTINPUT);
|
||||
giveFocus();
|
||||
}
|
||||
|
||||
void CTextInput::focusGot()
|
||||
{
|
||||
#ifndef VCMI_SDL1
|
||||
if (SDL_IsTextInputActive() == SDL_FALSE)
|
||||
{
|
||||
SDL_StartTextInput();
|
||||
}
|
||||
SDL_SetTextInputRect(&pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CTextInput::focusLost()
|
||||
{
|
||||
#ifndef VCMI_SDL1
|
||||
if (SDL_IsTextInputActive() == SDL_TRUE)
|
||||
{
|
||||
SDL_StopTextInput();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
std::string CTextInput::visibleText()
|
||||
{
|
||||
return focus ? text + "_" : text;
|
||||
return focus ? text + newText + "_" : text;
|
||||
}
|
||||
|
||||
void CTextInput::clickLeft( tribool down, bool previousState )
|
||||
@ -1593,6 +1616,30 @@ void CTextInput::clickLeft( tribool down, bool previousState )
|
||||
|
||||
void CTextInput::keyPressed( const SDL_KeyboardEvent & key )
|
||||
{
|
||||
auto trim = [](std::string & s){
|
||||
if(s.empty())
|
||||
return;
|
||||
auto b = s.begin();
|
||||
auto e = s.end();
|
||||
size_t lastLen = 0;
|
||||
size_t len = 0;
|
||||
while (b != e) {
|
||||
lastLen = len;
|
||||
size_t n = Unicode::getCharacterSize(*b);
|
||||
|
||||
if(!Unicode::isValidCharacter(&(*b),e-b))
|
||||
{
|
||||
logGlobal->errorStream() << "Invalid UTF8 sequence";
|
||||
break;//invalid sequence will be trimmed
|
||||
}
|
||||
|
||||
len += n;
|
||||
b += n;
|
||||
}
|
||||
|
||||
s.resize(lastLen);
|
||||
};
|
||||
|
||||
if(!focus || key.state != SDL_PRESSED)
|
||||
return;
|
||||
|
||||
@ -1603,32 +1650,43 @@ void CTextInput::keyPressed( const SDL_KeyboardEvent & key )
|
||||
return;
|
||||
}
|
||||
|
||||
std::string oldText = text;
|
||||
bool redrawNeeded = false;
|
||||
switch(key.keysym.sym)
|
||||
{
|
||||
case SDLK_DELETE: // have index > ' ' so it won't be filtered out by default section
|
||||
return;
|
||||
case SDLK_BACKSPACE:
|
||||
if(!text.empty())
|
||||
text.resize(text.size()-1);
|
||||
if(!newText.empty())
|
||||
{
|
||||
trim(newText);
|
||||
redrawNeeded = true;
|
||||
}
|
||||
else if(!text.empty())
|
||||
{
|
||||
trim(text);
|
||||
redrawNeeded = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
#ifdef VCMI_SDL1
|
||||
if (key.keysym.unicode < ' ')
|
||||
return;
|
||||
else
|
||||
{
|
||||
text += key.keysym.unicode; //TODO 16-/>8
|
||||
redrawNeeded = true;
|
||||
}
|
||||
#endif // 0
|
||||
break;
|
||||
}
|
||||
#ifdef VCMI_SDL1
|
||||
filters(text, oldText);
|
||||
if (text != oldText)
|
||||
#endif // 0
|
||||
if (redrawNeeded)
|
||||
{
|
||||
redraw();
|
||||
cb(text);
|
||||
}
|
||||
#endif // 0
|
||||
}
|
||||
|
||||
//todo: handle text input for SDL2
|
||||
}
|
||||
@ -1652,10 +1710,41 @@ bool CTextInput::captureThisEvent(const SDL_KeyboardEvent & key)
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false; //todo:CTextInput::captureThisEvent
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef VCMI_SDL1
|
||||
void CTextInput::textInputed(const SDL_TextInputEvent & event)
|
||||
{
|
||||
if(!focus)
|
||||
return;
|
||||
std::string oldText = text;
|
||||
|
||||
text += event.text;
|
||||
|
||||
filters(text,oldText);
|
||||
if (text != oldText)
|
||||
{
|
||||
redraw();
|
||||
cb(text);
|
||||
}
|
||||
newText = "";
|
||||
}
|
||||
|
||||
void CTextInput::textEdited(const SDL_TextEditingEvent & event)
|
||||
{
|
||||
if(!focus)
|
||||
return;
|
||||
|
||||
newText = event.text;
|
||||
redraw();
|
||||
cb(text+newText);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void CTextInput::filenameFilter(std::string & text, const std::string &)
|
||||
{
|
||||
static const std::string forbiddenChars = "<>:\"/\\|?*\r\n"; //if we are entering a filename, some special characters won't be allowed
|
||||
@ -1708,7 +1797,10 @@ CFocusable::CFocusable()
|
||||
CFocusable::~CFocusable()
|
||||
{
|
||||
if(inputWithFocus == this)
|
||||
{
|
||||
focusLost();
|
||||
inputWithFocus = nullptr;
|
||||
}
|
||||
|
||||
focusables -= this;
|
||||
}
|
||||
@ -1717,12 +1809,14 @@ void CFocusable::giveFocus()
|
||||
if(inputWithFocus)
|
||||
{
|
||||
inputWithFocus->focus = false;
|
||||
inputWithFocus->focusLost();
|
||||
inputWithFocus->redraw();
|
||||
}
|
||||
|
||||
focus = true;
|
||||
inputWithFocus = this;
|
||||
redraw();
|
||||
focusGot();
|
||||
redraw();
|
||||
}
|
||||
|
||||
void CFocusable::moveFocus()
|
||||
|
@ -436,6 +436,9 @@ public:
|
||||
/// UIElement which can get input focus
|
||||
class CFocusable : public virtual CIntObject
|
||||
{
|
||||
protected:
|
||||
virtual void focusGot(){};
|
||||
virtual void focusLost(){};
|
||||
public:
|
||||
bool focus; //only one focusable control can have focus at one moment
|
||||
|
||||
@ -451,9 +454,12 @@ public:
|
||||
/// Text input box where players can enter text
|
||||
class CTextInput : public CLabel, public CFocusable
|
||||
{
|
||||
std::string newText;
|
||||
protected:
|
||||
std::string visibleText() override;
|
||||
|
||||
void focusGot() override;
|
||||
void focusLost() override;
|
||||
public:
|
||||
CFunctionList<void(const std::string &)> cb;
|
||||
CFunctionList<void(std::string &, const std::string &)> filters;
|
||||
@ -466,6 +472,13 @@ public:
|
||||
void clickLeft(tribool down, bool previousState) override;
|
||||
void keyPressed(const SDL_KeyboardEvent & key) override;
|
||||
bool captureThisEvent(const SDL_KeyboardEvent & key) override;
|
||||
|
||||
#ifndef VCMI_SDL1
|
||||
void textInputed(const SDL_TextInputEvent & event) override;
|
||||
void textEdited(const SDL_TextEditingEvent & event) override;
|
||||
|
||||
|
||||
#endif // VCMI_SDL1
|
||||
|
||||
//Filter that will block all characters not allowed in filenames
|
||||
static void filenameFilter(std::string &text, const std::string & oldText);
|
||||
|
37
client/gui/SDL_Compat.h
Normal file
37
client/gui/SDL_Compat.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* SDL_Compat.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include <SDL_version.h>
|
||||
|
||||
#if (SDL_MAJOR_VERSION == 2)
|
||||
#define VCMI_SDL2
|
||||
|
||||
#include <SDL_keycode.h>
|
||||
typedef int SDLX_Coord;
|
||||
typedef int SDLX_Size;
|
||||
|
||||
typedef SDL_Keycode SDLKey;
|
||||
|
||||
#define SDL_SRCCOLORKEY SDL_TRUE
|
||||
|
||||
#define SDL_FULLSCREEN SDL_WINDOW_FULLSCREEN
|
||||
|
||||
#elif (SDL_MAJOR_VERSION == 1)
|
||||
#define VCMI_SDL1
|
||||
//SDL 1.x
|
||||
typedef Sint16 SDLX_Coord;
|
||||
typedef Uint16 SDLX_Size;
|
||||
#else
|
||||
#error "unknown or unsupported SDL version"
|
||||
#endif
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
size_t Unicode::getCharacterSize(ui8 firstByte)
|
||||
size_t Unicode::getCharacterSize(char firstByte)
|
||||
{
|
||||
// length of utf-8 character can be determined from 1st byte by counting number of highest bits set to 1:
|
||||
// 0xxxxxxx -> 1 - ASCII chars
|
||||
@ -27,14 +27,14 @@ size_t Unicode::getCharacterSize(ui8 firstByte)
|
||||
// 11110xxx -> 4 - last allowed in current standard
|
||||
// 1111110x -> 6 - last allowed in original standard
|
||||
|
||||
if (firstByte < 0x80)
|
||||
if ((ui8)firstByte < 0x80)
|
||||
return 1; // ASCII
|
||||
|
||||
size_t ret = 0;
|
||||
|
||||
for (size_t i=0; i<8; i++)
|
||||
{
|
||||
if ((firstByte & (0x80 >> i)) != 0)
|
||||
if (((ui8)firstByte & (0x80 >> i)) != 0)
|
||||
ret++;
|
||||
else
|
||||
break;
|
||||
@ -42,12 +42,15 @@ size_t Unicode::getCharacterSize(ui8 firstByte)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Unicode::isValidCharacter(const ui8 *character, size_t maxSize)
|
||||
bool Unicode::isValidCharacter(const char * character, size_t maxSize)
|
||||
{
|
||||
// can't be first byte in UTF8
|
||||
if ((ui8)character[0] >= 0x80 && (ui8)character[0] < 0xC0)
|
||||
return false;
|
||||
// first character must follow rules checked in getCharacterSize
|
||||
size_t size = getCharacterSize(character[0]);
|
||||
size_t size = getCharacterSize((ui8)character[0]);
|
||||
|
||||
if (character[0] > 0xF4)
|
||||
if ((ui8)character[0] > 0xF4)
|
||||
return false; // above maximum allowed in standard (UTF codepoints are capped at 0x0010FFFF)
|
||||
|
||||
if (size > maxSize)
|
||||
@ -56,7 +59,7 @@ bool Unicode::isValidCharacter(const ui8 *character, size_t maxSize)
|
||||
// remaining characters must have highest bit set to 1
|
||||
for (size_t i = 1; i < size; i++)
|
||||
{
|
||||
if ((character[i] & 0x80) == 0)
|
||||
if (((ui8)character[i] & 0x80) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -82,7 +85,7 @@ bool Unicode::isValidString(const std::string & text)
|
||||
{
|
||||
for (size_t i=0; i<text.size(); i += getCharacterSize(text[i]))
|
||||
{
|
||||
if (!isValidCharacter(reinterpret_cast<const ui8*>(text.data() + i), text.size() - i))
|
||||
if (!isValidCharacter(text.data() + i, text.size() - i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -92,7 +95,7 @@ bool Unicode::isValidString(const char * data, size_t size)
|
||||
{
|
||||
for (size_t i=0; i<size; i += getCharacterSize(data[i]))
|
||||
{
|
||||
if (!isValidCharacter(reinterpret_cast<const ui8*>(data + i), size - i))
|
||||
if (!isValidCharacter(data + i, size - i))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -16,11 +16,11 @@
|
||||
namespace Unicode
|
||||
{
|
||||
/// evaluates size of UTF-8 character
|
||||
size_t DLL_LINKAGE getCharacterSize(ui8 firstByte);
|
||||
size_t DLL_LINKAGE getCharacterSize(char firstByte);
|
||||
|
||||
/// test if character is a valid UTF-8 symbol
|
||||
/// maxSize - maximum number of bytes this symbol may consist from ( = remainer of string)
|
||||
bool DLL_LINKAGE isValidCharacter(const ui8 *character, size_t maxSize);
|
||||
bool DLL_LINKAGE isValidCharacter(const char * character, size_t maxSize);
|
||||
|
||||
/// test if text contains ASCII-string (no need for unicode conversion)
|
||||
bool DLL_LINKAGE isValidASCII(const std::string & text);
|
||||
|
Loading…
Reference in New Issue
Block a user