macOS: Override Modifier Key with CGEventTap - c

So I recently spilled some water on my macbook pro keyboard, and my left command and option keys no longer function. Apple wants me to mail it in for repairs, which I don't have time for right now. So I thought I'd override the right command key to serve as left control seeing as the left command key still works.
I adapted the following from a keylogger gist I found:
#include <stdio.h>
#import <Carbon/Carbon.h>
#import <ApplicationServices/ApplicationServices.h>
CGEventRef loggerCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* context)
{
if (type == kCGEventFlagsChanged && CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode) == 54 /* right cmd key */) {
printf(
"TEST: %d %llu\n",
type,
CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)
);
CGKeyCode virtualKey = 0x3B; // kVK_Control (left control);
CGEventRef override = CGEventCreateCopy(event);
CGEventSetIntegerValueField(override, kCGKeyboardEventKeycode, virtualKey);
return override;
}
return event;
}
int main(int argc, const char * argv[])
{
CFMachPortRef tap;
if ((tap = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
0, kCGEventMaskForAllEvents,
loggerCallback, NULL)) == NULL) {
printf("Failed ot create event tap\n");
exit(1);
}
CFRunLoopSourceRef runLoopSource;
if ((runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)) == NULL) {
printf("Failed to create run loop source\n");
exit(1);
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(tap, true);
CFRunLoopRun();
return 0;
}
Now the event tap works correctly, and it does intercept keyboard events ( I can see TEST 12 54 printed to the console), but the key is still behaving as command and not control. According to the documentation for CGEventTapCallback, the callback may return:
A newly-constructed event. After the new event has been passed back to the event system, the new event will be released along with the original event.
Passing in kCGHeadInsertEventTap as the tap location should ensure my event tap is inserted at the head of the handler list. Am I doing something wrong here or is it just not possible to modify events like this?

#Willeke was correct in their comment. Although I was correctly overriding the event, what I really needed to do was use the keydown/keyup events to keep track of when the right command key is pressed. I could then use that flag to intercept other keypress events, remove the command modifier, and insert the control modifier flag use bitwise operators. However, the simple solution here to this problem comes from the documentation link they provided:
hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x7000000E7,"HIDKeyboardModifierMappingDst":0x7000000E0}]}'

Related

How to make SDL_Keypress detect new Keypress during keypress-loop?

