30 #include "../../SDL_internal.h"
34 #ifdef SDL_JOYSTICK_HIDAPI
50 typedef struct _SDL_ThreadBarrier
58 static int SDL_CreateThreadBarrier(SDL_ThreadBarrier *barrier,
Uint32 count)
60 if (barrier ==
NULL) {
68 if (barrier->mutex ==
NULL) {
72 if (barrier->cond ==
NULL) {
76 barrier->trip_count =
count;
82 static void SDL_DestroyThreadBarrier(SDL_ThreadBarrier *barrier)
88 static int SDL_WaitThreadBarrier(SDL_ThreadBarrier *barrier)
92 if (barrier->count >= barrier->trip_count) {
103 #if defined(__cplusplus) && !defined(NAMESPACE)
108 #define LOG(...) fprintf(stderr, __VA_ARGS__)
110 #define LOG(...) do {} while (0)
114 #define DETACH_KERNEL_DRIVER
126 struct input_report {
129 struct input_report *next;
135 libusb_device_handle *device_handle;
140 int input_ep_max_packet_size;
147 int manufacturer_index;
158 SDL_ThreadBarrier barrier;
161 struct libusb_transfer *transfer;
164 struct input_report *input_reports;
167 static libusb_context *usb_context =
NULL;
169 uint16_t get_usb_code_for_current_locale(
void);
179 SDL_CreateThreadBarrier(&dev->barrier, 2);
187 SDL_DestroyThreadBarrier(&dev->barrier);
197 static void register_error(
hid_device *dev,
const char *
op)
203 #ifdef INVASIVE_GET_USAGE
209 if (cur + num_bytes >=
len)
214 else if (num_bytes == 1) {
217 else if (num_bytes == 2) {
218 return (rpt[cur+2] * 256 + rpt[cur+1]);
220 else if (num_bytes == 4) {
221 return (rpt[cur+4] * 0x01000000 +
222 rpt[cur+3] * 0x00010000 +
223 rpt[cur+2] * 0x00000100 +
224 rpt[cur+1] * 0x00000001);
234 static int get_usage(
uint8_t *report_descriptor,
size_t size,
235 unsigned short *usage_page,
unsigned short *
usage)
239 int data_len, key_size;
240 int usage_found = 0, usage_page_found = 0;
243 int key = report_descriptor[
i];
244 int key_cmd =
key & 0xfc;
248 if ((
key & 0xf0) == 0xf0) {
254 data_len = report_descriptor[
i+1];
265 size_code =
key & 0x3;
270 data_len = size_code;
283 if (key_cmd == 0x4) {
284 *usage_page = get_bytes(report_descriptor,
size, data_len,
i);
285 usage_page_found = 1;
288 if (key_cmd == 0x8) {
289 *
usage = get_bytes(report_descriptor,
size, data_len,
i);
294 if (usage_page_found && usage_found)
298 i += data_len + key_size;
305 #if defined(__FreeBSD__) && __FreeBSD__ < 10
313 static inline int libusb_get_string_descriptor(libusb_device_handle *dev,
317 return libusb_control_transfer(dev,
318 LIBUSB_ENDPOINT_IN | 0
x0,
319 LIBUSB_REQUEST_GET_DESCRIPTOR,
320 (LIBUSB_DT_STRING << 8) | descriptor_index,
329 static uint16_t get_first_language(libusb_device_handle *dev)
335 len = libusb_get_string_descriptor(dev,
346 static int is_language_supported(libusb_device_handle *dev,
uint16_t lang)
353 len = libusb_get_string_descriptor(dev,
364 for (
i = 1;
i <
len;
i++) {
376 static wchar_t *get_usb_string(libusb_device_handle *dev,
uint8_t idx)
392 lang = get_usb_code_for_current_locale();
393 if (!is_language_supported(dev, lang))
394 lang = get_first_language(dev);
397 len = libusb_get_string_descriptor(dev,
410 if (ic == (SDL_iconv_t)-1) {
411 LOG(
"SDL_iconv_open() failed\n");
419 outptr = (
char*) wbuf;
420 outbytes =
sizeof(wbuf);
421 res =
SDL_iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
422 if (
res == (
size_t)-1) {
423 LOG(
"SDL_iconv() failed\n");
428 wbuf[
sizeof(wbuf)/
sizeof(wbuf[0])-1] = 0x00000000;
429 if (outbytes >=
sizeof(wbuf[0]))
430 *((
wchar_t*)outptr) = 0x00000000;
441 static char *make_path(libusb_device *dev,
int interface_number)
444 snprintf(str,
sizeof(str),
"%04x:%04x:%02x",
445 libusb_get_bus_number(dev),
446 libusb_get_device_address(dev),
448 str[
sizeof(str)-1] =
'\0';
460 if (libusb_init(&usb_context))
464 locale = setlocale(LC_CTYPE,
NULL);
466 setlocale(LC_CTYPE,
"");
475 libusb_exit(usb_context);
482 static int is_xbox360(
unsigned short vendor_id,
const struct libusb_interface_descriptor *intf_desc)
484 static const int XB360_IFACE_SUBCLASS = 93;
485 static const int XB360_IFACE_PROTOCOL = 1;
486 static const int XB360W_IFACE_PROTOCOL = 129;
487 static const int SUPPORTED_VENDORS[] = {
511 if (intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
512 intf_desc->bInterfaceSubClass == XB360_IFACE_SUBCLASS &&
513 (intf_desc->bInterfaceProtocol == XB360_IFACE_PROTOCOL ||
514 intf_desc->bInterfaceProtocol == XB360W_IFACE_PROTOCOL)) {
516 for (
i = 0;
i <
sizeof(SUPPORTED_VENDORS)/
sizeof(SUPPORTED_VENDORS[0]); ++
i) {
517 if (vendor_id == SUPPORTED_VENDORS[
i]) {
525 static int is_xboxone(
unsigned short vendor_id,
const struct libusb_interface_descriptor *intf_desc)
527 static const int XB1_IFACE_SUBCLASS = 71;
528 static const int XB1_IFACE_PROTOCOL = 208;
529 static const int SUPPORTED_VENDORS[] = {
539 if (intf_desc->bInterfaceNumber == 0 &&
540 intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
541 intf_desc->bInterfaceSubClass == XB1_IFACE_SUBCLASS &&
542 intf_desc->bInterfaceProtocol == XB1_IFACE_PROTOCOL) {
544 for (
i = 0;
i <
sizeof(SUPPORTED_VENDORS)/
sizeof(SUPPORTED_VENDORS[0]); ++
i) {
545 if (vendor_id == SUPPORTED_VENDORS[
i]) {
553 static int should_enumerate_interface(
unsigned short vendor_id,
const struct libusb_interface_descriptor *intf_desc)
555 if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID)
559 if (is_xbox360(vendor_id, intf_desc))
563 if (is_xboxone(vendor_id, intf_desc))
571 libusb_device **devs;
573 libusb_device_handle *
handle;
583 num_devs = libusb_get_device_list(usb_context, &devs);
586 while ((dev = devs[
i++]) !=
NULL) {
587 struct libusb_device_descriptor desc;
588 struct libusb_config_descriptor *conf_desc =
NULL;
590 int interface_num = 0;
592 int res = libusb_get_device_descriptor(dev, &desc);
593 unsigned short dev_vid = desc.idVendor;
594 unsigned short dev_pid = desc.idProduct;
596 res = libusb_get_active_config_descriptor(dev, &conf_desc);
598 libusb_get_config_descriptor(dev, 0, &conf_desc);
600 for (
j = 0;
j < conf_desc->bNumInterfaces;
j++) {
601 const struct libusb_interface *intf = &conf_desc->interface[
j];
602 for (
k = 0;
k < intf->num_altsetting;
k++) {
603 const struct libusb_interface_descriptor *intf_desc;
604 intf_desc = &intf->altsetting[
k];
605 if (should_enumerate_interface(dev_vid, intf_desc)) {
606 interface_num = intf_desc->bInterfaceNumber;
609 if ((vendor_id == 0
x0 || vendor_id == dev_vid) &&
610 (product_id == 0
x0 || product_id == dev_pid)) {
628 cur_dev->
path = make_path(dev, interface_num);
631 if (desc.iSerialNumber > 0)
633 get_usb_string(
handle, desc.iSerialNumber);
636 if (desc.iManufacturer > 0)
638 get_usb_string(
handle, desc.iManufacturer);
639 if (desc.iProduct > 0)
641 get_usb_string(
handle, desc.iProduct);
643 #ifdef INVASIVE_GET_USAGE
660 unsigned char data[256];
661 #ifdef DETACH_KERNEL_DRIVER
664 res = libusb_kernel_driver_active(
handle, interface_num);
666 res = libusb_detach_kernel_driver(
handle, interface_num);
668 LOG(
"Couldn't detach kernel driver, even though a kernel driver was attached.");
673 res = libusb_claim_interface(
handle, interface_num);
676 res = libusb_control_transfer(
handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0,
data,
sizeof(
data), 5000);
678 unsigned short page=0,
usage=0;
686 LOG(
"libusb_control_transfer() for getting the HID report failed with %d\n",
res);
689 res = libusb_release_interface(
handle, interface_num);
691 LOG(
"Can't release the interface.\n");
694 LOG(
"Can't claim interface %d\n",
res);
695 #ifdef DETACH_KERNEL_DRIVER
698 res = libusb_attach_kernel_driver(
handle, interface_num);
700 LOG(
"Couldn't re-attach kernel driver.\n");
722 LOG(
"Can't open device 0x%.4x/0x%.4x during enumeration: %d\n", dev_vid, dev_pid,
res);
727 libusb_free_config_descriptor(conf_desc);
731 libusb_free_device_list(devs, 1);
742 free(
d->serial_number);
743 free(
d->manufacturer_string);
744 free(
d->product_string);
753 const char *path_to_open =
NULL;
764 path_to_open = cur_dev->
path;
769 path_to_open = cur_dev->
path;
773 cur_dev = cur_dev->
next;
786 static void read_callback(
struct libusb_transfer *transfer)
791 if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
793 struct input_report *rpt = (
struct input_report*)
malloc(
sizeof(*rpt));
795 memcpy(rpt->data, transfer->buffer, transfer->actual_length);
796 rpt->len = transfer->actual_length;
802 if (dev->input_reports ==
NULL) {
804 dev->input_reports = rpt;
809 struct input_report *cur = dev->input_reports;
811 while (cur->next !=
NULL) {
820 if (num_queued > 30) {
821 return_data(dev,
NULL, 0);
826 else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
827 dev->shutdown_thread = 1;
831 else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
832 dev->shutdown_thread = 1;
836 else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {
840 LOG(
"Unknown transfer code: %d\n", transfer->status);
844 res = libusb_submit_transfer(transfer);
846 LOG(
"Unable to submit URB. libusb error code: %d\n",
res);
847 dev->shutdown_thread = 1;
853 static int read_thread(
void *
param)
857 const size_t length = dev->input_ep_max_packet_size;
861 dev->transfer = libusb_alloc_transfer(0);
862 libusb_fill_interrupt_transfer(dev->transfer,
873 libusb_submit_transfer(dev->transfer);
876 SDL_WaitThreadBarrier(&dev->barrier);
879 while (!dev->shutdown_thread) {
881 res = libusb_handle_events(usb_context);
884 LOG(
"read_thread(): libusb reports error # %d\n",
res);
887 if (
res != LIBUSB_ERROR_BUSY &&
888 res != LIBUSB_ERROR_TIMEOUT &&
889 res != LIBUSB_ERROR_OVERFLOW &&
890 res != LIBUSB_ERROR_INTERRUPTED) {
898 libusb_cancel_transfer(dev->transfer);
900 while (!dev->cancelled)
901 libusb_handle_events_completed(usb_context, &dev->cancelled);
923 static void init_xboxone(libusb_device_handle *device_handle,
struct libusb_config_descriptor *conf_desc)
925 static const int XB1_IFACE_SUBCLASS = 71;
926 static const int XB1_IFACE_PROTOCOL = 208;
929 for (
j = 0;
j < conf_desc->bNumInterfaces;
j++) {
930 const struct libusb_interface *intf = &conf_desc->interface[
j];
931 for (
k = 0;
k < intf->num_altsetting;
k++) {
932 const struct libusb_interface_descriptor *intf_desc;
933 intf_desc = &intf->altsetting[
k];
935 if (intf_desc->bInterfaceNumber != 0 &&
936 intf_desc->bAlternateSetting == 0 &&
937 intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
938 intf_desc->bInterfaceSubClass == XB1_IFACE_SUBCLASS &&
939 intf_desc->bInterfaceProtocol == XB1_IFACE_PROTOCOL) {
940 res = libusb_claim_interface(device_handle, intf_desc->bInterfaceNumber);
942 LOG(
"can't claim interface %d: %d\n", intf_desc->bInterfaceNumber,
res);
946 res = libusb_set_interface_alt_setting(device_handle, intf_desc->bInterfaceNumber, intf_desc->bAlternateSetting);
948 LOG(
"xbox init: can't set alt setting %d: %d\n", intf_desc->bInterfaceNumber,
res);
951 libusb_release_interface(device_handle, intf_desc->bInterfaceNumber);
961 libusb_device **devs;
962 libusb_device *usb_dev;
970 dev = new_hid_device();
972 libusb_get_device_list(usb_context, &devs);
973 while ((usb_dev = devs[
d++]) !=
NULL) {
974 struct libusb_device_descriptor desc;
975 struct libusb_config_descriptor *conf_desc =
NULL;
978 libusb_get_device_descriptor(usb_dev, &desc);
980 res = libusb_get_active_config_descriptor(usb_dev, &conf_desc);
982 libusb_get_config_descriptor(usb_dev, 0, &conf_desc);
985 for (
j = 0;
j < conf_desc->bNumInterfaces;
j++) {
986 const struct libusb_interface *intf = &conf_desc->interface[
j];
987 for (
k = 0;
k < intf->num_altsetting;
k++) {
988 const struct libusb_interface_descriptor *intf_desc;
989 intf_desc = &intf->altsetting[
k];
990 if (should_enumerate_interface(desc.idVendor, intf_desc)) {
991 char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber);
992 if (!strcmp(dev_path,
path)) {
993 int detached_driver = 0;
998 res = libusb_open(usb_dev, &dev->device_handle);
1000 LOG(
"can't open device\n");
1006 #ifdef DETACH_KERNEL_DRIVER
1009 if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {
1010 res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);
1012 libusb_close(dev->device_handle);
1013 LOG(
"Unable to detach Kernel Driver\n");
1018 detached_driver = 1;
1022 res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
1024 LOG(
"can't claim interface %d: %d\n", intf_desc->bInterfaceNumber,
res);
1026 libusb_close(dev->device_handle);
1032 if (is_xboxone(desc.idVendor, intf_desc)) {
1033 init_xboxone(dev->device_handle, conf_desc);
1037 dev->manufacturer_index = desc.iManufacturer;
1038 dev->product_index = desc.iProduct;
1039 dev->serial_index = desc.iSerialNumber;
1042 dev->interface = intf_desc->bInterfaceNumber;
1043 dev->detached_driver = detached_driver;
1047 for (
i = 0;
i < intf_desc->bNumEndpoints;
i++) {
1048 const struct libusb_endpoint_descriptor *ep
1049 = &intf_desc->endpoint[
i];
1054 (ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
1055 == LIBUSB_TRANSFER_TYPE_INTERRUPT;
1057 (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
1058 == LIBUSB_ENDPOINT_OUT;
1060 (ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
1061 == LIBUSB_ENDPOINT_IN;
1064 if (dev->input_endpoint == 0 &&
1065 is_interrupt && is_input) {
1067 dev->input_endpoint = ep->bEndpointAddress;
1068 dev->input_ep_max_packet_size = ep->wMaxPacketSize;
1070 if (dev->output_endpoint == 0 &&
1071 is_interrupt && is_output) {
1073 dev->output_endpoint = ep->bEndpointAddress;
1080 SDL_WaitThreadBarrier(&dev->barrier);
1087 libusb_free_config_descriptor(conf_desc);
1091 libusb_free_device_list(devs, 1);
1099 free_hid_device(dev);
1109 if (dev->output_endpoint <= 0) {
1110 int report_number =
data[0];
1111 int skipped_report_id = 0;
1113 if (report_number == 0
x0) {
1116 skipped_report_id = 1;
1120 res = libusb_control_transfer(dev->device_handle,
1121 LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
1123 (2 << 8) | report_number,
1131 if (skipped_report_id)
1139 res = libusb_interrupt_transfer(dev->device_handle,
1140 dev->output_endpoint,
1141 (
unsigned char*)
data,
1143 &actual_length, 1000);
1148 return actual_length;
1158 struct input_report *rpt = dev->input_reports;
1162 dev->input_reports = rpt->next;
1169 static void cleanup_mutex(
void *
param)
1179 int bytes_read = -1;
1183 int res = libusb_interrupt_transfer(dev->device_handle, dev->input_endpoint,
data,
length, &transferred, 5000);
1184 LOG(
"transferred: %d\n", transferred);
1192 if (dev->input_reports) {
1198 if (dev->shutdown_thread) {
1205 if (milliseconds == -1) {
1207 while (!dev->input_reports && !dev->shutdown_thread) {
1210 if (dev->input_reports) {
1214 else if (milliseconds > 0) {
1218 while (!dev->input_reports && !dev->shutdown_thread) {
1221 if (dev->input_reports) {
1261 dev->blocking = !nonblock;
1270 int skipped_report_id = 0;
1271 int report_number =
data[0];
1273 if (report_number == 0
x0) {
1276 skipped_report_id = 1;
1279 res = libusb_control_transfer(dev->device_handle,
1280 LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
1282 (3 << 8) | report_number,
1291 if (skipped_report_id)
1300 int skipped_report_id = 0;
1301 int report_number =
data[0];
1303 if (report_number == 0
x0) {
1308 skipped_report_id = 1;
1310 res = libusb_control_transfer(dev->device_handle,
1311 LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
1313 (3 << 8) | report_number,
1321 if (skipped_report_id)
1336 dev->shutdown_thread = 1;
1337 libusb_cancel_transfer(dev->transfer);
1343 free(dev->transfer->buffer);
1344 libusb_free_transfer(dev->transfer);
1347 libusb_release_interface(dev->device_handle, dev->interface);
1349 #ifdef DETACH_KERNEL_DRIVER
1351 if (dev->detached_driver) {
1352 int res = libusb_attach_kernel_driver(dev->device_handle, dev->interface);
1354 LOG(
"Couldn't re-attach kernel driver.\n");
1359 libusb_close(dev->device_handle);
1363 while (dev->input_reports) {
1364 return_data(dev,
NULL, 0);
1368 free_hid_device(dev);
1391 str = get_usb_string(dev->device_handle, string_index);
1393 wcsncpy(
string, str, maxlen);
1394 string[maxlen-1] = L
'\0';
1409 struct lang_map_entry {
1411 const char *string_code;
1415 #define LANG(name,code,usb_code) { name, code, usb_code }
1416 static struct lang_map_entry lang_map[] = {
1417 LANG(
"Afrikaans",
"af", 0x0436),
1418 LANG(
"Albanian",
"sq", 0x041C),
1419 LANG(
"Arabic - United Arab Emirates",
"ar_ae", 0x3801),
1420 LANG(
"Arabic - Bahrain",
"ar_bh", 0x3C01),
1421 LANG(
"Arabic - Algeria",
"ar_dz", 0x1401),
1422 LANG(
"Arabic - Egypt",
"ar_eg", 0x0C01),
1423 LANG(
"Arabic - Iraq",
"ar_iq", 0x0801),
1424 LANG(
"Arabic - Jordan",
"ar_jo", 0x2C01),
1425 LANG(
"Arabic - Kuwait",
"ar_kw", 0x3401),
1426 LANG(
"Arabic - Lebanon",
"ar_lb", 0x3001),
1427 LANG(
"Arabic - Libya",
"ar_ly", 0x1001),
1428 LANG(
"Arabic - Morocco",
"ar_ma", 0x1801),
1429 LANG(
"Arabic - Oman",
"ar_om", 0x2001),
1430 LANG(
"Arabic - Qatar",
"ar_qa", 0x4001),
1431 LANG(
"Arabic - Saudi Arabia",
"ar_sa", 0x0401),
1432 LANG(
"Arabic - Syria",
"ar_sy", 0x2801),
1433 LANG(
"Arabic - Tunisia",
"ar_tn", 0x1C01),
1434 LANG(
"Arabic - Yemen",
"ar_ye", 0x2401),
1435 LANG(
"Armenian",
"hy", 0x042B),
1436 LANG(
"Azeri - Latin",
"az_az", 0x042C),
1437 LANG(
"Azeri - Cyrillic",
"az_az", 0x082C),
1438 LANG(
"Basque",
"eu", 0x042D),
1439 LANG(
"Belarusian",
"be", 0x0423),
1440 LANG(
"Bulgarian",
"bg", 0x0402),
1441 LANG(
"Catalan",
"ca", 0x0403),
1442 LANG(
"Chinese - China",
"zh_cn", 0x0804),
1443 LANG(
"Chinese - Hong Kong SAR",
"zh_hk", 0x0C04),
1444 LANG(
"Chinese - Macau SAR",
"zh_mo", 0x1404),
1445 LANG(
"Chinese - Singapore",
"zh_sg", 0x1004),
1446 LANG(
"Chinese - Taiwan",
"zh_tw", 0x0404),
1447 LANG(
"Croatian",
"hr", 0x041A),
1448 LANG(
"Czech",
"cs", 0x0405),
1449 LANG(
"Danish",
"da", 0x0406),
1450 LANG(
"Dutch - Netherlands",
"nl_nl", 0x0413),
1451 LANG(
"Dutch - Belgium",
"nl_be", 0x0813),
1452 LANG(
"English - Australia",
"en_au", 0x0C09),
1453 LANG(
"English - Belize",
"en_bz", 0x2809),
1454 LANG(
"English - Canada",
"en_ca", 0x1009),
1455 LANG(
"English - Caribbean",
"en_cb", 0x2409),
1456 LANG(
"English - Ireland",
"en_ie", 0x1809),
1457 LANG(
"English - Jamaica",
"en_jm", 0x2009),
1458 LANG(
"English - New Zealand",
"en_nz", 0x1409),
1459 LANG(
"English - Philippines",
"en_ph", 0x3409),
1460 LANG(
"English - Southern Africa",
"en_za", 0x1C09),
1461 LANG(
"English - Trinidad",
"en_tt", 0x2C09),
1462 LANG(
"English - Great Britain",
"en_gb", 0x0809),
1463 LANG(
"English - United States",
"en_us", 0x0409),
1464 LANG(
"Estonian",
"et", 0x0425),
1465 LANG(
"Farsi",
"fa", 0x0429),
1466 LANG(
"Finnish",
"fi", 0x040B),
1467 LANG(
"Faroese",
"fo", 0x0438),
1468 LANG(
"French - France",
"fr_fr", 0x040C),
1469 LANG(
"French - Belgium",
"fr_be", 0x080C),
1470 LANG(
"French - Canada",
"fr_ca", 0x0C0C),
1471 LANG(
"French - Luxembourg",
"fr_lu", 0x140C),
1472 LANG(
"French - Switzerland",
"fr_ch", 0x100C),
1473 LANG(
"Gaelic - Ireland",
"gd_ie", 0x083C),
1474 LANG(
"Gaelic - Scotland",
"gd", 0x043C),
1475 LANG(
"German - Germany",
"de_de", 0x0407),
1476 LANG(
"German - Austria",
"de_at", 0x0C07),
1477 LANG(
"German - Liechtenstein",
"de_li", 0x1407),
1478 LANG(
"German - Luxembourg",
"de_lu", 0x1007),
1479 LANG(
"German - Switzerland",
"de_ch", 0x0807),
1480 LANG(
"Greek",
"el", 0x0408),
1481 LANG(
"Hebrew",
"he", 0x040D),
1482 LANG(
"Hindi",
"hi", 0x0439),
1483 LANG(
"Hungarian",
"hu", 0x040E),
1484 LANG(
"Icelandic",
"is", 0x040F),
1485 LANG(
"Indonesian",
"id", 0x0421),
1486 LANG(
"Italian - Italy",
"it_it", 0x0410),
1487 LANG(
"Italian - Switzerland",
"it_ch", 0x0810),
1488 LANG(
"Japanese",
"ja", 0x0411),
1489 LANG(
"Korean",
"ko", 0x0412),
1490 LANG(
"Latvian",
"lv", 0x0426),
1491 LANG(
"Lithuanian",
"lt", 0x0427),
1492 LANG(
"F.Y.R.O. Macedonia",
"mk", 0x042F),
1493 LANG(
"Malay - Malaysia",
"ms_my", 0x043E),
1494 LANG(
"Malay ??? Brunei",
"ms_bn", 0x083E),
1495 LANG(
"Maltese",
"mt", 0x043A),
1496 LANG(
"Marathi",
"mr", 0x044E),
1497 LANG(
"Norwegian - Bokml",
"no_no", 0x0414),
1498 LANG(
"Norwegian - Nynorsk",
"no_no", 0x0814),
1499 LANG(
"Polish",
"pl", 0x0415),
1500 LANG(
"Portuguese - Portugal",
"pt_pt", 0x0816),
1501 LANG(
"Portuguese - Brazil",
"pt_br", 0x0416),
1502 LANG(
"Raeto-Romance",
"rm", 0x0417),
1503 LANG(
"Romanian - Romania",
"ro", 0x0418),
1504 LANG(
"Romanian - Republic of Moldova",
"ro_mo", 0x0818),
1505 LANG(
"Russian",
"ru", 0x0419),
1506 LANG(
"Russian - Republic of Moldova",
"ru_mo", 0x0819),
1507 LANG(
"Sanskrit",
"sa", 0x044F),
1508 LANG(
"Serbian - Cyrillic",
"sr_sp", 0x0C1A),
1509 LANG(
"Serbian - Latin",
"sr_sp", 0x081A),
1510 LANG(
"Setsuana",
"tn", 0x0432),
1511 LANG(
"Slovenian",
"sl", 0x0424),
1512 LANG(
"Slovak",
"sk", 0x041B),
1513 LANG(
"Sorbian",
"sb", 0x042E),
1514 LANG(
"Spanish - Spain (Traditional)",
"es_es", 0x040A),
1515 LANG(
"Spanish - Argentina",
"es_ar", 0x2C0A),
1516 LANG(
"Spanish - Bolivia",
"es_bo", 0x400A),
1517 LANG(
"Spanish - Chile",
"es_cl", 0x340A),
1518 LANG(
"Spanish - Colombia",
"es_co", 0x240A),
1519 LANG(
"Spanish - Costa Rica",
"es_cr", 0x140A),
1520 LANG(
"Spanish - Dominican Republic",
"es_do", 0x1C0A),
1521 LANG(
"Spanish - Ecuador",
"es_ec", 0x300A),
1522 LANG(
"Spanish - Guatemala",
"es_gt", 0x100A),
1523 LANG(
"Spanish - Honduras",
"es_hn", 0x480A),
1524 LANG(
"Spanish - Mexico",
"es_mx", 0x080A),
1525 LANG(
"Spanish - Nicaragua",
"es_ni", 0x4C0A),
1526 LANG(
"Spanish - Panama",
"es_pa", 0x180A),
1527 LANG(
"Spanish - Peru",
"es_pe", 0x280A),
1528 LANG(
"Spanish - Puerto Rico",
"es_pr", 0x500A),
1529 LANG(
"Spanish - Paraguay",
"es_py", 0x3C0A),
1530 LANG(
"Spanish - El Salvador",
"es_sv", 0x440A),
1531 LANG(
"Spanish - Uruguay",
"es_uy", 0x380A),
1532 LANG(
"Spanish - Venezuela",
"es_ve", 0x200A),
1533 LANG(
"Southern Sotho",
"st", 0x0430),
1534 LANG(
"Swahili",
"sw", 0x0441),
1535 LANG(
"Swedish - Sweden",
"sv_se", 0x041D),
1536 LANG(
"Swedish - Finland",
"sv_fi", 0x081D),
1537 LANG(
"Tamil",
"ta", 0x0449),
1538 LANG(
"Tatar",
"tt", 0X0444),
1539 LANG(
"Thai",
"th", 0x041E),
1540 LANG(
"Turkish",
"tr", 0x041F),
1541 LANG(
"Tsonga",
"ts", 0x0431),
1542 LANG(
"Ukrainian",
"uk", 0x0422),
1543 LANG(
"Urdu",
"ur", 0x0420),
1544 LANG(
"Uzbek - Cyrillic",
"uz_uz", 0x0843),
1545 LANG(
"Uzbek ??? Latin",
"uz_uz", 0x0443),
1546 LANG(
"Vietnamese",
"vi", 0x042A),
1547 LANG(
"Xhosa",
"xh", 0x0434),
1548 LANG(
"Yiddish",
"yi", 0x043D),
1549 LANG(
"Zulu",
"zu", 0x0435),
1553 uint16_t get_usb_code_for_current_locale(
void)
1556 char search_string[64];
1558 struct lang_map_entry *lang;
1561 locale = setlocale(0,
NULL);
1566 strncpy(search_string, locale,
sizeof(search_string));
1567 search_string[
sizeof(search_string)-1] =
'\0';
1570 ptr = search_string;
1582 while (lang->string_code) {
1583 if (!strcmp(lang->string_code, search_string)) {
1584 return lang->usb_code;
1591 ptr = search_string;
1604 while (lang->string_code) {
1605 if (!strcmp(lang->string_code, search_string)) {
1606 return lang->usb_code;
1616 #if defined(__cplusplus) && !defined(NAMESPACE)