Reputation: 2648
I have seen many post on this topic. But haven't found a clear answer anywhere.
Is there a way to toggle CAPS LOCK in Objective-C or C code? I am not looking for a solution using X11 libs. I am not bothered about the LED on/off status. But just the functionality of CAPS LOCK (changing the case of letters and printing the special characters on number keys).
Why is CGEvent not supporting this the way it does for other keys?
Upvotes: 3
Views: 1755
Reputation: 15049
The following command line program in Objective-C will toggle the current caps lock state:
#import <IOKit/IOKitLib.h> // or @import IOKit;
#import <IOKit/hid/IOHIDBase.h> // needed for kIOHIDSystemClass
int main(int argc, const char * argv[]) {
@autoreleasepool {
// Use kIOMasterPortDefault instead of kIOMainPortDefault for macOS 11.x or earlier
io_service_t ioService = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching(kIOHIDSystemClass));
io_connect_t ioConnect = 0;
IOServiceOpen(ioService, mach_task_self_, kIOHIDParamConnectType, &ioConnect);
bool state = false;
IOHIDGetModifierLockState(ioConnect, kIOHIDCapsLockState, &state);
// Toggle state
state = !state; // 1 = CapsLock on, 0 = CapsLock off
IOHIDSetModifierLockState(ioConnect, kIOHIDCapsLockState, state);
IOServiceClose(ioConnect);
}
return 0;
}
Upvotes: 3
Reputation: 140
The following method also works when you want CapsLock to toggle the current keyboard language (if you have the CapsLock key configured to do that).
CFMutableDictionaryRef mdict = IOServiceMatching(kIOHIDSystemClass);
io_service_t ios = IOServiceGetMatchingService(kIOMasterPortDefault, (CFDictionaryRef)mdict);
if (ios) {
io_connect_t ioc = 0;
IOServiceOpen(ios, mach_task_self(), kIOHIDParamConnectType, &ioc);
if (ioc) {
NXEventData event{};
IOGPoint loc{};
// press CapsLock key
UInt32 evtInfo = NX_KEYTYPE_CAPS_LOCK << 16 | NX_KEYDOWN << 8;
event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
event.compound.misc.L[0] = evtInfo;
IOHIDPostEvent(ioc, NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
// release CapsLock key
evtInfo = NX_KEYTYPE_CAPS_LOCK << 16 | NX_KEYUP << 8;
event.compound.subType = NX_SUBTYPE_AUX_CONTROL_BUTTONS;
event.compound.misc.L[0] = evtInfo;
IOHIDPostEvent(ioc, NX_SYSDEFINED, loc, &event, kNXEventDataVersion, 0, FALSE);
IOServiceClose(ioc);
}
}
Upvotes: 0
Reputation: 151
var ioConnect: io_connect_t = .init(0)
let ioService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching(kIOHIDSystemClass))
IOServiceOpen(ioService, mach_task_self_, UInt32(kIOHIDParamConnectType), &ioConnect)
var modifierLockState = false
IOHIDGetModifierLockState(ioConnect, Int32(kIOHIDCapsLockState), &modifierLockState)
modifierLockState.toggle()
IOHIDSetModifierLockState(ioConnect, Int32(kIOHIDCapsLockState), modifierLockState)
IOServiceClose(ioConnect)
Upvotes: 5
Reputation: 2648
I got this working, after a long struggle.
Invoke the method given below twice. Once for up event and another for down event. For example for simulating CAPS A, we need to do the following.
[self handleKeyEventWithCapsOn:0 andKeyDown:NO];
[self handleKeyEventWithCapsOn:0 andKeyDown:YES];
0 is the keycode for 'a'.
- (void) handleKeyEventWithCapsOn:(int) keyCode andKeyDown:(BOOL)keyDown
{
if(keyDown)
{
CGEventRef eventDown;
eventDown = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)keyCode, true);
CGEventSetFlags(eventDown, kCGEventFlagMaskShift);
CGEventPost(kCGSessionEventTap, eventDown);
CFRelease(eventDown);
}
else
{
CGEventRef eventUp;
eventUp = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)keyCode, false);
CGEventSetFlags(eventUp, kCGEventFlagMaskShift);
CGEventPost(kCGSessionEventTap, eventUp);
// SHIFT Up Event
CGEventRef eShiftUp = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, false);
CGEventPost(kCGSessionEventTap, eShiftUp);
CFRelease(eventUp);
CFRelease(eShiftUp);
}
}
Upvotes: -1