I'm trying to use the ToUnicode function in response to receiving a WM_KEYDOWN notification, which sounds a lot easier than it is.
Actually, ToUnicode should superfluous if one simply uses WM_CHAR, but much to my surprise this actually does not work properly at all! Having used WM_CHAR in no-common-controls-programs for ages, I've just for the first time ever typed a word with a diacritic accent1 only to realize that dead keys don't work at all!
As in, if I type for example ´e, then WM_CHAR is telling me e when it should be telling é (similar for other dead key combinations, such asâ).
ToUnicode seems like the obvious solution according to its documentation -- unwieldy as it is, its MSDN description page states that it does exactly what I need. It does take an awful lot of parameters, but those too seem straighforward.
The first parameter is simply the virtual key code (wParam), and the second one can be obtained via MapVirtualKey.
The third parameter is optional, so not actually needed (that's what "optional" means, isn't it!). Here's the first surprise: If you don't provide the key state, the function simply fails ("no key mapped") for any key you press. Which means an extra call to GetKeyboardState is needed.
That leaves us with this code:
case WM_KEYDOWN:
BYTE kb[256];
GetKeyboardState(kb);
WCHAR uc[5] = {};
switch(ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0))
{
case -1: _putws(L"dead key"); break;
case 0: _putws(L"no idea!"); break;
case 1:
case 2:
case 3:
case 4:
_putws(uc);
}
...
This outputs the proper Unicode character for every normal character (no big achievement, you already get that from WM_CHAR), but spectacularly fails for dead keys, in the exact same way (one might suspect TranslateMessage uses ToUnicode to produce WM_CHAR).
The shift and alt keys as well as altgr are all honored (so for example typing µ (altgr-m) will give me µ just fine), but the diacritic dead keys (like acute or circumflex) won't work. Which means if you were to try to type some French or Spanish words on my German-layout keyboard, you're without luck.
Is there a way to use this function properly, so it works? Or, alternatively, is there a different function that works properly for dead keys?
1Well, obviously not for the first time, but for the first time in this context.
I cannot confirm the symptoms you describe. I used Spy++ to monitor the messages received by Notepad. Then I pressed the dead key ´, followed by an e.
As you can see, the WM_CHAR message is absolutely correct with the Unicode character 233. That represents é.
<00001> 000F0C86 P WM_KEYDOWN nVirtKey:VK_OEM_6 cRepeat:1 ScanCode:0D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00002> 000F0C86 P WM_DEADCHAR chCharCode:'180' (180) cRepeat:1 ScanCode:0D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00003> 000F0C86 P WM_KEYUP nVirtKey:VK_OEM_6 cRepeat:1 ScanCode:0D fExtended:0 fAltDown:0 fRepeat:1 fUp:1
<00004> 000F0C86 P WM_KEYDOWN nVirtKey:'E' cRepeat:1 ScanCode:12 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00005> 000F0C86 P WM_CHAR chCharCode:'233' (233) cRepeat:1 ScanCode:12 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00006> 000F0C86 P WM_KEYUP nVirtKey:'E' cRepeat:1 ScanCode:12 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
So WM_CHAR is everything you need if you just want the composed input. Otherwise, you can handle WM_DEADCHAR and process the input manually.
Please read the docs about keyboard input on MSDN.
Related
I came across TOKENMATCHES in minute 31 of Introducing CloudKit and was curious, so I did a google search and found very little about it outside of another StackOverflow post.
NSPredicate(format: "ALL tokenize(%#, 'Cdl') IN allTokens", "after session")
Actually, confusing things further, that post uses different syntax than the WWDC video:
NSPredicate(format: "allTokens TOKENMATCHES[cdl] %#", "bob smith")
As I understand it, these queries return any records that have all of the tokenized string arguments within one or more text fields. The latter case would fetch a record with, say, person.name = "bob" and person.last = "smith", as well as, say, a record where person.note = "Bob likes Joseph Smith.". (Corrections welcome.)
All that said, this question isn't about the full predicate, but just that cdl (or Cdl?) parameter/modifier/whateverthehellitis.
TL;DR—What's cdl mean, and are there other values that can go in that "slot" of the format string?
<rant> Why isn't the predicate syntax documentation comprehensive? It's as if Apple's managers are scared of the mysterious, ancient power that is NSPredicate; none dare assign the technical writer and engineer needed to make this otherwise simple class accessible to the Rest of Us™. A Google search for "nspredicate TOKENMATCHES" gives only 8 results, none of which are at apple.com. 😠 </rant>
Found it, at least!
The doc: NSComparisonPredicateOptions
typedef enum NSComparisonPredicateOptions : NSUInteger {
NSCaseInsensitivePredicateOption = 0x01, //==> [c]
NSDiacriticInsensitivePredicateOption = 0x02, //==> [d]
NSNormalizedPredicateOption = 0x04 //==> [n]
} NSComparisonPredicateOptions;
+ NSLocaleSensitivePredicateOption //==> [l]
So basically :
[c]: uppercase is the same as lowercase (ie: A == a)
[d]: char with diacritics (acute accent, cedilla, etc.) is the same as char without it (ie à == a (accent)
[l]: it's for localized specificities. The Apple sample is with "straße" and "strasse" using the German "double s" (Eszett) as an example.
I have a program where for various reasons i need to send keypress events to various windows. What I am using at the moment
XEvent event;
/* set some other stuff*/
event.type = KeyPress;
event.xkey.keycode = XKeysymToKeycode(display,XStringToKeysym(curr_key));
works for lower case letters and numbers, but I need to modify this so that it is capable of sending the enter key and upper case letters.
From the XStringToKeysym man page:
void XConvertCase(KeySym keysym, KeySym *lower_return, KeySym *upper_return);
The XConvertCase function returns the uppercase and lowercase forms of the specified Keysym, if the KeySym is subject to case conversion; otherwise, the specified KeySym is returned to both lower_return and upper_return. Support for conversion of other than Latin and Cyrillic KeySyms is implementation-dependent.
All the keysyms are in /usr/include/X11/keysymdef.h e.g. the enter key is XK_Return. The letters are there too e.g. XK_a and XK_A.
Having setup an event tap, I'm not able to identify what modifier key was pressed given a CGEvent.
CGEventFlags flagsP;
flagsP=CGEventGetFlags(event);
NSLog(#"flags: 0x%llX",flagsP);
NSLog(#"stored: 0x%llX",kCGEventFlagMaskCommand);
if (flagsP==kCGEventFlagMaskCommand) {
NSLog(#"command pressed");
}
Given the above snippet, the first NSLog returns a different value from the second NSLog. No surprise that the conditional is never triggered when the command modifier key is pressed.
I need to identify whether command, alternate, option, control or shift are pressed for a given CGEvent. First though, I need help to understand why the above isn't working.
Thanks!
These are bit masks, which will be bitwise-ORed together into the value you receive from CGEventGetFlags (or pass when creating an event yourself).
You can't test equality here because no single bit mask will be equal to a combination of multiple bit masks. You need to test equality of a single bit.
To extract a single bit mask's value from a combined bit mask, use the bitwise-AND (&) operator. Then, compare that to the single bit mask you're interested in:
BOOL commandKeyIsPressed = (flagsP & kCGEventFlagMaskCommand) == kCGEventFlagMaskCommand;
Why both?
The & expression evaluates to the same type as its operands, which is CGEventFlags in this case, which may not fit in the size of a BOOL, which is a signed char. The == expression resolves that to 1 or 0, which is all that will fit in a BOOL.
Other solutions to that problem include negating the value twice (!!) and declaring the variable as bool or _Bool rather than Boolean or BOOL. C99's _Bool type (synonymized to bool when you include stdbool.h) forces its value to be either 1 or 0, just as the == and !! solutions do.
I'm trying to use event taps to create an OS X program that will listen for Yiddish typed in transliteration and post the result in Hebrew characters. I made a very short program to test one things I'd have to do: http://pastie.org/791398
As is, the program successfully replaces every typed 'q' with 'w':
if(inputString[0] == 'q') { inputString[0] = 'w'; }
But how does one post a string of more than one character? For instance, if someone types 'sh' you'd presumably have to post a backspace (to delete the character that was posted for 's' alone) and then post the character that corresponds to 'sh'. However, this code results in only a backspace being posted:
else if(inputString[0] == 'm') { inputString[0] = '\b'; inputString[1] = 'n'; }
I apologize if these are basic questions; I have read all the documentation I could find, but I might not have understood it all. It's also possible that I'm going about this entirely the wrong way.
Ideally you should be using an input method instead of a program with event taps, most likely using Input Method Kit if you don't need to support pre-10.5. Using event taps for this purpose is inherently a bad idea because the user can change where he/she is typing with the mouse as well as the keyboard. So if the user typed a "s" in one text field followed by a "h" in another, you wouldn't be able to tell the difference.
That said, here's a direct answer to your question.
The string is length-counted, so you can't just provide the incoming length (1); the second character will be ignored. However, most applications also don't like to get more than a single character per event, so they'll just discard the remaining characters. (Terminal is a notable exception.)
So what you can do is simply post a second event with the second character in it.
else if(inputString[0] == 'm') {
inputString[0] = 'n';
CGEventKeyboardSetUnicodeString(event, 1, inputString);
CGEventPost(kCGSessionEventTap, event);
inputString[0] = '\b';
}
In the general case (simulating > 2 keypresses) you'll need to create an event for each character you want to insert. This mailing list post includes a simple example.
This is how I send a string to the first responder ( foreground application )
// 1 - Get the string length in bytes.
NSUInteger l = [string lengthOfBytesUsingEncoding:NSUTF16StringEncoding];
// 2 - Get bytes for unicode characters
UniChar *uc = malloc(l);
[string getBytes:uc maxLength:l usedLength:NULL encoding:NSUTF16StringEncoding options:0 range:NSMakeRange(0, l) remainingRange:NULL];
// 3 - create an empty tap event, and set unicode string
CGEventRef tap = CGEventCreateKeyboardEvent(NULL,0, YES);
CGEventKeyboardSetUnicodeString(tap, string.length, uc);
// 4 - Send event and tear down
CGEventPost(kCGSessionEventTap, tap);
CFRelease(tap);
free(uc);
To send a serial string character to the serial port. I would need to call WriteFile(handle, "A", strlen("A"), ...)
However, what if I want to specify and send a hex or binary number? For example, I want to send WriteFile(handle, 0x41, sizeOf(0x41), ...) ?
Is there a function that allow me to do this?
If you just want to write one byte, it still needs to be in an array.
So you would need:
int buffer[1024];
buffer[0] = 42;
WriteFile(handle, buffer, 1);
See this:
http://msdn.microsoft.com/en-us/library/aa365747(VS.85).aspx
There are many ways.
The most straight forward for you though would be WriteFile( handle, "\x41", 1 ... );
The strlen() is redundant, since you know the length.