Hiho,
ich arbeite immer mal weiter an meinem kleinen SDL-Projekt und habe mir bisher eine statische Klasse "um die SDL-Eingabe" herum gebaut, d.h. folgendes:
Input.hpp
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
#ifndef INPUT_HPP_INCLUDED
#define INPUT_HPP_INCLUDED
#include <map>
#include <string>
#include <queue>
#include <SDL/SDL.h>
// ein paar andere Sachen - die auftretenden Bezeichner sollten aber hoffentlich selbsterklärend sein :)
#include <core/geometry.hpp>
#include <core/unicode.hpp>
#include <core/filesystem.hpp>
#include <core/exception.hpp>
namespace core {
/// ID-Typ für Tasten
typedef unsigned short KeyID;
/// ID-Typ für Maustasten
typedef unsigned short ButtonID;
/// Zustand einer Taste
enum KeyState {
RELEASED = 0,
PRESSED = 1,
HELD = 2
};
namespace keyboard {
extern KeyID FIRST;
extern KeyID BACKSPACE;
extern KeyID TAB;
extern KeyID CLEAR;
extern KeyID RETURN;
extern KeyID PAUSE;
/*
... ich kürze das an der Stelle mal ab
*/
extern KeyID POWER;
extern KeyID EURO;
extern KeyID UNDO;
extern KeyID LAST;
}
namespace mouse {
extern ButtonID FIRST;
extern ButtonID LEFT;
extern ButtonID MIDDLE;
extern ButtonID RIGHT;
extern ButtonID WHEELUP;
extern ButtonID WHEELDOWN;
extern ButtonID LAST;
}
/// Zusammenfassung von Maus, Tastatur und Gamepad
class Input {
private:
/// Zuletzt gedrückte Tasten
static std::queue<KeyID> lastKeys;
/// Zuletzt gedrückte Maustasten
static std::queue<ButtonID> lastButtons;
/// Beschreibt, ob Eingabebehandlung initialisiert wurde
static bool ready;
/// Beschreibt, ob die Maus eingefangen wurde
static bool grab;
/// Beschreibt, ob die Maus zentriert ist
static bool drag;
/// Sensibilität der Maus
static float sensitivity;
public:
/// Initialisiert Eingabebehandlung
static void init();
/// Beendet Eingabebehandlung
static void quit();
/// Aktualisiert die Eingabebehandlung
static void update();
/// Erfasst gedrückte Tasten
static std::map<KeyID, KeyState> keyboard;
/// Erfasst gedrückte Maustasten
static std::map<ButtonID, KeyState> button;
/// Position des Mauszeigers
static Vector pos;
/// Relative Änderung des Mauszeigers
static Vector diff;
/// Eingegebenes Zeichen als Unicode-String
static std::string text;
/*
/// Liefert, wie lange eine Taste gehalten wird
static unsigned short getKeyboardHeld(KeyID const & id);
/// Liefert, wie lange eine Maustste gehalten wird
static unsigned short getButtonHeld(ButtonID const & id);
*/
/// Beschreibt, ob SDL_QUIT ausgelöst wurde
static bool window_close;
};
}
#endif // INPUT_HPP_INCLUDED
|
Input.cpp
|
C-/C++-Quelltext
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
#include <core/input.hpp>
#include <stdexcept>
namespace core {
namespace keyboard {
KeyID FIRST = SDLK_FIRST;
KeyID BACKSPACE = SDLK_BACKSPACE;
KeyID TAB = SDLK_TAB;
KeyID CLEAR = SDLK_CLEAR;
/*
... auch hier kürze ich mal ab
*/
KeyID EURO = SDLK_EURO;
KeyID UNDO = SDLK_UNDO;
KeyID LAST = SDLK_LAST;
}
namespace mouse {
ButtonID FIRST = SDL_BUTTON_LEFT;
ButtonID LEFT = SDL_BUTTON_LEFT;
ButtonID MIDDLE = SDL_BUTTON_MIDDLE;
ButtonID RIGHT = SDL_BUTTON_RIGHT;
ButtonID WHEELUP = SDL_BUTTON_WHEELUP;
ButtonID WHEELDOWN = SDL_BUTTON_WHEELDOWN;
ButtonID LAST = SDL_BUTTON_WHEELDOWN;
}
bool Input::ready = false;
std::queue<KeyID> Input::lastKeys;
std::queue<ButtonID> Input::lastButtons;
std::map<KeyID, KeyState> Input::keyboard;
std::map<ButtonID, KeyState> Input::button;
Vector Input::pos;
Vector Input::diff;
std::string Input::text;
bool Input::grab = false;
bool Input::drag = false;
float Input::sensitivity = 1.0;
bool Input::window_close = false;
void Input::init() {
if (Input::ready == true) {
std::clog << "Input system is already initialized" << std::endl;
return;
}
SDL_EnableUNICODE(true);
Input::ready = true;
}
void Input::quit() {
if (Input::ready == false) {
std::clog << "Input system was not initialized" << std::endl;
return;
}
SDL_EnableUNICODE(false);
Input::ready = false;
}
void Input::update() {
Vector tmp;
Input::window_close = false;
Input::text.clear();
// Tastendruck in -halten umwandeln
while (!Input::lastKeys.empty()) {
KeyID buffer = Input::lastKeys.front();
Input::lastKeys.pop();
Input::keyboard[buffer] = HELD;
}
// Maustastendruck in -halten umwandeln
while (!Input::lastButtons.empty()) {
ButtonID buffer = Input::lastButtons.front();
Input::lastButtons.pop();
Input::button[buffer] = HELD;
}
if (Input::ready == false) {
throw RuntimeError("Input must be initialized before handling input");
}
if (Input::grab) {
if (SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE) {
SDL_ShowCursor(SDL_DISABLE);
SDL_WM_GrabInput(SDL_GRAB_ON);
}
} else {
if (SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE) {
SDL_ShowCursor(SDL_ENABLE);
SDL_WM_GrabInput(SDL_GRAB_OFF);
}
}
SDL_Event event;
short keycode;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
Input::keyboard[event.key.keysym.sym] = PRESSED;
Input::lastKeys.push(event.key.keysym.sym);
keycode = event.key.keysym.unicode;
// Read and Convert Printable Input
if ((keycode > 0x800) | (keycode > 0x80) | (keycode > 32 && keycode != 127)) {
Input::text.push_back(keycode);
}
break;
case SDL_KEYUP:
Input::keyboard[event.key.keysym.sym] = RELEASED;
break;
case SDL_MOUSEBUTTONDOWN:
Input::button[event.button.button] = PRESSED;
Input::lastButtons.push(event.button.button);
break;
case SDL_MOUSEBUTTONUP:
Input::button[event.button.button] = RELEASED;
break;
case SDL_MOUSEMOTION:
tmp = Vector(event.motion.x, event.motion.y);
Input::diff = Input::pos - tmp;
Input::pos = tmp;
break;
case SDL_QUIT:
Input::window_close = true;
break;
}
}
if (Input::drag) {
SDL_WarpMouse(Input::pos.x, Input::pos.y);
}
}
}
|
Warum, wieso, weshalb?
Ich würde gern den Zustand er Eingabe speichern, um in der Programmlogik verschiedene Eingabesachen abzufragen, ohne direkt mit SDLEvents arbeiten zu müssen. Sicherlich: das hat dann eher etwas vom "jede Minute gucken, ob die Pizza fertig ist", statt dem eleganteren "ich stelle mir einen Wecker und bekomme eine 'Information' wenn sie fertig ist". Eine "schönere" Lösung ist mir noch nicht eingefallen
Effektiv ist das mit der "Zustandsklasse" für die Eingabe für mich eine Frage des Information Hiding und der Kapselung - auch im Hinblick auf eine Migration zu einer neueren SDL-Version. Atm arbeite ich noch mit 1.2, möchte aber in absehbarer Zeit auf 2.0 wechseln.
Ich habe mir ein paar Widget-Klassen geschrieben, die dieses Input-System verwenden. Ja: ich hätte auch eine der fertigen SDL-Widget-Libs nehmen können, aber die bauen alle auf den SDLEvents auf, so dass ich mir die Integration schwer vorstellen kann. Imho ist dieses "Eingabe in das gewünschte Format bringen" (was ich mit der statischen Klasse effektiv mache) kein Teufelszeug
Zumindest bilde ich mir das ein.
Was suche ich? Was will ich hören?
Könnt ihr mir ein besseres Konzept empfehlen? Oder kennt ihr vielleicht sogar eine Lib die auf SDL aufbaut, Widgets zur Verfügung stellt und eine Art Zustandsspeicherung für die Eingaben vornimmt? Die einzige Forderung an ein Widget-System wäre, dass ich das Aussehen der Widgets mit Grafiken modifiziere kann, d.h. ich möchte keine Widgets im üblichen Systemlayout.
Meine aktuelle Lösung der Eingabebehandlung gefällt mir überhaupt nicht. Und bevor ich damit weiterarbeite und mein Projekt zu stark davon abhängig mache, wollte ich mal rumfragen
LG Glocke
/EDIT: Sorry, falsches Unterforum erwischt -.-