Reputation: 8928
I'm attempting to write a wchar_t
character (wide character) to file. Currently it writes the hex code to file, and not the character.
Here's the part in the application where it's failing
if(capslockKey || shiftKey)
{
// When debugging and I press 's' this becomes 'S'. It's visible in the deugging locals window.
wchar_t upper = towupper((wchar_t)*buffer);
if(upper != *buffer)
// "Testing " gets written to file, but upper gets written as a hex value
logFile << L"Testing " << upper << logFile.flush();
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
I've commented the code. When debugging upper
contains the correct character. If a lowercase s
is pressed, it becomes S
if shift or capslock is pressed. This works fine.
But, when writing to file upper
gets written as a hex value. The string Testing
gets written as normal. Outputting to stdout using std::wout
prints the characters just fine.
How can I save the actual character to file, and not the hex value?
Thanks to Remy, I ended up with the following which works fine:
/*
* Is the keypress an alpha key? This limits everything except a-z and A-Z
*/
if((p->vkCode > 64) && (p->vkCode < 91) || (p->vkCode > 96) && (p->vkCode < 123))
{
/*
* Are we dealing with capital letters?
*/
if(capslockKey || shiftKey)
{
wchar_t upper = towupper((wchar_t)*buffer);
if(upper != *buffer)
logFile << (wchar_t)upper << std::flush;
}
else
{
logFile << buffer << std::flush;
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
... Although WM_CHAR
might be a better option for my needs. Saves having to deal with issues such as whether or not shift is pressed. Or converting VK_RETURN
to \n
.
Above is pointless (lowercase to uppercase part). GetKeyboardState
and toUnicodeEx
does it perfectly with much less hassle.
BYTE keyState[256] = {0};
bool keyStateResult = GetKeyboardState(keyState);
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
wchar_t buffer[5];
int toUnicodeResult = ToUnicodeEx(
p->vkCode,
p->scanCode,
keyState,
buffer,
_countof(buffer),
0,
NULL
);
Upvotes: 0
Views: 2595
Reputation: 595339
On this line:
logFile << L"Testing " << upper << logFile.flush();
You are not passing flush()
itself to operator<<
. You are actually calling flush()
first and then passing its return value (a basic_ostream&
reference) to operator<<
, which is causing the hex output you see.
To properly flush the stream using operator<<
, you need to use the std::flush
stream manipulator instead, which will (indirectly) call logFile.flush()
for you without sending its returned reference to the stream output:
logFile << L"Testing " << upper << std::flush;
Upvotes: 4
Reputation: 145204
Wide streams translate to and from a narrow character external encoding. To directly save wide text (UTF-16 encoded in Windows) you can use a narrow stream opened in binary mode. Or you can use Microsoft extension _setmode
to set _O_U16
-something mode on the stream, but that's non-portable, and doesn't seem to work with newer versions of MinGW g++, although it did work earlier.
A good alternative is to use the standard library facilities to translate the wide text to UTF-8 encoded narrow text, and save that to a narrow stream opened in binary mode. Since this is Windows it would be a good idea to save a BOM (byte order mark) at the beginning. Conversely, in Unixland it's a good idea to not do that.
I'm unable to reproduce the hex digits effect – and you don't include code to reproduce it – but the above advice is what you need to do anyway, assuming that the wide text isn't restricted to plain ASCII.
Upvotes: 1