xaizek / pms (License: GPLv3+) (since 2018-12-07)
Older version of Practical Music Search written in C++.
Commit ab0086775f79fb95a70569cd2a43e5917df11cc6

Support wide character input.
Author: Kim Tore Jensen
Author date (UTC): 2012-08-16 14:39
Committer name: Kim Tore Jensen
Committer date (UTC): 2012-08-16 14:39
Parent(s): 9adfc20b4bafda332424a3e68b3e47cf979d52ca
Signing key:
Tree: f604ae706bf09f8d0b713d859419d60ae93c9703
File Lines added Lines deleted
configure.ac 2 2
src/input.cpp 50 18
src/input.h 10 1
File configure.ac changed (mode: 100644) (index cbda1d1..30f6be7)
... ... AC_PROG_CC
14 14
15 15 # Checks for libraries. # Checks for libraries.
16 16 AX_WITH_CURSES AX_WITH_CURSES
17 if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
18 AC_MSG_ERROR([requires either NcursesW or Ncurses library])
17 if test "x$ax_cv_ncursesw" != xyes; then
18 AC_MSG_ERROR([requires ncurses with wide character support])
19 19 fi fi
20 20
21 21 # Checks for header files. # Checks for header files.
File src/input.cpp changed (mode: 100644) (index b1fa57a..c7c42c9)
25 25 #include "config.h" #include "config.h"
26 26 #include "console.h" #include "console.h"
27 27 #include <cstring> #include <cstring>
28 #include <stdlib.h>
28 29
29 30 Keybindings * keybindings; Keybindings * keybindings;
30 31 Commandlist * commandlist; Commandlist * commandlist;
 
... ... Input::Input()
68 69 mode = INPUT_MODE_COMMAND; mode = INPUT_MODE_COMMAND;
69 70 chbuf = 0; chbuf = 0;
70 71 multiplier = 0; multiplier = 0;
71 strbuf.clear();
72 wstrbuf.clear();
72 73 buffer.clear(); buffer.clear();
73 74 is_tab_completing = false; is_tab_completing = false;
74 75 is_option_tab_completing = false; is_option_tab_completing = false;
 
... ... Inputevent * Input::next()
91 92 { {
92 93 int m; int m;
93 94
94 if ((chbuf = getch()) == ERR)
95 get_wch(&chbuf);
96 if (chbuf == ERR)
97 {
95 98 return NULL; return NULL;
99 }
96 100
97 101 ev.clear(); ev.clear();
98 102
 
... ... Inputevent * Input::next()
117 121 } }
118 122
119 123 buffer.push_back(chbuf); buffer.push_back(chbuf);
120 strbuf.push_back(chbuf);
124 wstrbuf.push_back(chbuf);
125 conv_to_mbs();
121 126 m = keybindings->find(wm->context, &buffer, &ev.action, &strbuf); m = keybindings->find(wm->context, &buffer, &ev.action, &strbuf);
122 127
123 128 if (m == KEYBIND_FIND_EXACT) if (m == KEYBIND_FIND_EXACT)
 
... ... Inputevent * Input::next()
127 132 else if (m == KEYBIND_FIND_NOMATCH) else if (m == KEYBIND_FIND_NOMATCH)
128 133 { {
129 134 buffer.clear(); buffer.clear();
130 strbuf.clear();
135 wstrbuf.clear();
131 136 multiplier = 0; multiplier = 0;
132 137 } }
133 138
 
