Don't fall off commandline processing routine
[lsnes.git] / src / plat-sdl / commandline.cpp
blob5fe574cb2d9faa248626c72baae9fa5351dc642d
1 #include "plat-sdl/platform.hpp"
3 #include <sstream>
5 namespace
7 volatile uint32_t autorepeat_first = 10;
8 volatile uint32_t autorepeat_subsequent = 4;
11 commandline_model::commandline_model() throw()
13 enabled_flag = false;
14 autorepeating_key = SPECIAL_NOOP;
15 autorepeat_phase = 0;
16 cursor_pos = 0;
17 overwrite_mode = false;
20 std::string commandline_model::key(uint32_t k) throw(std::bad_alloc)
22 std::string ret;
23 switch(k) {
24 case SPECIAL_NOOP:
25 return "";
26 case SPECIAL_ACK:
27 history.push_front(codepoints);
28 ret = read_command();
29 enabled_flag = false;
30 return ret;
31 case SPECIAL_NAK:
32 enabled_flag = false;
33 return "";
34 default:
35 //Fall through.
39 //Set up autorepeat if needed.
40 if(k & PRESSED_MASK) {
41 autorepeating_key = k;
42 autorepeat_counter = 0;
43 autorepeat_phase = 1;
44 } else {
45 //These all are active on positive edge.
46 autorepeating_key = SPECIAL_NOOP;
47 autorepeat_counter = 0;
48 autorepeat_phase = 0;
49 return "";
52 switch(k & ~PRESSED_MASK) {
53 case SPECIAL_INSERT:
54 overwrite_mode = !overwrite_mode;
55 case SPECIAL_HOME:
56 cursor_pos = 0;
57 return "";
58 case SPECIAL_END:
59 cursor_pos = codepoints.size();
60 return "";
61 case SPECIAL_PGUP:
62 case SPECIAL_UP:
63 scroll_history_up();
64 return "";
65 case SPECIAL_PGDN:
66 case SPECIAL_DOWN:
67 scroll_history_down();
68 return "";
69 case SPECIAL_LEFT:
70 if(cursor_pos > 0)
71 cursor_pos--;
72 return "";
73 case SPECIAL_RIGHT:
74 if(cursor_pos < codepoints.size())
75 cursor_pos++;
76 return "";
77 case SPECIAL_BACKSPACE:
78 if(cursor_pos == 0)
79 //Nothing to delete.
80 return "";
81 delete_codepoint(cursor_pos - 1);
82 cursor_pos--;
83 return "";
84 case SPECIAL_DELETE:
85 if(cursor_pos == codepoints.size())
86 //Nothing to delete.
87 return "";
88 delete_codepoint(cursor_pos);
89 return "";
90 default:
91 //This can't be NOOP, ACK nor NAK because those were checked above, nor is it special. Therefore
92 //it is a character.
93 handle_cow();
94 if(!overwrite_mode || cursor_pos == codepoints.size()) {
95 codepoints.resize(codepoints.size() + 1);
96 for(size_t i = codepoints.size() - 1; i > cursor_pos; i--)
97 codepoints[i] = codepoints[i - 1];
99 codepoints[cursor_pos++] = k & ~PRESSED_MASK;
100 return "";
104 void commandline_model::tick() throw(std::bad_alloc)
106 if(autorepeat_phase == 0 || !enabled_flag)
107 return;
108 if(autorepeat_phase == 1) {
109 autorepeat_counter++;
110 if(autorepeat_counter >= autorepeat_first) {
111 key(autorepeating_key);
112 autorepeat_phase = 2;
113 autorepeat_counter = 0;
116 if(autorepeat_phase == 2) {
117 autorepeat_counter++;
118 if(autorepeat_counter >= autorepeat_subsequent) {
119 key(autorepeating_key);
120 autorepeat_counter = 0;
125 size_t commandline_model::cursor() throw()
127 return enabled_flag ? cursor_pos : 0;
130 bool commandline_model::enabled() throw()
132 return enabled_flag;
135 bool commandline_model::overwriting() throw()
137 return overwrite_mode;
140 void commandline_model::enable() throw()
142 if(enabled_flag)
143 return;
144 enabled_flag = true;
145 autorepeat_phase = 0;
146 autorepeat_counter = 0;
147 codepoints.clear();
148 cursor_pos = 0;
149 overwrite_mode = false;
150 history_itr = history.end();
153 std::string commandline_model::read_command() throw(std::bad_alloc)
155 std::ostringstream o;
156 for(auto i : codepoints) {
157 char buf[5] = {0, 0, 0, 0, 0};
158 if(i < 0x80)
159 buf[0] = i;
160 else if(i < 0x800) {
161 buf[0] = 0xC0 | (i >> 6);
162 buf[1] = 0x80 | (i & 63);
163 } else if(i < 0x10000) {
164 buf[0] = 0xE0 | (i >> 12);
165 buf[1] = 0x80 | ((i >> 6) & 63);
166 buf[2] = 0x80 | (i & 63);
167 } else if(i < 0x10FFFF) {
168 buf[0] = 0xF0 | (i >> 18);
169 buf[1] = 0x80 | ((i >> 12) & 63);
170 buf[2] = 0x80 | ((i >> 6) & 63);
171 buf[3] = 0x80 | (i & 63);
173 o << buf;
175 return o.str();
178 void commandline_model::handle_cow()
180 if(history_itr == history.end())
181 //Latched to end of history.
182 return;
183 codepoints = *history_itr;
184 history_itr = history.end();
187 void commandline_model::scroll_history_up()
189 std::list<std::vector<uint32_t>>::iterator tmp;
192 void commandline_model::scroll_history_down()
194 std::list<std::vector<uint32_t>>::iterator tmp;
197 void commandline_model::delete_codepoint(size_t idx)
199 handle_cow();
200 for(size_t i = idx; i < codepoints.size() - 1; i++)
201 codepoints[i] = codepoints[i + 1];
202 codepoints.resize(codepoints.size() - 1);
205 void commandline_model::paint(SDL_Surface* surf, uint32_t x, uint32_t y, uint32_t maxwidth, uint32_t color,
206 bool box, uint32_t boxcolor) throw()
208 if(!maxwidth)
209 return;
210 try {
211 if(box)
212 draw_box(surf, x, y, maxwidth, 16, boxcolor);
213 if(enabled_flag)
214 draw_string(surf, read_command(), x, y, maxwidth, color, overwrite_mode ? 2 : 1, cursor_pos);
215 else
216 draw_string(surf, "", x, y, maxwidth, color, 0, 0);
217 } catch(...) {
218 OOM_panic();