How to simulate ctrl+up in Mac OSX? - cocoa

I'm trying to simulate keyboard input Ctrl + Up to open the mission control, and referenced the code here:
https://stackoverflow.com/a/10745616/8556692
#import <Cocoa/Cocoa.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSLog(#"Open Mission Control");
CGEventSourceRef src =
CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
CGEventRef ctrld = CGEventCreateKeyboardEvent(src, 0x3B, true);
CGEventRef ctrlu = CGEventCreateKeyboardEvent(src, 0x3B, false);
CGEventRef upd = CGEventCreateKeyboardEvent(src, 0x7E, true);
CGEventRef upu = CGEventCreateKeyboardEvent(src, 0x7E, false);
CGEventSetFlags(upd, kCGEventFlagMaskControl);
CGEventSetFlags(upu, kCGEventFlagMaskControl);
CGEventTapLocation loc = kCGHIDEventTap; // kCGSessionEventTap also works
CGEventPost(loc, ctrld);
CGEventPost(loc, upd);
usleep(20000);
CGEventPost(loc, upu);
CGEventPost(loc, ctrlu);
CFRelease(ctrld);
CFRelease(ctrlu);
CFRelease(upd);
CFRelease(upu);
CFRelease(src);
}
NSLog(#"Done");
return 0;//NSApplicationMain(argc, argv);
}
But failed.
I tried to use this piece of code to simulate Cmd+Space (0x38 + 0x31 + Command Mask), it succeeded once, I think must be something wrong in my code...

I also ran into this problem. All flags (kCGEventFlagMaskCommand, kCGEventFlagMaskShift) except kCGEventFlagMaskControl worked. I added kCGEventFlagMaskSecondaryFn as written here Simulated key command not working since OS upgrade and now works.
CGEventSetFlags(upd, kCGEventFlagMaskControl | kCGEventFlagMaskSecondaryFn);
CGEventSetFlags(upu, kCGEventFlagMaskControl | kCGEventFlagMaskSecondaryFn);

Ahhh, I already got it, open mission control is not that complex, just std::system("open /System/Applications/Mission\\ Control.app"); is enough.
But still hard to understand why ctrl+up why not work

Related

Failed to load keyboard layout DLL for layout A0000409: C:\WINDOWS\system32\kbdPrlUS.dll

My ultimate goal is to compile and build a GTK application for Windows using only the C programming language
I'm using a Macbook Pro with the M1 chip. So instead of developing on Mac and cross compiling for windows, I decided to try and develop on Windows for windows.
I'm using parallels to run a Windows 10 virtual machine and after a lot of trial and error I was finally able to compile and execute a GTK program using msys2.
There is just one problem: No keyboard functionality in the GTK application. With the error message in the command prompt: "Failed to load keyboard layout DLL for layout A0000409: C:\WINDOWS\system32\KbdPrlUS.dll"
I solved my previous DLL issue by adding a path to the system variables. How might I approach addressing this keyboard layout DLL issue? The file definitely already exists at that location.
EDIT Here is the code that compiles (and works) but doesn't register and letter keypress from the keyboard. The same code works on Mac OS just fine.
#include <gtk/gtk.h>
static GtkTextBuffer *tb = NULL;
static GtkTextBuffer *tb2 = NULL;
static void
quit_activated(GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GApplication *app = G_APPLICATION (user_data);
g_application_quit (app);
}
static void
click1_cb (GtkButton *btn,
gpointer user_data)
{
GtkTextIter start, end;
gtk_text_buffer_get_bounds(tb, &start, &end);
const GtkTextIter* start2 = &start;
const GtkTextIter* end2 = &end;
char* text = gtk_text_buffer_get_text(tb,start2,end2,false);
gtk_text_buffer_set_text (tb2, text, -1);
}
static void
app_activate (GApplication *app,
gpointer user_data)
{
GtkWidget *win;
GtkWidget *tv;
GtkWidget *tv2;
GtkWidget *box;
GtkWidget *btn;
GtkWidget *btn2;
gchar *text;
text =
"Input some text "
"As many lines as you want\n"
"One day, he went into a mountain and found a shining bamboo. "
"\"What a mysterious bamboo it is!,\" he said. "
"He cut it, then there was a small cute baby girl in it. "
"The girl was shining faintly. "
"He thought this baby girl is a gift from Heaven and took her home.\n"
"His wife was surprized at his tale. "
"They were very happy because they had no children. "
;
win = gtk_application_window_new (GTK_APPLICATION (app));
gtk_window_set_title (GTK_WINDOW (win), "Taketori");
gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
gtk_window_set_child (GTK_WINDOW (win), box);
btn = gtk_button_new_with_label ("Execute.");
g_signal_connect (btn, "clicked", G_CALLBACK (click1_cb), NULL);
tv = gtk_text_view_new ();
tv2 = gtk_text_view_new ();
tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
tb2 = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv2));
gtk_text_buffer_set_text (tb2, "", -1);
gtk_text_buffer_set_text (tb, text, -1);
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv2), GTK_WRAP_WORD_CHAR);
gtk_box_append (GTK_BOX (box),tv);
gtk_box_append (GTK_BOX (box), tv2);
gtk_box_append (GTK_BOX (box), btn);
/*
GSimpleAction *act_quit = g_simple_action_new ("quit", NULL);
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION(act_quit));
g_signal_connect (act_quit,"activate",G_CALLBACK (quit_activated),app);
GMenu *menubar = g_menu_new();
GMenuItem *menu_item_menu = g_menu_item_new ("Menu",NULL);
GMenu *menu = g_menu_new();
GMenuItem *menu_item_quit = g_menu_item_new ("Quit","app.quit");
g_menu_append_item (menu, menu_item_quit);
g_object_unref (menu_item_quit);
g_menu_set_submenu (menu_item_menu,G_MENU_MODEL(menu));
g_menu_append_item (menubar,menu_item_menu);
g_object_unref(menu_item_menu);*/
//gtk_application_set_menubar (GTK_APPLICATION (app), G_MENU_MODEL (menubar));
//gtk_application_window_set_show_menubar (GTK_APPLICATION_WINDOW (win), TRUE);
gtk_widget_show (win);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int stat;
app = gtk_application_new ("com.gitbut.fff", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
stat = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;
}