I'm writing Conways game of life in C with SDL. The game logic and everything works fine but I want to have it when you press p for example that the game automatically updates until p is pressed again and the loop stops. Somehow it only repeats once and doesn't even register the second time p is pressed.
else if (e.key.keysym.sym == SDLK_p){
bool stop = false;
while (!stop){
nextEpoch();
updateGame(window, renderer, r);
msleep(500);
if (e.type == SDL_KEYDOWN){
if (e.key.keysym.sym == SDLK_p){
stop = true;
printf("s\n");
}
}
}
}
It doesn't register that p is pressed when it in the while-loop.
Here's the full code: https://gist.github.com/PhilippRados/2df8760cc55822c2eac62addafb24403
As already pointed out by someone else in the comments section, you are not updating e in the inner loop. If you want to update e with a new event, you must call SDL_PollEvent( &e ) again to fill it with a new event.
In your linked code, you seem to be attempting to implement a new state of your program outside the main event loop, which represents the running state of the program, whereas the main event loop represents the paused state of the program. That way, you effectively have two separate event loops, one for each state of the program. While it is possible to make your program work this way, I don't recommend it.
For example, the way you have designed your program, your program won't respond to SDL_QUIT events in the running state. It will only do so in the paused state.
Therefore, it would make more sense to have a single event loop for both the running and the paused states of your program.
I don't recommend that you call usleep or SDL_Delay for waiting until it is time to render the next frame, as your program will not be responding to user input during this time. Especially since you have a very low frame rate of 2 frames per second, this means that it will take up to half a second for your program to respond to user input (for example if the user resizes the window or attempts to close it). Instead, I recommend that you set up a timer using SDL_AddTimer. You can program the timer callback function to give you a SDL_USEREVENT event twice per second. That way, when you receive this event, you will know that it is time to update the game and render the next frame. While waiting for this event, your program will still be able to respond to other events.
Note that in order to use SDL timers, you must initialize the corresponding subsystem using the SDL_INIT_TIMER flag when calling SDL_Init. Strangely, your linked code does not seem to call SDL_Init at all, so I am surprised that your code works at all. According to the documentation, you should call SDL_Init like this:
SDL_Init( SDL_INIT_TIMER | SDL_INIT_VIDEO );
Also, calling SDL_PollEvent in a loop seems like a big waste of CPU resources, as your CPU usage will likely be 100% although you are effectively doing nothing most of the time. I recommend that you call SDL_WaitEvent instead, so that the thread will sleep until it receives a new event to respond to.
Another thing worth noting is that when handling an SDL_MOUSEBUTTONDOWN event, it does not seem appropriate to use the result of SDL_GetMouseState to determine the coordinates of the mouse click, as that function will return the current mouse coordinates and not the coordinates at the time of the click. Therefore, it would be more appropriate to read these coordinates from the SDL_MouseButtonEvent structure.
Here is an example of how you could rewrite your event loop to use SDL_WaitEvent instead of SDL_PollEvent and to support both a running and a paused state in the main event loop.
Uint32 my_callbackfunc( Uint32 interval, void *param )
{
SDL_Event e;
e.user.type = SDL_USEREVENT;
e.user.code = 0;
e.user.data1 = NULL;
e.user.data2 = NULL;
SDL_PushEvent( &e );
return interval;
}
int main (int argc, char** argv)
{
[...]
//set timer to trigger twice per second
SDL_TimerID timer = SDL_AddTimer( 500, my_callbackfunc, NULL );
if ( timer == 0 ) {
//TODO: handle error
return EXIT_FAILURE;
}
//start game in a paused state
bool paused = true;
while ( SDL_WaitEvent( &e ) ) {
switch ( e.type ) {
case SDL_QUIT:
goto quit_game;
case SDL_WINDOWEVENT:
//rerender in case of window state change
updateGame( window, renderer, r );
break;
case SDL_USEREVENT:
if ( !paused ) {
nextEpoch();
updateGame(window, renderer, r);
}
break;
case SDL_MOUSEBUTTONDOWN:
mouseX = getNearestMultiple( e.button.x ) / RECT_SIZE;
mouseY = getNearestMultiple( e.button.y) / RECT_SIZE;
if ( Field[mouseX][mouseY] ) {
//Deactivate cell
Field[mouseX][mouseY] = false;
updateGame(window,renderer,r);
}
else {
//activate cell at position x,y
Field[mouseX][mouseY] = true;
updateGame(window,renderer,r);
}
break;
case SDL_KEYDOWN:
switch ( e.key.keysym.sym ) {
case SDLK_SPACE:
if ( paused ) {
nextEpoch();
updateGame(window, renderer, r);
}
break;
case SDLK_r:
memset(Field,0,sizeof(Field[0][0]) * WIDTH * HEIGHT);
memset(nextState,0,sizeof(nextState[0][0]) * WIDTH * HEIGHT);
updateGame(window,renderer, r);
break;
case SDLK_p:
paused = !paused;
}
}
}
quit_game:
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}

xlib - print event name

