mirror of
https://github.com/holub/mame
synced 2025-04-23 08:49:55 +03:00
Consolidated code that inputs characters into buffers
This commit is contained in:
parent
ea15eb9111
commit
1a017c9302
@ -12,6 +12,7 @@
|
||||
|
||||
#include "ui/barcode.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/utils.h"
|
||||
|
||||
namespace ui {
|
||||
// itemrefs for key menu items
|
||||
@ -67,7 +68,7 @@ void menu_barcode_reader::populate()
|
||||
}
|
||||
else
|
||||
{
|
||||
new_barcode = m_barcode_buffer;
|
||||
new_barcode = m_barcode_buffer.c_str();
|
||||
}
|
||||
|
||||
item_append(_("New Barcode:"), new_barcode, 0, ITEMREF_NEW_BARCODE);
|
||||
@ -121,8 +122,7 @@ void menu_barcode_reader::handle()
|
||||
{
|
||||
current_device()->write_code(tmp_file.c_str(), tmp_file.length());
|
||||
// if sending was successful, reset char buffer
|
||||
if (m_barcode_buffer[0] != '\0')
|
||||
memset(m_barcode_buffer, '\0', ARRAY_LENGTH(m_barcode_buffer));
|
||||
m_barcode_buffer.clear();
|
||||
reset(reset_options::REMEMBER_POSITION);
|
||||
}
|
||||
}
|
||||
@ -131,26 +131,14 @@ void menu_barcode_reader::handle()
|
||||
case IPT_SPECIAL:
|
||||
if (get_selection_ref() == ITEMREF_NEW_BARCODE)
|
||||
{
|
||||
auto const buflen = std::strlen(m_barcode_buffer);
|
||||
|
||||
// if it's a backspace and we can handle it, do so
|
||||
if ((event->unichar == 8) || (event->unichar == 0x7f))
|
||||
{
|
||||
if (0 < buflen)
|
||||
*const_cast<char *>(utf8_previous_char(&m_barcode_buffer[buflen])) = 0;
|
||||
}
|
||||
else if ((event->unichar >= '0') && (event->unichar <= '9'))
|
||||
{
|
||||
event->append_char(m_barcode_buffer, buflen);
|
||||
}
|
||||
reset(reset_options::REMEMBER_POSITION);
|
||||
if (input_character(m_barcode_buffer, event->unichar, uchar_is_digit))
|
||||
reset(reset_options::REMEMBER_POSITION);
|
||||
}
|
||||
break;
|
||||
|
||||
case IPT_UI_CANCEL:
|
||||
// reset the char buffer also in this case
|
||||
if (m_barcode_buffer[0] != '\0')
|
||||
memset(m_barcode_buffer, '\0', ARRAY_LENGTH(m_barcode_buffer));
|
||||
m_barcode_buffer.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ private:
|
||||
virtual void populate() override;
|
||||
virtual void handle() override;
|
||||
|
||||
char m_barcode_buffer[20];
|
||||
std::string m_barcode_buffer;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
@ -945,7 +945,7 @@ void menu_rgb_ui::inkey_special(const event *menu_event)
|
||||
|
||||
if (!m_key_active)
|
||||
{
|
||||
int val = atoi(m_search);
|
||||
int val = atoi(m_search.data());
|
||||
val = m_color->clamp(val);
|
||||
|
||||
switch ((FPTR)menu_event->itemref)
|
||||
@ -967,7 +967,7 @@ void menu_rgb_ui::inkey_special(const event *menu_event)
|
||||
break;
|
||||
}
|
||||
|
||||
m_search[0] = 0;
|
||||
m_search.erase();
|
||||
m_lock_ref = 0;
|
||||
return;
|
||||
}
|
||||
@ -975,26 +975,11 @@ void menu_rgb_ui::inkey_special(const event *menu_event)
|
||||
|
||||
if (!m_key_active)
|
||||
{
|
||||
m_search[0] = 0;
|
||||
m_search.erase();
|
||||
return;
|
||||
}
|
||||
|
||||
auto const buflen = std::strlen(m_search);
|
||||
if ((menu_event->unichar == 8) || (menu_event->unichar == 0x7f))
|
||||
{
|
||||
// if it's a backspace and we can handle it, do so
|
||||
if (0 < buflen)
|
||||
*const_cast<char *>(utf8_previous_char(&m_search[buflen])) = 0;
|
||||
}
|
||||
else if (buflen >= 3)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if ((menu_event->unichar >= '0' && menu_event->unichar <= '9'))
|
||||
{
|
||||
// if it's any other key and we're not maxed out, update
|
||||
menu_event->append_char(m_search, buflen);
|
||||
}
|
||||
input_character(m_search, 3, menu_event->unichar, uchar_is_digit);
|
||||
}
|
||||
|
||||
std::pair<const char *, const char *> const menu_palette_sel::s_palette[] = {
|
||||
|
@ -162,7 +162,7 @@ private:
|
||||
void inkey_special(const event *menu_event);
|
||||
|
||||
rgb_t *m_color;
|
||||
char m_search[4];
|
||||
std::string m_search;
|
||||
bool m_key_active;
|
||||
int m_lock_ref;
|
||||
std::string m_title;
|
||||
|
@ -342,19 +342,9 @@ void menu_add_change_folder::handle()
|
||||
}
|
||||
else if (menu_event->iptkey == IPT_SPECIAL)
|
||||
{
|
||||
auto const buflen = std::strlen(m_search);
|
||||
bool update_selected = false;
|
||||
|
||||
if ((menu_event->unichar == 8) || (menu_event->unichar == 0x7f))
|
||||
{
|
||||
// if it's a backspace and we can handle it, do so
|
||||
if (0 < buflen)
|
||||
{
|
||||
*const_cast<char *>(utf8_previous_char(&m_search[buflen])) = 0;
|
||||
update_selected = true;
|
||||
}
|
||||
}
|
||||
else if (menu_event->unichar == 0x09)
|
||||
if (menu_event->unichar == 0x09)
|
||||
{
|
||||
// Tab key, save current path
|
||||
std::string error_string;
|
||||
@ -391,11 +381,10 @@ void menu_add_change_folder::handle()
|
||||
reset_parent(reset_options::SELECT_FIRST);
|
||||
stack_pop();
|
||||
}
|
||||
else if (menu_event->is_char_printable())
|
||||
else
|
||||
{
|
||||
// if it's any other key and we're not maxed out, update
|
||||
if (menu_event->append_char(m_search, buflen))
|
||||
update_selected = true;
|
||||
update_selected = input_character(m_search, menu_event->unichar, uchar_is_printable);
|
||||
}
|
||||
|
||||
// check for entries which matches our search buffer
|
||||
@ -406,12 +395,12 @@ void menu_add_change_folder::handle()
|
||||
|
||||
// from current item to the end
|
||||
for (entry = cur_selected; entry < item.size(); entry++)
|
||||
if (item[entry].ref != nullptr && m_search[0] != 0)
|
||||
if (item[entry].ref != nullptr && !m_search.empty())
|
||||
{
|
||||
int match = 0;
|
||||
for (int i = 0; i < ARRAY_LENGTH(m_search); i++)
|
||||
for (int i = 0; i < m_search.size(); i++)
|
||||
{
|
||||
if (core_strnicmp(item[entry].text.c_str(), m_search, i) == 0)
|
||||
if (core_strnicmp(item[entry].text.c_str(), m_search.data(), i) == 0)
|
||||
match = i;
|
||||
}
|
||||
|
||||
@ -425,12 +414,12 @@ void menu_add_change_folder::handle()
|
||||
// and from the first item to current one
|
||||
for (entry = 0; entry < cur_selected; entry++)
|
||||
{
|
||||
if (item[entry].ref != nullptr && m_search[0] != 0)
|
||||
if (item[entry].ref != nullptr && !m_search.empty())
|
||||
{
|
||||
int match = 0;
|
||||
for (int i = 0; i < ARRAY_LENGTH(m_search); i++)
|
||||
for (int i = 0; i < m_search.size(); i++)
|
||||
{
|
||||
if (core_strnicmp(item[entry].text.c_str(), m_search, i) == 0)
|
||||
if (core_strnicmp(item[entry].text.c_str(), m_search.data(), i) == 0)
|
||||
match = i;
|
||||
}
|
||||
|
||||
@ -447,8 +436,7 @@ void menu_add_change_folder::handle()
|
||||
else if (menu_event->iptkey == IPT_UI_CANCEL)
|
||||
{
|
||||
// reset the char buffer also in this case
|
||||
if (m_search[0] != 0)
|
||||
m_search[0] = '\0';
|
||||
m_search.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ private:
|
||||
|
||||
int m_ref;
|
||||
std::string m_current_path;
|
||||
char m_search[40];
|
||||
std::string m_search;
|
||||
bool m_change;
|
||||
std::vector<std::string> m_folders;
|
||||
};
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "ui/filesel.h"
|
||||
#include "ui/ui.h"
|
||||
#include "ui/utils.h"
|
||||
|
||||
#include "imagedev/floppy.h"
|
||||
|
||||
@ -432,33 +433,11 @@ void menu_file_selector::handle()
|
||||
}
|
||||
else if (event->iptkey == IPT_SPECIAL)
|
||||
{
|
||||
bool update_selected = false;
|
||||
|
||||
if ((event->unichar == 8) || (event->unichar == 0x7f))
|
||||
// if it's any other key and we're not maxed out, update
|
||||
if (input_character(m_filename, event->unichar, uchar_is_printable))
|
||||
{
|
||||
// if it's a backspace and we can handle it, do so
|
||||
auto const buflen = m_filename.size();
|
||||
if (0 < buflen)
|
||||
{
|
||||
auto buffer_oldend = m_filename.c_str() + buflen;
|
||||
auto buffer_newend = utf8_previous_char(buffer_oldend);
|
||||
m_filename.resize(buffer_newend - m_filename.c_str());
|
||||
update_selected = true;
|
||||
|
||||
ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename.c_str());
|
||||
}
|
||||
}
|
||||
else if (event->is_char_printable())
|
||||
{
|
||||
// if it's any other key and we're not maxed out, update
|
||||
m_filename += utf8_from_uchar(event->unichar);
|
||||
update_selected = true;
|
||||
|
||||
ui().popup_time(ERROR_MESSAGE_TIME, "%s", m_filename.c_str());
|
||||
}
|
||||
|
||||
if (update_selected)
|
||||
{
|
||||
file_selector_entry const *const cur_selected(reinterpret_cast<file_selector_entry const *>(get_selection_ref()));
|
||||
|
||||
// check for entries which matches our m_filename_buffer:
|
||||
|
@ -138,31 +138,6 @@ protected:
|
||||
int iptkey; // one of the IPT_* values from inptport.h
|
||||
unicode_char unichar; // unicode character if iptkey == IPT_SPECIAL
|
||||
render_bounds mouse; // mouse position if iptkey == IPT_CUSTOM
|
||||
|
||||
bool is_char_printable() const
|
||||
{
|
||||
return
|
||||
!(0x0001f >= unichar) && // C0 control
|
||||
!((0x0007f <= unichar) && (0x0009f >= unichar)) && // DEL and C1 control
|
||||
!((0x0fdd0 <= unichar) && (0x0fddf >= unichar)) && // noncharacters
|
||||
!(0x0fffe == (unichar & 0x0ffff)) && // byte-order detection noncharacter
|
||||
!(0x0ffff == (unichar & 0x0ffff)); // the other noncharacter
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
bool append_char(char (&buffer)[N], std::size_t offset) const
|
||||
{
|
||||
auto const chlen = utf8_from_uchar(&buffer[offset], N - offset - 1, unichar);
|
||||
if (0 < chlen)
|
||||
{
|
||||
buffer[offset + chlen] = '\0';
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int top_line; // main box top line
|
||||
|
@ -99,28 +99,14 @@ void menu_selector::handle()
|
||||
}
|
||||
else if (menu_event->iptkey == IPT_SPECIAL)
|
||||
{
|
||||
auto const buflen = strlen(m_search);
|
||||
if ((menu_event->unichar == 8) || (menu_event->unichar == 0x7f))
|
||||
{
|
||||
// if it's a backspace and we can handle it, do so
|
||||
if (0 < buflen)
|
||||
{
|
||||
*const_cast<char *>(utf8_previous_char(&m_search[buflen])) = 0;
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
}
|
||||
else if (menu_event->is_char_printable())
|
||||
{
|
||||
// if it's any other key and we're not maxed out, update
|
||||
if (menu_event->append_char(m_search, buflen))
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
if (input_character(m_search, menu_event->unichar, uchar_is_printable))
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
|
||||
// escape pressed with non-empty text clears the text
|
||||
else if (menu_event->iptkey == IPT_UI_CANCEL && m_search[0] != 0)
|
||||
{
|
||||
m_search[0] = '\0';
|
||||
m_search.clear();
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
}
|
||||
@ -132,9 +118,9 @@ void menu_selector::handle()
|
||||
|
||||
void menu_selector::populate()
|
||||
{
|
||||
if (m_search[0] != 0)
|
||||
if (!m_search.empty())
|
||||
{
|
||||
find_matches(m_search);
|
||||
find_matches(m_search.c_str());
|
||||
|
||||
for (int curitem = 0; m_searchlist[curitem]; ++curitem)
|
||||
item_append(*m_searchlist[curitem], "", 0, (void *)m_searchlist[curitem]);
|
||||
|
@ -47,7 +47,7 @@ private:
|
||||
|
||||
void find_matches(const char *str);
|
||||
|
||||
char m_search[40];
|
||||
std::string m_search;
|
||||
UINT16 &m_selector;
|
||||
int m_category, m_hover;
|
||||
bool m_first_pass;
|
||||
|
@ -967,23 +967,8 @@ void menu_select_game::inkey_special(const event *menu_event)
|
||||
{
|
||||
if (!isfavorite())
|
||||
{
|
||||
auto const buflen = std::strlen(m_search);
|
||||
|
||||
if ((menu_event->unichar == 8) || (menu_event->unichar == 0x7f))
|
||||
{
|
||||
// if it's a backspace and we can handle it, do so
|
||||
if (0 < buflen)
|
||||
{
|
||||
*const_cast<char *>(utf8_previous_char(&m_search[buflen])) = 0;
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
}
|
||||
else if (menu_event->is_char_printable())
|
||||
{
|
||||
// if it's any other key and we're not maxed out, update
|
||||
if (menu_event->append_char(m_search, buflen))
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
if (input_character(m_search, menu_event->unichar, uchar_is_printable))
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ private:
|
||||
};
|
||||
|
||||
enum { VISIBLE_GAMES_IN_SEARCH = 200 };
|
||||
char m_search[40];
|
||||
std::string m_search;
|
||||
static bool first_start;
|
||||
static int m_isabios;
|
||||
int highlight;
|
||||
|
@ -488,7 +488,7 @@ void menu_select_software::populate()
|
||||
|
||||
else
|
||||
{
|
||||
find_matches(m_search, VISIBLE_GAMES_IN_SEARCH);
|
||||
find_matches(m_search.c_str(), VISIBLE_GAMES_IN_SEARCH);
|
||||
|
||||
for (int curitem = 0; m_searchlist[curitem] != nullptr; ++curitem)
|
||||
item_append(m_searchlist[curitem]->longname, m_searchlist[curitem]->devicetype,
|
||||
@ -747,23 +747,8 @@ void menu_select_software::inkey_select(const event *menu_event)
|
||||
|
||||
void menu_select_software::inkey_special(const event *menu_event)
|
||||
{
|
||||
auto const buflen = std::strlen(m_search);
|
||||
|
||||
if ((menu_event->unichar == 8) || (menu_event->unichar == 0x7f))
|
||||
{
|
||||
// if it's a backspace and we can handle it, do so
|
||||
if (0 < buflen)
|
||||
{
|
||||
*const_cast<char *>(utf8_previous_char(&m_search[buflen])) = 0;
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
}
|
||||
else if (menu_event->is_char_printable())
|
||||
{
|
||||
// if it's any other key and we're not maxed out, update
|
||||
if (menu_event->append_char(m_search, buflen))
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
if (input_character(m_search, menu_event->unichar, uchar_is_printable))
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,7 +31,7 @@ protected:
|
||||
|
||||
private:
|
||||
enum { VISIBLE_GAMES_IN_SEARCH = 200 };
|
||||
char m_search[40];
|
||||
std::string m_search;
|
||||
const game_driver *m_driver;
|
||||
bool m_has_empty_start;
|
||||
s_filter m_filter;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "ui/ui.h"
|
||||
#include "ui/miscmenu.h"
|
||||
#include "ui/optsmenu.h"
|
||||
#include "ui/utils.h"
|
||||
|
||||
#include "audit.h"
|
||||
#include "drivenum.h"
|
||||
@ -33,8 +34,8 @@ namespace ui {
|
||||
simple_menu_select_game::simple_menu_select_game(mame_ui_manager &mui, render_container &container, const char *gamename) : menu(mui, container), m_driverlist(driver_list::total() + 1)
|
||||
{
|
||||
build_driver_list();
|
||||
if(gamename)
|
||||
strcpy(m_search, gamename);
|
||||
if (gamename)
|
||||
m_search.assign(gamename);
|
||||
m_matchlist[0] = -1;
|
||||
}
|
||||
|
||||
@ -199,23 +200,12 @@ void simple_menu_select_game::inkey_cancel()
|
||||
void simple_menu_select_game::inkey_special(const event *menu_event)
|
||||
{
|
||||
// typed characters append to the buffer
|
||||
auto const buflen = std::strlen(m_search);
|
||||
|
||||
if ((menu_event->unichar == 8) || (menu_event->unichar == 0x7f))
|
||||
size_t old_size = m_search.size();
|
||||
if (input_character(m_search, menu_event->unichar, uchar_is_printable))
|
||||
{
|
||||
// if it's a backspace and we can handle it, do so
|
||||
if (0 < buflen)
|
||||
{
|
||||
*const_cast<char *>(utf8_previous_char(&m_search[buflen])) = 0;
|
||||
if (m_search.size() < old_size)
|
||||
m_rerandomize = true;
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
}
|
||||
else if (menu_event->is_char_printable())
|
||||
{
|
||||
// if it's any other key and we're not maxed out, update
|
||||
if (menu_event->append_char(m_search, buflen))
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
reset(reset_options::SELECT_FIRST);
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,7 +239,7 @@ void simple_menu_select_game::populate()
|
||||
// otherwise, rebuild the match list
|
||||
assert(m_drivlist != nullptr);
|
||||
if (m_search[0] != 0 || m_matchlist[0] == -1 || m_rerandomize)
|
||||
m_drivlist->find_approximate_matches(m_search, matchcount, m_matchlist);
|
||||
m_drivlist->find_approximate_matches(m_search.c_str(), matchcount, m_matchlist);
|
||||
m_rerandomize = false;
|
||||
|
||||
// iterate over entries
|
||||
|
@ -45,7 +45,7 @@ private:
|
||||
// internal state
|
||||
UINT8 m_error;
|
||||
bool m_rerandomize;
|
||||
char m_search[40];
|
||||
std::string m_search;
|
||||
int m_matchlist[VISIBLE_GAMES_IN_LIST];
|
||||
std::vector<const game_driver *> m_driverlist;
|
||||
std::unique_ptr<driver_enumerator> m_drivlist;
|
||||
|
@ -244,7 +244,7 @@ std::vector<std::string> tokenize(const std::string &text, char sep);
|
||||
//-------------------------------------------------
|
||||
|
||||
template <typename F>
|
||||
bool input_character(std::string &buffer, unicode_char unichar, F &&filter)
|
||||
bool input_character(std::string &buffer, std::size_t size, unicode_char unichar, F &&filter)
|
||||
{
|
||||
bool result = false;
|
||||
auto buflen = buffer.size();
|
||||
@ -260,7 +260,7 @@ bool input_character(std::string &buffer, unicode_char unichar, F &&filter)
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
else if ((unichar >= ' ') && filter(unichar))
|
||||
else if ((unichar >= ' ') && (size == ~0 || buffer.size() < size) && filter(unichar))
|
||||
{
|
||||
// append this character
|
||||
buffer += utf8_from_uchar(unichar);
|
||||
@ -270,4 +270,16 @@ bool input_character(std::string &buffer, unicode_char unichar, F &&filter)
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// input_character - inputs a typed character
|
||||
// into a buffer
|
||||
//-------------------------------------------------
|
||||
|
||||
template <typename F>
|
||||
bool input_character(std::string &buffer, unicode_char unichar, F &&filter)
|
||||
{
|
||||
return input_character(buffer, ~0, unichar, filter);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __UI_UTILS_H__ */
|
||||
|
@ -22,6 +22,33 @@ bool uchar_isvalid(unicode_char uchar)
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// uchar_is_printable - tests to see if a unicode
|
||||
// char is printable
|
||||
//-------------------------------------------------
|
||||
|
||||
bool uchar_is_printable(unicode_char uchar)
|
||||
{
|
||||
return
|
||||
!(0x0001f >= uchar) && // C0 control
|
||||
!((0x0007f <= uchar) && (0x0009f >= uchar)) && // DEL and C1 control
|
||||
!((0x0fdd0 <= uchar) && (0x0fddf >= uchar)) && // noncharacters
|
||||
!(0x0fffe == (uchar & 0x0ffff)) && // byte-order detection noncharacter
|
||||
!(0x0ffff == (uchar & 0x0ffff)); // the other noncharacter
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// uchar_is_digit - tests to see if a unicode
|
||||
// char is a digit
|
||||
//-------------------------------------------------
|
||||
|
||||
bool uchar_is_digit(unicode_char uchar)
|
||||
{
|
||||
return uchar >= '0' && uchar <= '9';
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// uchar_from_utf8 - convert a UTF-8 sequence
|
||||
// into a unicode character
|
||||
|
@ -90,6 +90,12 @@ typedef UINT32 unicode_char;
|
||||
// tests to see if a unicode char is a valid code point
|
||||
bool uchar_isvalid(unicode_char uchar);
|
||||
|
||||
// tests to see if a unicode char is printable
|
||||
bool uchar_is_printable(unicode_char uchar);
|
||||
|
||||
// tests to see if a unicode char is a digit
|
||||
bool uchar_is_digit(unicode_char uchar);
|
||||
|
||||
// converting strings to 32-bit Unicode chars
|
||||
int uchar_from_utf8(unicode_char *uchar, const char *utf8char, size_t count);
|
||||
int uchar_from_utf16(unicode_char *uchar, const utf16_char *utf16char, size_t count);
|
||||
|
Loading…
Reference in New Issue
Block a user