How to uniquely identify a redirected by EasyPrint printer on an RDP session in Delphi (or via Windows API)?

I like to uniquely identify a redirected by EasyPrint printer on an RDP session in Delphi. Each time a user connects to the RDP session, the name of the printer change, e.g.: "HPLJP1606 (redirected 6)". The last number (6) is always changing to ensure the printer name is unique across the server. In my program, I like to save some printer related parameters that are dependent to the printer model. I was expecting to find something like a GUID to identify the printer somewhere a bit like a MAC address. It should allow my program to ensure it's the same printer than previously selected.
Me and my colleagues looked into this solution:
How can I uniquely identify a print queue on Windows even if the queue is renamed?
This wouldn't work because the GUID is different for each session.
We also tried some system workaround to rename the printer but it's not easy to generalize.
Is there a way to identify the underlying EasyPrint printer without using the printer name in Delphi or via Windows API?
I use Delphi 10.2
Thanks in advance,
I do not use delphi but this should help you. What you need to use are the following functions from setup class.
SetupDiGetClassDevs
SetupDiEnumDeviceInfo
SetupDiGetDeviceRegistryProperty
Hardware Class IDs
Here is a crude sample Cpp code that I wrote. No matter if the printer is local/network/redirected rdp printer, the hardware Id will always be same even if the name is different.
#include <Windows.h>
#include <stdio.h>
#include <SetupAPI.h>
#pragma comment(lib, "setupapi.lib")
void PrintPrinterIds(REFGUID ClassGuid)
{
HDEVINFO hDevInfo = SetupDiGetClassDevs(&ClassGuid, NULL, NULL, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
{
wprintf(L"Cannot get devices : %d\n", GetLastError());
return;
}
int idx = 0;
DWORD errorVal = ERROR_SUCCESS;
while (true)
{
SP_DEVINFO_DATA devInfoData = {};
WCHAR regProp[512];
devInfoData.cbSize = sizeof(devInfoData);
if (!SetupDiEnumDeviceInfo(hDevInfo, idx, &devInfoData))
{
errorVal = GetLastError();
break;
}
if (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&devInfoData,
SPDRP_FRIENDLYNAME,
NULL,
(PBYTE)regProp,
sizeof(regProp),
NULL))
{
errorVal = GetLastError();
break;
}
wprintf(L"Friendly name = %s\n", regProp);
if (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&devInfoData,
SPDRP_HARDWAREID,
NULL,
(PBYTE)regProp,
sizeof(regProp),
NULL))
{
errorVal = GetLastError();
break;
}
// hardwareId is reg_multi_sz
// Print all of the hardware ids for this device
PWCHAR pId = regProp;
do
{
wprintf(L"HardwareId = %s\n", pId);
pId += wcslen(pId) + 1;
} while (pId[0] != 0);
// Point to next device
idx++;
}
if (errorVal != ERROR_NO_MORE_ITEMS)
{
printf("Error : %d\n", errorVal);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
int main()
{
// {4d36e979-e325-11ce-bfc1-08002be10318}
static const GUID PrinterClass =
{ 0x4d36e979, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
PrintPrinterIds(PrinterClass);
// L"{1ed2bbf9-11f0-4084-b21f-ad83a8e6dcdc}"
static const GUID PrinterQueue =
{ 0x1ed2bbf9, 0x11f0, 0x4084, { 0xb2, 0x1f, 0xad, 0x83, 0xa8, 0xe6, 0xdc, 0xdc } };
PrintPrinterIds(PrinterQueue);
}

How to detect IPv4 address change on macOS using SystemConfiguration framework

I am trying to use the SystemConfiguration on mac OS to get a notification when a new network interface appears on the mac and a new IP address is assigned for it.
I set it up to watch for the system configuration key State:/Network/Interface and it works that I get a notification whenever a new network interface appears or disappears.
However I would like to get a notification whenever the IPv4 address is assigned on the new network interface (e.g. by DHCP). I know that the key State:/Network/Interface/en0/IPv4 is holding the IPv4 address for the en0 interface. But using regular expressions as depicted in the man page for all IPv4 addresses State:/Network/Interface/.*/IPv4 does not work for the new interface.
I have put together a small minimal code example on github, however one can also use the scutil command line tool.
Link to demo repository
main.c
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
/* Callback used if a configuration change on monitored keys was detected.
*/
void dynamicStoreCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void* __nullable info) {
CFIndex count = CFArrayGetCount(changedKeys);
for (CFIndex i=0; i<count; i++) {
NSLog(#"Key \"%#\" was changed", CFArrayGetValueAtIndex(changedKeys, i));
}
}
int main(int argc, const char * argv[]) {
NSArray *SCMonitoringInterfaceKeys = #[#"State:/Network/Interface.*"];
#autoreleasepool {
SCDynamicStoreRef dsr = SCDynamicStoreCreate(NULL, CFSTR("network_interface_detector"), &dynamicStoreCallback, NULL);
SCDynamicStoreSetNotificationKeys(dsr, CFBridgingRetain(SCMonitoringInterfaceKeys), NULL);
CFRunLoopAddSource(CFRunLoopGetCurrent(), SCDynamicStoreCreateRunLoopSource(NULL, dsr, 0), kCFRunLoopDefaultMode);
NSLog(#"Starting RunLoop...");
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
}
return 0;
}
With the help of some developer colleagues I found out what went wrong. The signature for the SCDynamicStoreSetNotificationKeys function is as follows:
Boolean SCDynamicStoreSetNotificationKeys (SCDynamicStoreRef store,
CFArrayRef __nullable keys,
CFArrayRef __nullable patterns
)
Meaning that I have to set the pattern separately from the keys which act as the root of the tree under which the pattern matching will occur. Here is the modified version of my main.m:
int main(int argc, const char * argv[]) {
NSArray *SCMonitoringInterfaceKeys = #[#"State:/Network/Interface"];
NSArray *patterns = #[#"en\\d*/IPv4"];
#autoreleasepool {
SCDynamicStoreRef dsr = SCDynamicStoreCreate(NULL, CFSTR("network_interface_detector"), &dynamicStoreCallback, NULL);
SCDynamicStoreSetNotificationKeys(dsr, CFBridgingRetain(SCMonitoringInterfaceKeys), CFBridgingRetain(patterns));
CFRunLoopAddSource(CFRunLoopGetCurrent(), SCDynamicStoreCreateRunLoopSource(NULL, dsr, 0), kCFRunLoopDefaultMode);
NSLog(#"Starting RunLoop...");
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
}
return 0;
}
I have included the solution into the solved branch of the repo.

Programmatically turn airplane mode on or off Windows

I am writing an app where I need to turn airplane mode on or off on windows. I have seen this question, but the answers only get the status, or say you cannot do such a thing for Metro apps. I am not making a modern/metro app, so I don't need to worry about application sandboxing.
Is there an api to turn Airplane mode on/off, and how should I use it?
EDIT: In my use case, I know I can control it, and the user is ok with that.
Also, I found this msdn question with the following excerpt:
Windows 8(build 8250), I can turn on / off airplane mode in Metro Style Network Setting UI.
How to do this programmatically?
Microsoft defined HID Usage code for Wireless Radio Button (Usage: 0xC6).
Question: Is there some virtual key code for Wireless Radio Button? If so, Application can send this keycode by Keybd_event.
WLANAPI.dll export the API WlanStoreRadioStateOnEnteringAirPlaneMode , but there are no any document for this API.
Question: Can you provide detail information? Is it used to control Air Plane Mode, How to call this API?
So apparently (to give a summery of the answer), one can check the state of Airplane mode using the MobileBroadbandRadioState enum.
The HID route may be a possibility docs. Apparently it is a question of whether one can send the code 0xc6 to kbd_event.
EDIT2: Apparently there is a window called Network Flyout and I was thinking of enumerating the children to find the switch, but I haven't had much success. I'll have to use Spy++ some more to find out.
All of the following I discovered myself via reverse engineering.
The internal API used internally by windows to get/set Airplane mode makes use of COM calls to "RMsvc" service (which is located in "RMApi.dll"). That service is exporting a factory and interface which contains functions to get/set flight mode:
#include <Windows.h>
#include <assert.h>
#include <stdio.h>
static GUID const CLSID_RadioManagementAPI = { 0x581333f6, 0x28db, 0x41be, { 0xbc, 0x7a, 0xff, 0x20, 0x1f, 0x12, 0xf3, 0xf6 } };
static GUID const CID_IRadioManager = { 0xdb3afbfb, 0x08e6, 0x46c6, { 0xaa, 0x70, 0xbf, 0x9a, 0x34, 0xc3, 0x0a, 0xb7 } };
typedef IUnknown IUIRadioInstanceCollection; /* Didn't bother rev-engineering this one... */
typedef DWORD _RADIO_CHANGE_REASON;
typedef struct IRadioManagerVtbl IRadioManagerVtbl;
typedef struct IRadioManager {
IRadioManagerVtbl *lpVtbl;
} IRadioManager;
struct IRadioManagerVtbl {
/* IUnknown */
HRESULT (STDMETHODCALLTYPE *QueryInterface)(IRadioManager *This, GUID const *riid, LPVOID *ppvObj);
ULONG (STDMETHODCALLTYPE *AddRef)(IRadioManager *This);
ULONG (STDMETHODCALLTYPE *Release)(IRadioManager *This);
/* IRadioManager (aka. `CUIRadioManager') */
HRESULT (STDMETHODCALLTYPE *IsRMSupported)(IRadioManager *This, DWORD *pdwState);
HRESULT (STDMETHODCALLTYPE *GetUIRadioInstances)(IRadioManager *This, IUIRadioInstanceCollection **param_1);
HRESULT (STDMETHODCALLTYPE *GetSystemRadioState)(IRadioManager *This, int *pbEnabled, int *param_2, _RADIO_CHANGE_REASON *param_3);
HRESULT (STDMETHODCALLTYPE *SetSystemRadioState)(IRadioManager *This, int bEnabled);
HRESULT (STDMETHODCALLTYPE *Refresh)(IRadioManager *This);
HRESULT (STDMETHODCALLTYPE *OnHardwareSliderChange)(IRadioManager *This, int param_1, int param_2);
};
int main() {
HRESULT hr;
IRadioManager *irm;
hr = CoInitialize(NULL);
assert(!FAILED(hr));
irm = NULL;
hr = CoCreateInstance(&CLSID_RadioManagementAPI, NULL, 4,
&CID_IRadioManager, (void **)&irm);
assert(!FAILED(hr) && irm);
int bOldMode, b;
_RADIO_CHANGE_REASON c;
hr = irm->lpVtbl->GetSystemRadioState(irm, &bOldMode, &b, &c);
assert(!FAILED(hr));
printf("Old flight-mode state was: %s\n", bOldMode == 0 ? "on" : "off");
/* Set flight mode to the opposite state. */
hr = irm->lpVtbl->SetSystemRadioState(irm, bOldMode == 0 ? 1 : 0);
assert(!FAILED(hr));
irm->lpVtbl->Release(irm);
CoUninitialize();
return 0;
}

OSX Quartz Event Taps: event types and how to edit events

Here's my code:
#import <ApplicationServices/ApplicationServices.h>
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
printf("%u\n", (uint32_t)type);
return event;
}
int main (int argc, const char * argv[]) {
CFMachPortRef eventTap;
CFRunLoopSourceRef runLoopSource;
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, myCGEventCallback, NULL);
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
return 0;
}
First.. what if I wanted to edit the event? For example I listen for the keyDown event and if it's an "a" I turn it in a "b", or edit the mouse position in real time, or for example simply capture an event and make it have no effect (disabling a particular key for example..)
Second.. CGEventType is defined with an enum that lists only a few types.. for example when I hit CMD I get a 12, but that doesn't match the value specified in the enum.. what I'm I missing??
To modify an event, there are various CGEventSet... functions. To kill the event, I think your tap function can just return NULL.
The enumeration for event types includes kCGEventFlagsChanged = NX_FLAGSCHANGED. If you look up IOKit/hidsystem/IOLLEvent.h, it defines NX_FLAGSCHANGED to be 12.

Resources