mirror of
https://github.com/RPCS3/hidapi.git
synced 2025-02-18 17:57:53 +00:00
Support for getting USB Strings using the applications locale.
If the locale's language is not supported by the device, it defaults to the first language available on the device.
This commit is contained in:
parent
2dedc16309
commit
0c07642ab5
@ -19,6 +19,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <errno.h>
|
||||
|
||||
@ -62,6 +63,9 @@ struct hid_device_ {
|
||||
|
||||
static int initialized = 0;
|
||||
|
||||
uint16_t get_usb_code_for_current_locale();
|
||||
|
||||
|
||||
hid_device *new_hid_device()
|
||||
{
|
||||
hid_device *dev = calloc(1, sizeof(hid_device));
|
||||
@ -105,6 +109,33 @@ static uint16_t get_first_language(libusb_device_handle *dev)
|
||||
return buf[1]; // First two bytes are len and descriptor type.
|
||||
}
|
||||
|
||||
static int is_language_supported(libusb_device_handle *dev, uint16_t lang)
|
||||
{
|
||||
uint16_t buf[32];
|
||||
int len;
|
||||
int i;
|
||||
|
||||
/* Get the string from libusb. */
|
||||
len = libusb_get_string_descriptor(dev,
|
||||
0x0, /* String ID */
|
||||
0x0, /* Language */
|
||||
(unsigned char*)buf,
|
||||
sizeof(buf));
|
||||
if (len < 4)
|
||||
return 0x0;
|
||||
|
||||
|
||||
len /= 2; /* language IDs are two-bytes each. */
|
||||
/* Start at index 1 because there are two bytes of protocol data. */
|
||||
for (i = 1; i < len; i++) {
|
||||
if (buf[i] == lang)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This function returns a newly allocated wide string containing the USB
|
||||
device string numbered by the index. The returned string must be freed
|
||||
by using free(). */
|
||||
@ -123,8 +154,12 @@ static wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t index)
|
||||
char *inptr;
|
||||
char *outptr;
|
||||
|
||||
uint16_t lang = get_first_language(dev);
|
||||
|
||||
/* Determine which language to use. */
|
||||
uint16_t lang;
|
||||
lang = get_usb_code_for_current_locale();
|
||||
if (!is_language_supported(dev, lang))
|
||||
lang = get_first_language(dev);
|
||||
|
||||
/* Get the string from libusb. */
|
||||
len = libusb_get_string_descriptor(dev,
|
||||
index,
|
||||
@ -766,3 +801,211 @@ HID_API_EXPORT wchar_t * HID_API_CALL hid_error(hid_device *dev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct lang_map_entry {
|
||||
const char *name;
|
||||
const char *string_code;
|
||||
uint16_t usb_code;
|
||||
};
|
||||
|
||||
#define LANG(name,code,usb_code) { name, code, usb_code }
|
||||
static struct lang_map_entry lang_map[] = {
|
||||
LANG("Afrikaans", "af", 0x0436),
|
||||
LANG("Albanian", "sq", 0x041C),
|
||||
LANG("Arabic - United Arab Emirates", "ar_ae", 0x3801),
|
||||
LANG("Arabic - Bahrain", "ar_bh", 0x3C01),
|
||||
LANG("Arabic - Algeria", "ar_dz", 0x1401),
|
||||
LANG("Arabic - Egypt", "ar_eg", 0x0C01),
|
||||
LANG("Arabic - Iraq", "ar_iq", 0x0801),
|
||||
LANG("Arabic - Jordan", "ar_jo", 0x2C01),
|
||||
LANG("Arabic - Kuwait", "ar_kw", 0x3401),
|
||||
LANG("Arabic - Lebanon", "ar_lb", 0x3001),
|
||||
LANG("Arabic - Libya", "ar_ly", 0x1001),
|
||||
LANG("Arabic - Morocco", "ar_ma", 0x1801),
|
||||
LANG("Arabic - Oman", "ar_om", 0x2001),
|
||||
LANG("Arabic - Qatar", "ar_qa", 0x4001),
|
||||
LANG("Arabic - Saudi Arabia", "ar_sa", 0x0401),
|
||||
LANG("Arabic - Syria", "ar_sy", 0x2801),
|
||||
LANG("Arabic - Tunisia", "ar_tn", 0x1C01),
|
||||
LANG("Arabic - Yemen", "ar_ye", 0x2401),
|
||||
LANG("Armenian", "hy", 0x042B),
|
||||
LANG("Azeri - Latin", "az_az", 0x042C),
|
||||
LANG("Azeri - Cyrillic", "az_az", 0x082C),
|
||||
LANG("Basque", "eu", 0x042D),
|
||||
LANG("Belarusian", "be", 0x0423),
|
||||
LANG("Bulgarian", "bg", 0x0402),
|
||||
LANG("Catalan", "ca", 0x0403),
|
||||
LANG("Chinese - China", "zh_cn", 0x0804),
|
||||
LANG("Chinese - Hong Kong SAR", "zh_hk", 0x0C04),
|
||||
LANG("Chinese - Macau SAR", "zh_mo", 0x1404),
|
||||
LANG("Chinese - Singapore", "zh_sg", 0x1004),
|
||||
LANG("Chinese - Taiwan", "zh_tw", 0x0404),
|
||||
LANG("Croatian", "hr", 0x041A),
|
||||
LANG("Czech", "cs", 0x0405),
|
||||
LANG("Danish", "da", 0x0406),
|
||||
LANG("Dutch - Netherlands", "nl_nl", 0x0413),
|
||||
LANG("Dutch - Belgium", "nl_be", 0x0813),
|
||||
LANG("English - Australia", "en_au", 0x0C09),
|
||||
LANG("English - Belize", "en_bz", 0x2809),
|
||||
LANG("English - Canada", "en_ca", 0x1009),
|
||||
LANG("English - Caribbean", "en_cb", 0x2409),
|
||||
LANG("English - Ireland", "en_ie", 0x1809),
|
||||
LANG("English - Jamaica", "en_jm", 0x2009),
|
||||
LANG("English - New Zealand", "en_nz", 0x1409),
|
||||
LANG("English - Phillippines", "en_ph", 0x3409),
|
||||
LANG("English - Southern Africa", "en_za", 0x1C09),
|
||||
LANG("English - Trinidad", "en_tt", 0x2C09),
|
||||
LANG("English - Great Britain", "en_gb", 0x0809),
|
||||
LANG("English - United States", "en_us", 0x0409),
|
||||
LANG("Estonian", "et", 0x0425),
|
||||
LANG("Farsi", "fa", 0x0429),
|
||||
LANG("Finnish", "fi", 0x040B),
|
||||
LANG("Faroese", "fo", 0x0438),
|
||||
LANG("French - France", "fr_fr", 0x040C),
|
||||
LANG("French - Belgium", "fr_be", 0x080C),
|
||||
LANG("French - Canada", "fr_ca", 0x0C0C),
|
||||
LANG("French - Luxembourg", "fr_lu", 0x140C),
|
||||
LANG("French - Switzerland", "fr_ch", 0x100C),
|
||||
LANG("Gaelic - Ireland", "gd_ie", 0x083C),
|
||||
LANG("Gaelic - Scotland", "gd", 0x043C),
|
||||
LANG("German - Germany", "de_de", 0x0407),
|
||||
LANG("German - Austria", "de_at", 0x0C07),
|
||||
LANG("German - Liechtenstein", "de_li", 0x1407),
|
||||
LANG("German - Luxembourg", "de_lu", 0x1007),
|
||||
LANG("German - Switzerland", "de_ch", 0x0807),
|
||||
LANG("Greek", "el", 0x0408),
|
||||
LANG("Hebrew", "he", 0x040D),
|
||||
LANG("Hindi", "hi", 0x0439),
|
||||
LANG("Hungarian", "hu", 0x040E),
|
||||
LANG("Icelandic", "is", 0x040F),
|
||||
LANG("Indonesian", "id", 0x0421),
|
||||
LANG("Italian - Italy", "it_it", 0x0410),
|
||||
LANG("Italian - Switzerland", "it_ch", 0x0810),
|
||||
LANG("Japanese", "ja", 0x0411),
|
||||
LANG("Korean", "ko", 0x0412),
|
||||
LANG("Latvian", "lv", 0x0426),
|
||||
LANG("Lithuanian", "lt", 0x0427),
|
||||
LANG("F.Y.R.O. Macedonia", "mk", 0x042F),
|
||||
LANG("Malay - Malaysia", "ms_my", 0x043E),
|
||||
LANG("Malay – Brunei", "ms_bn", 0x083E),
|
||||
LANG("Maltese", "mt", 0x043A),
|
||||
LANG("Marathi", "mr", 0x044E),
|
||||
LANG("Norwegian - Bokml", "no_no", 0x0414),
|
||||
LANG("Norwegian - Nynorsk", "no_no", 0x0814),
|
||||
LANG("Polish", "pl", 0x0415),
|
||||
LANG("Portuguese - Portugal", "pt_pt", 0x0816),
|
||||
LANG("Portuguese - Brazil", "pt_br", 0x0416),
|
||||
LANG("Raeto-Romance", "rm", 0x0417),
|
||||
LANG("Romanian - Romania", "ro", 0x0418),
|
||||
LANG("Romanian - Republic of Moldova", "ro_mo", 0x0818),
|
||||
LANG("Russian", "ru", 0x0419),
|
||||
LANG("Russian - Republic of Moldova", "ru_mo", 0x0819),
|
||||
LANG("Sanskrit", "sa", 0x044F),
|
||||
LANG("Serbian - Cyrillic", "sr_sp", 0x0C1A),
|
||||
LANG("Serbian - Latin", "sr_sp", 0x081A),
|
||||
LANG("Setsuana", "tn", 0x0432),
|
||||
LANG("Slovenian", "sl", 0x0424),
|
||||
LANG("Slovak", "sk", 0x041B),
|
||||
LANG("Sorbian", "sb", 0x042E),
|
||||
LANG("Spanish - Spain (Traditional)", "es_es", 0x040A),
|
||||
LANG("Spanish - Argentina", "es_ar", 0x2C0A),
|
||||
LANG("Spanish - Bolivia", "es_bo", 0x400A),
|
||||
LANG("Spanish - Chile", "es_cl", 0x340A),
|
||||
LANG("Spanish - Colombia", "es_co", 0x240A),
|
||||
LANG("Spanish - Costa Rica", "es_cr", 0x140A),
|
||||
LANG("Spanish - Dominican Republic", "es_do", 0x1C0A),
|
||||
LANG("Spanish - Ecuador", "es_ec", 0x300A),
|
||||
LANG("Spanish - Guatemala", "es_gt", 0x100A),
|
||||
LANG("Spanish - Honduras", "es_hn", 0x480A),
|
||||
LANG("Spanish - Mexico", "es_mx", 0x080A),
|
||||
LANG("Spanish - Nicaragua", "es_ni", 0x4C0A),
|
||||
LANG("Spanish - Panama", "es_pa", 0x180A),
|
||||
LANG("Spanish - Peru", "es_pe", 0x280A),
|
||||
LANG("Spanish - Puerto Rico", "es_pr", 0x500A),
|
||||
LANG("Spanish - Paraguay", "es_py", 0x3C0A),
|
||||
LANG("Spanish - El Salvador", "es_sv", 0x440A),
|
||||
LANG("Spanish - Uruguay", "es_uy", 0x380A),
|
||||
LANG("Spanish - Venezuela", "es_ve", 0x200A),
|
||||
LANG("Southern Sotho", "st", 0x0430),
|
||||
LANG("Swahili", "sw", 0x0441),
|
||||
LANG("Swedish - Sweden", "sv_se", 0x041D),
|
||||
LANG("Swedish - Finland", "sv_fi", 0x081D),
|
||||
LANG("Tamil", "ta", 0x0449),
|
||||
LANG("Tatar", "tt", 0X0444),
|
||||
LANG("Thai", "th", 0x041E),
|
||||
LANG("Turkish", "tr", 0x041F),
|
||||
LANG("Tsonga", "ts", 0x0431),
|
||||
LANG("Ukrainian", "uk", 0x0422),
|
||||
LANG("Urdu", "ur", 0x0420),
|
||||
LANG("Uzbek - Cyrillic", "uz_uz", 0x0843),
|
||||
LANG("Uzbek – Latin", "uz_uz", 0x0443),
|
||||
LANG("Vietnamese", "vi", 0x042A),
|
||||
LANG("Xhosa", "xh", 0x0434),
|
||||
LANG("Yiddish", "yi", 0x043D),
|
||||
LANG("Zulu", "zu", 0x0435),
|
||||
LANG(NULL, NULL, 0x0),
|
||||
};
|
||||
|
||||
uint16_t get_usb_code_for_current_locale()
|
||||
{
|
||||
char *locale;
|
||||
char search_string[64];
|
||||
char *ptr;
|
||||
|
||||
/* Get the current locale. */
|
||||
locale = setlocale(0, NULL);
|
||||
if (!locale)
|
||||
return 0x0;
|
||||
|
||||
/* Make a copy of the current locale string. */
|
||||
strncpy(search_string, locale, sizeof(search_string));
|
||||
search_string[sizeof(search_string)-1] = '\0';
|
||||
|
||||
/* Chop off the encoding part, and make it lower case. */
|
||||
ptr = search_string;
|
||||
while (*ptr) {
|
||||
*ptr = tolower(*ptr);
|
||||
if (*ptr == '.') {
|
||||
*ptr = '\0';
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* Find the entry which matches the string code of our locale. */
|
||||
struct lang_map_entry *lang = lang_map;
|
||||
while (lang->string_code) {
|
||||
if (!strcmp(lang->string_code, search_string)) {
|
||||
return lang->usb_code;
|
||||
}
|
||||
lang++;
|
||||
}
|
||||
|
||||
/* There was no match. Find with just the language only. */
|
||||
/* Chop off the variant. Chop it off at the '_'. */
|
||||
ptr = search_string;
|
||||
while (*ptr) {
|
||||
*ptr = tolower(*ptr);
|
||||
if (*ptr == '_') {
|
||||
*ptr = '\0';
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
#if 0 // TODO: Do we need this?
|
||||
/* Find the entry which matches the string code of our language. */
|
||||
lang = lang_map;
|
||||
while (lang->string_code) {
|
||||
if (!strcmp(lang->string_code, search_string)) {
|
||||
return lang->usb_code;
|
||||
}
|
||||
lang++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Found nothing. */
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user