Get culture info of the system using win32 application - c++

I am working win32 console application. I want to get the current system locale or culture info in my win32 application.
Like en-US or zh-CN.
Is there anything provided by WINAPI.
Sample code for this will really help.

You should use GetLocaleInfo.
wchar_t szISOLang[5] = { 0 };
wchar_t szISOCountry[5] = { 0 };
::GetLocaleInfo(LOCALE_USER_DEFAULT,
LOCALE_SISO639LANGNAME,
szISOLang,
sizeof(szISOLang) / sizeof(wchar_t));
::GetLocaleInfo(LOCALE_USER_DEFAULT,
LOCALE_SISO3166CTRYNAME,
szISOCountry,
sizeof(szISOCountry) / sizeof(WCHAR));
std::wcout << szISOLang << "_" << szISOCountry << std::endl;

In C or C++, you can create a locale based on a name, so if you supply a name like en-US it will create a matching locale (assuming you use one of the strings it knows about--obviously most libraries aren't going to recognize every possible string).
This has one little-known feature though: if you supply an empty string, it will create a locale that's appropriate for the environment as configured by the user (determined by some means the language doesn't specify).
So, you can retrieve that, and use it. For example:
#include <locale>
#include <iostream>
int main() {
auto loc = std::locale("");
std::cout << loc.name() << "\n";
}
On the machine I'm using at the moment (Linux), this prints out: en_US.UTF-8.

Related

Change input method on windows using c++ and windows API