So I have a standard window created with xlib that handles events:
while (keep_running){
XNextEvent (display, &event);
printf("event\n");
}
Now it doesn't seem to be calling the expose event, so I'm not able to draw in the window. I can see by the print statement that there are some events being fired, and I'd like to know what events they are.
So basically my question is, how can I get the event name to print it?
I'm still learning C, so any help is appriciated!
so I don't totally agree with their design decision, but it was probably made 30 years ago, so now isn't the time for monday morning quarterbacking...
the type is a crazy union:
typedef union _XEvent {
int type; /* must not be changed */
XAnyEvent xany;
XKeyEvent xkey;
XButtonEvent xbutton;
XMotionEvent xmotion;
XCrossingEvent xcrossing;
XFocusChangeEvent xfocus;
XExposeEvent xexpose;
XGraphicsExposeEvent xgraphicsexpose;
XNoExposeEvent xnoexpose;
XVisibilityEvent xvisibility;
XCreateWindowEvent xcreatewindow;
XDestroyWindowEvent xdestroywindow;
XUnmapEvent xunmap;
XMapEvent xmap;
XMapRequestEvent xmaprequest;
XReparentEvent xreparent;
XConfigureEvent xconfigure;
XGravityEvent xgravity;
XResizeRequestEvent xresizerequest;
XConfigureRequestEvent xconfigurerequest;
XCirculateEvent xcirculate;
XCirculateRequestEvent xcirculaterequest;
XPropertyEvent xproperty;
XSelectionClearEvent xselectionclear;
XSelectionRequestEvent xselectionrequest;
XSelectionEvent xselection;
XColormapEvent xcolormap;
XClientMessageEvent xclient;
XMappingEvent xmapping;
XErrorEvent xerror;
XKeymapEvent xkeymap;
long pad[24];
} Event;
so you must first use the type to determine which event is being used:
if(event.type == KeyPress)
{
printf("keypress\n");
// now you know the type you can use the specific fields from `XKeyEvent xkey`...
}
or you could just log the type
printf("event type = (%d)\n",event.type);
the union works because each of the other possible elements also has type as the first element, so they all line up on the same address...

Need for XEventsQueued(display, QueuedAfterReading) in XCB

I am migrating some code of CYBOI from Xlib to XCB.
CYBOI uses a couple of threads for different communication channels like:
serial_port, terminal, socket, x_window_system.
However, it uses these threads only for signal/event/data detection;
the actual receiving and sending is done in the main thread,
in order to avoid any multi-threading conflicts of address space.
For the x_window_system channel, I previously detected events in a thread:
int n = XEventsQueued(display, QueuedAfterReading);
Upon detection of an event, an "interrupt flag" was set.
Afterwards, the main thread was reading the actual event using:
XNextEvent(display, &event);
When no more events were available, the main thread stopped receiving events
and the x_window_system channel thread started listening with XEventsQueued again.
Now, I am migrating the code to X C Binding (XCB).
There is a blocking function "xcb_wait_for_event" which is fine for reading an event.
What I miss is some function "peeking ahead" if there are events pending,
WITHOUT actually returning/removing the event from the queue.
I was reading the web for a couple of hours now, but am not able to find such a function.
The "xcb_poll_for_event" does not help. Blocking is fine for me,
since my event detection runs in its own thread.
The "xcb_request_check" as third input function does not seem to be what I want.
Could somebody help me out?
Thanks,
Christian
Are you looking for xcb_poll_for_queued_event(xcb_connection_t *c) which returns the next event without reading from the connection?
First, thanks to Julien for his reply.
I have studied the XCB 1.9 sources and found out that the
"xcb_poll_for_queued_event" function is not what I need.
The functions "xcb_poll_for_event" and "xcb_poll_for_queued_event"
both call "poll_for_next_event".
The functions "poll_for_next_event" and "xcb_wait_for_event"
both call "get_event".
If "get_event" finds an event, it changes the internal
linked list to point to the next event. However, I would
prefer NOT to change the event queue AT ALL, independent
from whether or not events are available.
I therefore propose to add a function like the following to XCB:
void* NULL_POINTER = (void*) 0;
int xcb_test_for_event(xcb_connection_t* c) {
int r = 0;
if (c != NULL_POINTER) {
struct _xcb_in in = c->in;
struct event_list* l = in.events;
if (l != NULL_POINTER) {
xcb_generic_event_t* e = l->event;
if (e != NULL_POINTER) {
r = 1;
}
}
}
return r;
}
This would allow me to write an endless loop like:
while (!xcb_test_for_event(connection)) {
sleep(t);
}
This is comparable to the old Xlib function:
int n = XEventsQueued(d, QueuedAfterReading);
which just checked the number of events in the event queue.
The "XEventsQueued" function always returns immediately WITHOUT
input/output, if there are events already in the queue.
Thanks
Christian

Open Windows Explorer Shell context menu