... ... Inputevent * Input::next()
143 148
144 149 if (ev.result != INPUT_RESULT_NOINPUT) if (ev.result != INPUT_RESULT_NOINPUT)
145 150 { {
151 conv_to_mbs();
146 152 ev.context = wm->context; ev.context = wm->context;
147 153 ev.text = strbuf; ev.text = strbuf;
148 154 ev.multiplier = multiplier > 0 ? multiplier : 1; ev.multiplier = multiplier > 0 ? multiplier : 1;
 
... ... Inputevent * Input::next()
150 156 if (ev.result != INPUT_RESULT_BUFFERED && ev.result != INPUT_RESULT_MULTIPLIER) if (ev.result != INPUT_RESULT_BUFFERED && ev.result != INPUT_RESULT_MULTIPLIER)
151 157 { {
152 158 buffer.clear(); buffer.clear();
153 strbuf.clear();
159 wstrbuf.clear();
154 160 if (ev.action != ACT_MODE_INPUT) if (ev.action != ACT_MODE_INPUT)
155 161 multiplier = 0; multiplier = 0;
156 162 } }
 
... ... void Input::tr_chbuf()
185 191 void Input::handle_text_input() void Input::handle_text_input()
186 192 { {
187 193 option_t * opt; option_t * opt;
188 string::iterator si;
194 wstring::iterator si;
189 195 size_t fpos; size_t fpos;
190 196 size_t pos; size_t pos;
191 197
 
... ... void Input::handle_text_input()
205 211 return; return;
206 212
207 213 case KEY_RIGHT: case KEY_RIGHT:
208 if (cursorpos < strbuf.size())
214 if (cursorpos < wstrbuf.size())
209 215 ++cursorpos; ++cursorpos;
210 216 ev.result = INPUT_RESULT_BUFFERED; ev.result = INPUT_RESULT_BUFFERED;
211 217 return; return;
 
... ... void Input::handle_text_input()
218 224
219 225 case 5: /* ^E */ case 5: /* ^E */
220 226 case KEY_END: case KEY_END:
221 cursorpos = strbuf.size();
227 cursorpos = wstrbuf.size();
222 228 ev.result = INPUT_RESULT_BUFFERED; ev.result = INPUT_RESULT_BUFFERED;
223 229 return; return;
224 230
 
... ... void Input::handle_text_input()
238 244 if (cursorpos > 0) if (cursorpos > 0)
239 245 { {
240 246 buffer.erase(vector<int>::iterator(buffer.begin()), vector<int>::iterator(buffer.begin() + cursorpos)); buffer.erase(vector<int>::iterator(buffer.begin()), vector<int>::iterator(buffer.begin() + cursorpos));
241 strbuf.erase(string::iterator(strbuf.begin()), string::iterator(strbuf.begin() + cursorpos));
247 wstrbuf.erase(wstring::iterator(wstrbuf.begin()), wstring::iterator(wstrbuf.begin() + cursorpos));
242 248 } }
243 249 cursorpos = 0; cursorpos = 0;
244 250 ev.result = INPUT_RESULT_BUFFERED; ev.result = INPUT_RESULT_BUFFERED;
 
... ... void Input::handle_text_input()
255 261 if (cursorpos > 0) if (cursorpos > 0)
256 262 { {
257 263 buffer.erase(--vector<int>::iterator(buffer.begin() + cursorpos)); buffer.erase(--vector<int>::iterator(buffer.begin() + cursorpos));
258 strbuf.erase(--string::iterator(strbuf.begin() + cursorpos));
264 wstrbuf.erase(--wstring::iterator(wstrbuf.begin() + cursorpos));
259 265 if (cursorpos > 0) if (cursorpos > 0)
260 266 --cursorpos; --cursorpos;
261 267 } }
 
... ... void Input::handle_text_input()
270 276
271 277 case 9: /* Tab */ case 9: /* Tab */
272 278 /* Tabcomplete options instead of commands */ /* Tabcomplete options instead of commands */
273 if ((strbuf.size() >= 3 && strbuf.substr(0, 3) == "se ") ||
274 (strbuf.size() >= 4 && strbuf.substr(0, 4) == "set "))
279 if ((wstrbuf.size() >= 3 && wstrbuf.substr(0, 3) == L"se ") ||
280 (wstrbuf.size() >= 4 && wstrbuf.substr(0, 4) == L"set "))
275 281 { {
276 fpos = strbuf.find(' ') + 1;
282 fpos = wstrbuf.find(L' ') + 1;
277 283
278 284 /* No equal sign given, cycle through options */ /* No equal sign given, cycle through options */
279 if ((pos = strbuf.find('=', fpos)) == string::npos)
285 if ((pos = wstrbuf.find(L'=', fpos)) == wstring::npos)
280 286 { {
281 287 if (is_option_tab_completing) if (is_option_tab_completing)
282 288 { {
 
... ... void Input::handle_text_input()
285 291 } }
286 292 else else
287 293 { {
294 conv_to_mbs();
288 295 config->grep_opt(strbuf.substr(fpos), &option_tab_results, &option_tab_prefix); config->grep_opt(strbuf.substr(fpos), &option_tab_results, &option_tab_prefix);
289 296 if (option_tab_results.size() > 0) if (option_tab_results.size() > 0)
290 297 { {
 
... ... void Input::handle_text_input()
296 303 if (is_option_tab_completing) if (is_option_tab_completing)
297 304 { {
298 305 if ((opt = option_tab_results[option_tab_complete_index]) != NULL) if ((opt = option_tab_results[option_tab_complete_index]) != NULL)
306 {
307 conv_to_mbs();
299 308 strbuf = strbuf.substr(0, fpos) + option_tab_prefix + opt->name; strbuf = strbuf.substr(0, fpos) + option_tab_prefix + opt->name;
309 conv_to_wcs();
310 }
300 311 } }
301 312 } }
302 313
303 314 /* Equal sign found, print option if none given. */ /* Equal sign found, print option if none given. */
304 else if (pos + 1 == strbuf.size())
315 else if (pos + 1 == wstrbuf.size())
305 316 { {
317 conv_to_mbs();
306 318 opt = config->get_opt_ptr(strbuf.substr(fpos, pos - fpos)); opt = config->get_opt_ptr(strbuf.substr(fpos, pos - fpos));
307 319 if (opt && opt->type != OPTION_TYPE_BOOL) if (opt && opt->type != OPTION_TYPE_BOOL)
320 {
308 321 strbuf = strbuf + config->get_opt_str(opt); strbuf = strbuf + config->get_opt_str(opt);
322 conv_to_wcs();
323 }
309 324 } }
310 325
311 326 } }
 
... ... void Input::handle_text_input()
320 335 } }
321 336 else else
322 337 { {
338 conv_to_mbs();
323 339 tab_results = commandlist->grep(wm->context, strbuf); tab_results = commandlist->grep(wm->context, strbuf);
324 340 if (tab_results->size() > 0) if (tab_results->size() > 0)
325 341 { {
 
... ... void Input::handle_text_input()
330 346
331 347 if (is_tab_completing) if (is_tab_completing)
332 348 { {
349 conv_to_mbs();
333 350 strbuf = tab_results->at(tab_complete_index)->name; strbuf = tab_results->at(tab_complete_index)->name;
351 conv_to_wcs();
334 352 } }
335 353 } }
336 354
337 355 /* Sync binary input buffer with string buffer */ /* Sync binary input buffer with string buffer */
338 356 buffer.clear(); buffer.clear();
339 for (si = strbuf.begin(); si != strbuf.end(); ++si)
357 for (si = wstrbuf.begin(); si != wstrbuf.end(); ++si)
340 358 buffer.push_back(*si); buffer.push_back(*si);
341 359
342 360 cursorpos = buffer.size(); cursorpos = buffer.size();
 
... ... void Input::handle_text_input()
350 368 return; return;
351 369
352 370 buffer.insert(vector<int>::iterator(buffer.begin() + cursorpos), chbuf); buffer.insert(vector<int>::iterator(buffer.begin() + cursorpos), chbuf);
353 strbuf.insert(string::iterator(strbuf.begin() + cursorpos), chbuf);
371 wstrbuf.insert(wstring::iterator(wstrbuf.begin() + cursorpos), chbuf);
354 372 ++cursorpos; ++cursorpos;
355 373 ev.result = INPUT_RESULT_BUFFERED; ev.result = INPUT_RESULT_BUFFERED;
356 374 } }
 
... ... void Input::setmode(int nmode)
361 379 if (nmode == mode) if (nmode == mode)
362 380 return; return;
363 381
364 strbuf.clear();
382 wstrbuf.clear();
365 383 buffer.clear(); buffer.clear();
366 384 chbuf = 0; chbuf = 0;
367 385 cursorpos = 0; cursorpos = 0;
 
... ... void Input::setmode(int nmode)
372 390 else else
373 391 curs_set(1); curs_set(1);
374 392 } }
393
394 size_t Input::conv_to_mbs()
395 {
396 size_t r = wcstombs(mbs_buffer, wstrbuf.c_str(), 1024);
397 strbuf = mbs_buffer;
398 return r;
399 }
400
401 size_t Input::conv_to_wcs()
402 {
403 size_t r = mbstowcs(wcs_buffer, strbuf.c_str(), 1024);
404 wstrbuf = wcs_buffer;
405 return r;
406 }
File src/input.h changed (mode: 100644) (index 768920c..818fd7c)
... ... class Keybindings
106 106 class Input class Input
107 107 { {
108 108 private: private:
109 int chbuf;
109 /* Used for conversion from/to wide character */
110 char mbs_buffer[1024];
111 wchar_t wcs_buffer[1024];
112
113 wint_t chbuf;
110 114 bool is_tab_completing; bool is_tab_completing;
111 115 bool is_option_tab_completing; bool is_option_tab_completing;
112 116 string option_tab_prefix; string option_tab_prefix;
 
... ... class Input
130 134 int mode; int mode;
131 135 unsigned long multiplier; unsigned long multiplier;
132 136 vector<int> buffer; vector<int> buffer;
137 wstring wstrbuf;
133 138 string strbuf; string strbuf;
134 139
135 140 Input(); Input();
 
... ... class Input
137 142 /* Read next character from ncurses buffer */ /* Read next character from ncurses buffer */
138 143 Inputevent * next(); Inputevent * next();
139 144
145 /* Convert from/to wide-string */
146 size_t conv_to_mbs();
147 size_t conv_to_wcs();
148
140 149 /* Setter and getter for mode */ /* Setter and getter for mode */
141 150 void setmode(int nmode); void setmode(int nmode);
142 151 int getmode() { return mode; } int getmode() { return mode; }
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/pms

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/pms

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master