I want to write some code in C++ in combination with windows API in order to change the input method on windows (Keyboard input language).
Here is my first try:
#include <iostream>
#include <windows.h>
int main() {
int arr_size = GetKeyboardLayoutList(0, NULL);
HKL hkl_array[arr_size]; // The array to hold input locale identifies found in the system(HKL)
// Initialize the array to all zeros
for (int i = 0; i <= arr_size - 1; i++) {
hkl_array[i] = nullptr;
}
int lang_found = GetKeyboardLayoutList(arr_size, hkl_array); // Get all the HKLs in the array
for (int i = 0; i <= lang_found - 1; ++i) {
// Print all the HKLs found
std::cout << i + 1 << ". " << hkl_array[i] << std::endl;
}
std::cout << "Function return: " << ActivateKeyboardLayout(hkl_array[0], KLF_SETFORPROCESS);
return 0;
}
When running the above code with English as the current language I get:
1. 0x4080408
2. 0x4090409
Function return: 0x4090409
(0x4080408 is Greek and 0x4090409 is English)
According to the documentation for ActivateKeyboardLayout, the return value is of type HKL and If the function succeeds, the return value is the previous input locale identifier. Otherwise, it is zero. In my case, the function clearly runs with no errors since it returns the input locale identifier for English witch was the language before the hypothetical change. The language although does not change. I get similar results if I start from greek and try to change to English.
I have tried different values in the flag parameter with no luck. It is always the same thing. I have also tried using the LoadKeyboardLayoutA as follows:
#include <iostream>
#include <windows.h>
int main(){
LPCSTR language_select = "00000408"; // Code for greek
std::cout << LoadKeyboardLayoutA(language_select, KLF_ACTIVATE);
return 0;
}
When running the above code with English as the current language I get:
0x4080408
According to the documentation for LoadKeyboardLayoutA, If the function succeeds, the return type is HKL and the return value is the input locale identifier corresponding to the name specified in the function's parameter (language_select). So this seems to run ok as well but no luck with language change. I also tried with language_select = "00000809" (UK English) and the result I got was Uk English was just added to the list of languages as I did not have it installed.
Finally, I tried calling the ActivateKeyboardLayout with LoadKeyboardLayoutA ad the HKL parameter as follows
#include <iostream>
#include <windows.h>
int main() {
LPCSTR language_select = "00000408"; // Code for greek
std::cout << ActivateKeyboardLayout(LoadKeyboardLayoutA(language_select, KLF_ACTIVATE), KLF_SETFORPROCESS);
return 0;
}
When running the above code with English as the current language I get:
0x4080408
Which again seems normal but there is no chance in the language. I am running this on Windows 10 20H2 OS Build 19042.685 and I am using CLion as an IDE (I don't think it matters but just in case anyone needs the info). What am I doing wrong?
The very first sentence of the ActivateKeyboardLayout function documentation states: "Sets the input locale identifier (formerly called the keyboard layout handle) for the calling thread or the current process.". Since you never read input in your program, you don't observe its effect. It does not change the keyboard layout of the system.
On Windows, each thread has its own keyboard layout. To change the keyboard layout for a specific window, you need to send the WM_INPUTLANGCHANGEREQUEST message to it:
SendMessageW(<windowHandle>, WM_INPUTLANGCHANGEREQUEST, 0, LoadKeyboardLayoutW(language_select, KLF_ACTIVATE));

架 (U+67B6) is not graphical with en_US.UTF-8. Whats going on?

This is a follow up question to:
std::isgraph asserts, how to fix?
After setting locale to "en_US.UTF-8", std::isgraph no longer asserts.
However, the unicode character 架 (U+67B6) is reported as false in the same function. What is going on ?
It's a unicode built on Windows platform.
If you want to test characters that are too large to fit in an unsigned char, you can try using the wide-character versions, or a Unicode library as already suggested (Which is really the better option for portable code, as it removes any system or locale based differences in behavior).
This program:
#include <clocale>
#include <cwctype>
#include <iostream>
int main() {
wchar_t x = L'\u67B6';
char *loc = std::setlocale(LC_CTYPE, "");
std::wcout << "Using locale " << loc << ".\n";
std::wcout << "Character " << x << " is graphical: " << std::boolalpha
<< static_cast<bool>(std::iswgraph(x)) << '\n';
return 0;
}
when compiled and ran on my Ubuntu test system, outputs
Using locale en_US.utf8.
Character 架 is graphical: true
You said you're using Windows, but I don't have a Windows computer available for testing, so I can't confirm if this'll work there or not.
std::isgraph is not a Unicode-aware function.
It's an antiquity from C.
From the documentation:
The behavior is undefined if the value of ch is not representable as unsigned char and is not equal to EOF.
It only takes int because .. it's an antiquity from C. Just like std::tolower.
You should be using something like ICU instead.

Output unicode symbol π and ≈ in c++ win32 console application

I am fairly new to programming, but it seems like the π(pi) symbol is not in the standard set of outputs that ASCII handles.
I am wondering if there is a way to get the console to output the π symbol, so as to express exact answers regarding certain mathematical formulas.
I'm not really sure about any other methods (such as those that use the STL) but you can do this with Win32 using WriteConsoleW:
HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
LPCWSTR lpPiString = L"\u03C0";
DWORD dwNumberOfCharsWritten;
WriteConsoleW(hConsoleOutput, lpPiString, 1, &dwNumberOfCharsWritten, NULL);
The Microsoft CRT is not very Unicode-savvy, so it may be necessary to bypass it and use WriteConsole() directly. I'm assuming you already compile for Unicode, else you need to explicitly use WriteConsoleW()
I'm in the learning phase of this, so correct me if I get something wrong.
It seems like this is a three step process:
Use wide versions of cout, cin, string and so on. So: wcout, wcin, wstring
Before using a stream set it to an Unicode-friendly mode.
Configure the targeted console to use an Unicode-capable font.
You should now be able to rock those funky åäös.
Example:
#include <iostream>
#include <string>
#include <io.h>
// We only need one mode definition in this example, but it and several other
// reside in the header file fcntl.h.
#define _O_WTEXT 0x10000 /* file mode is UTF16 (translated) */
// Possibly useful if we want UTF-8
//#define _O_U8TEXT 0x40000 /* file mode is UTF8 no BOM (translated) */
void main(void)
{
// To be able to write UFT-16 to stdout.
_setmode(_fileno(stdout), _O_WTEXT);
// To be able to read UTF-16 from stdin.
_setmode(_fileno(stdin), _O_WTEXT);
wchar_t* hallå = L"Hallå, värld!";
std::wcout << hallå << std::endl;
// It's all Greek to me. Go UU!
std::wstring etabetapi = L"η β π";
std::wcout << etabetapi << std::endl;
std::wstring myInput;
std::wcin >> myInput;
std:: wcout << myInput << L" has " << myInput.length() << L" characters." << std::endl;
// This character won't show using Consolas or Lucida Console
std::wcout << L"♔" << std::endl;
}

How to get current locale of my environment?

Had tried following code in Linux, but always return 'C' under different LANG settings.
#include <iostream>
#include <locale.h>
#include <locale>
using namespace std;
int main()
{
cout<<"locale 1: "<<setlocale(LC_ALL, NULL)<<endl;
cout<<"locale 2: "<<setlocale(LC_CTYPE, NULL)<<endl;
locale l;
cout<<"locale 3: "<<l.name()<<endl;
}
$ ./a.out
locale 1: C
locale 2: C
locale 3: C
$
$ export LANG=zh_CN.UTF-8
$ ./a.out
locale 1: C
locale 2: C
locale 3: C
What should I do to get current locale setting in Linux(like Ubuntu)?
Another question is, is it the same way to get locale in Windows?
From man 3 setlocale (New maxim: "When in doubt, read the entire manpage."):
If locale is "", each part of the locale that should be modified is set according to the environment variables.
So, we can read the environment variables by calling setlocale at the beginning of the program, as follows:
#include <iostream>
#include <locale.h>
using namespace std;
int main()
{
setlocale(LC_ALL, "");
cout << "LC_ALL: " << setlocale(LC_ALL, NULL) << endl;
cout << "LC_CTYPE: " << setlocale(LC_CTYPE, NULL) << endl;
return 0;
}
My system does not support the zh_CN locale, as the following output reveals:
$ ./a.out
LC_ALL: en_US.utf8
LC_CTYPE: en_US.utf8
$ export LANG=zh_CN.UTF-8
$ ./a.out
LC_ALL: C
LC_CTYPE: C
Windows: I have no idea about Windows locales. I suggest starting with an MSDN search, and then opening a separate Stack Overflow question if you still have questions.
Just figured out how to get locale by C++, simply use an empty string "" to construct std::locale, which does the same thing as setlocale(LC_ALL, "").
locale l("");
cout<<"Locale by C++: "<<l.name()<<endl;
This link described differences in details between C locale and C++ locale.
For Windows use the following code:
LCID lcid = GetThreadLocale();
wchar_t name[LOCALE_NAME_MAX_LENGTH];
if (LCIDToLocaleName(lcid, name, LOCALE_NAME_MAX_LENGTH, 0) == 0)
error(GetLastError());
std::wcout << L"Locale name = " << name << std::endl;
This is going to print something like "en-US".
To purge sublanguage information use the following:
wchar_t parentLocateName[LOCALE_NAME_MAX_LENGTH];
if (GetLocaleInfoEx(name, LOCALE_SPARENT, parentLocateName, LOCALE_NAME_MAX_LENGTH) == 0)
error(GetLastError());
std::wcout << L"parentLocateName = " << parentLocateName << std::endl;
This will give you just "en".
A good alternative to consider instead of std::locale is boost::locale which is capable of returning more reliable information - see http://www.boost.org/doc/libs/1_52_0/libs/locale/doc/html/locale_information.html
boost::locale::info has the following member functions:
std::string name() -- the full name of the locale, for example en_US.UTF-8
std::string language() -- the ISO-639 language code of the current locale, for example "en".
std::string country() -- the ISO-3199 country code of the current locale, for example "US".
std::string variant() -- the variant of current locale, for example "euro".
std::string encoding() -- the encoding used for char based strings, for example "UTF-8"
bool utf8() -- a fast way to check whether the encoding is UTF-8.
The default constructor of std::locale creates a copy of the global C++ locale.
So to get the name of the current locale:
std::cout << std::locale().name() << '\n';

How to print subscripts/superscripts on the screen in C++?

Is it possible to print subscripts/superscripts ?
for example like that : x²
what are functions allow to do that ?
This depends entirely on the environment you're running in. For a GUI system (Windows, Mac, Qt, etc.) you would need to consult the API documentation. For a text mode system, the best you could do is use specific characters in your current encoding. For instance, unicode has certain code points that are super- or sub-scripts of other characters.
If you're using a GUI, you can change the size and orientation of the font.
There are also superscript and subscript characters available in Unicode that could be used.
You can print the appropriate Unicode symbol, to cout or wcout depending on locale:
#include <iostream>
int main()
{
std::cout << "x\u00b2" << std::endl;
}
or
#include <iostream>
#include <locale>
int main()
{
std::locale::global(std::locale("de_DE.UTF8"));
std::wcout << L"x\u00b2" << std::endl;
}