How do I enumerate the shell context menu item using Windows API? I need to do it in pure C.
It is a little unclear to me if you want to show a menu or just enumerate the items, this does the latter (Excluding submenus)
HRESULT GetContextMenuForFSItem(PCTSTR path,IContextMenu**ppCM)
{
PIDLIST_ABSOLUTE pidlAbs;
HRESULT hr = SHParseDisplayName(path,0,&pidlAbs,0,0);
if (!hr)
{
IShellFolder*pSF;
PCUITEMID_CHILD pidlLast;
hr = SHBindToParent(pidlAbs,&IID_IShellFolder,(void**)&pSF,&pidlLast);
if (!hr)
{
hr = pSF->lpVtbl->GetUIObjectOf(pSF,0,1,&pidlLast,&IID_IContextMenu,0,(void**)ppCM);
pSF->lpVtbl->Release(pSF);
}
ILFree(pidlAbs);
}
return hr;
}
int main()
{
CoInitialize(0);
WCHAR buf[MAX_PATH];
GetWindowsDirectory(buf,MAX_PATH); /* Arbitrary filesystem item */
IContextMenu*pCM;
HRESULT hr = GetContextMenuForFSItem(buf,&pCM);
if (!hr)
{
HMENU hMenu = CreatePopupMenu();
hr = pCM->lpVtbl->QueryContextMenu(pCM,hMenu,0,1,0x7fff,0);
if (hr > 0)
{
UINT c=GetMenuItemCount(hMenu), i=0;
for (; i<c; ++i)
{
GetMenuString(hMenu,i,buf,MAX_PATH,MF_BYPOSITION);
if (GetMenuState(hMenu,i,MF_BYPOSITION)&MF_SEPARATOR) lstrcpy(buf,_T("--separator--"));
printf("%.2u=%ws\n",i,buf);
/*
Call IContextMenu::GetCommandString to get the verb
or IContextMenu::InvokeCommand to execute
*/
}
}
pCM->lpVtbl->Release(pCM);
DestroyMenu(hMenu);
}
CoUninitialize();
return 0;
}
On my system this prints:
00=&Open
01=--separator--
02=S&hare with
03=Restore previous &versions
04=&Include in library
05=--separator--
06=Se&nd to
07=--separator--
08=Cu&t
09=&Copy
10=--separator--
11=Create &shortcut
12=&Delete
13=--separator--
14=P&roperties
Using COM in C is not fun, switch to C++ if you can...
You need to do exactly what Explorer does: for the item in question (file, folder, other shell namespace location) you identify the list of shell extensions. These are COM classes and they implement IContextMenu interface. For every shell extension applicable, you can provide your own menu and request that such extension (handler) populates the menu with its additional items (IContextMenu::QueryContextMenu).
Later on you are free to decide when, where and if you are going to pop this menu up. Should there a need in handle one of those additional handler's commands, you are responsible to fowrward the command to the handler via IContextMenu::InvokeCommand. If you for some reason prefer to automate certain command and invoke it without popping up the menu, you can do it as well.
Links you might be interested in:
How to access Windows shell context menu items?
Creating Shortcut Menu Handlers
Raymond Chen wrote an eleven part series explaining how to do this. It's really not straightforward.

ncurses write to window not displayed

I've got one function do_refresh which should draw some character in a window like this:
void do_refresh(WINDOW *w_game, int *xPos, int *yPos, char vector[], snake *snake){
mvwaddch(w_game, (*yPos), (*xPos), snake->headsym);// mv to new pos and place char
wrefresh(w_game);
}
The window w_game has also a panel pendant which lies on top of all other panels.
Before that function gets called, I let the user do non blocking input with getch() and timeout(0):
fflush(stdin);
key = getch();
if(key != ERR){ ...
only the first time I call do_refresh, the char gets drawn to the window, later nothing changes though xPos & yPos as well as all other parameters to mvwaddch are valid and change over the time.
Doing a redrawwin on the window causes a segfault, using wgetch(w_game) instead of getch() returns no input.
I would be very grateful if someone could at least link to a decent documentation what has to be considered when using wgetch instead and what it does different.
UPDATE
I found the solution to the problem, The function which sets up the panel stuff modifies the address of the windows!, you have to return the (new) destination of the pointer to main and reset it there like this:
...setup_panels(...){
return w_game; // my window
}
int main(...){
WINDOW *w_game;
[...]
w_game = setup_panels(...);
}

Resources