spiegel-keyman/mac/KeymanEngine4Mac/KeymanEngine4Mac/KME/OnScreenKeyboard/OSKView.m

800 lines
41 KiB
Objective-C

//
// OSKView.m
// KeymanEngine4Mac
//
// Created by Serkan Kurt on 7/11/2014.
// Copyright (c) 2017 SIL International. All rights reserved.
//
#import "OSKView.h"
#import "OSKKey.h"
#import "KeyView.h"
#import "MacVKCodes.h"
#import "WindowsVKCodes.h"
#import "NKey.h"
#import "CoreHelper.h"
#include <Carbon/Carbon.h>
#import "KMELogs.h"
const int64_t OSK_EVENT_FLAG = 0x8000000000000000;
const int64_t OSK_EVENT_MODIFIER_MASK = 0x00000000FFFFFFFF;
@interface OSKView()
@property (nonatomic, strong) NSArray *oskLayout;
@property (nonatomic, strong) NSArray *oskDefaultNKeys;
@property (nonatomic, assign) BOOL physicalShiftState;
@property (nonatomic, assign) BOOL oskShiftState;
@property (nonatomic, assign) BOOL physicalOptionState;
@property (nonatomic, assign) BOOL oskOptionState;
@property (nonatomic, assign) BOOL physicalControlState;
@property (nonatomic, assign) BOOL oskControlState;
@end
@implementation OSKView
@synthesize tag;
/**
* Check the kCGEventSourceUserData field of the event and determine whether the event was
* generated by the OSK.
*/
+ (BOOL)isOskKeyDownEvent:(CGEventRef)event {
// check to see if this event was generated by the OSK
int64_t eventUserData = CGEventGetIntegerValueField(event, kCGEventSourceUserData);
return ((eventUserData & OSK_EVENT_FLAG) == OSK_EVENT_FLAG);
}
/**
* If the event was generated by the OSK, then return the modifier flags stored in the kCGEventSourceUserData
* field at the time the event was generated
*/
+ (NSEventModifierFlags)extractModifierFlagsFromOskEvent:(CGEventRef)event {
NSEventModifierFlags modifierFlags = 0;
int64_t eventUserData = CGEventGetIntegerValueField(event, kCGEventSourceUserData);
if ([OSKView isOskKeyDownEvent:event]) {
modifierFlags = (NSEventModifierFlags) eventUserData & OSK_EVENT_MODIFIER_MASK;
}
return modifierFlags;
}
- (id)initWithFrame:(NSRect)frame {
os_log_debug([KMELogs oskLog], "OSKView initWithFrame: %{public}@", NSStringFromRect(frame));
self = [super initWithFrame:frame];
if (self) {
// Custom initialization
[self initOSKKeys];
}
return self;
}
- (NSString *)description {
NSString *format = @"<shiftState:%d oskShiftState:%d optionState:%d oskOptionState:%d controlState:%d oskControlState:%d>";
NSString *str = [NSString stringWithFormat:format, _physicalShiftState, _oskShiftState, _physicalOptionState, _oskOptionState, _physicalControlState, _oskControlState];
return str;
}
- (void)drawRect:(NSRect)rect {
os_log_debug([KMELogs oskLog], "OSKView drawRect: %{public}@", NSStringFromRect(rect));
CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] CGContext];
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSetLineWidth(context, 1.0);
CGColorRef cgClearColor = CGColorGetConstantColor(kCGColorClear);
CGContextSetStrokeColorWithColor(context, cgClearColor);
CGContextSetFillColorWithColor(context, cgClearColor);
CGContextBeginPath(context);
CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0));
CGContextDrawPath(context, kCGPathStroke);
CGContextBeginPath(context);
CGContextAddRect(context, CGRectMake(1.0, 1.0, rect.size.width-1.0, rect.size.height-1.0));
CGContextClip(context);
//TODO: gradient from clear to clear -- what does this do?
NSColor *bgColor = [NSColor clearColor]; //[NSColor colorWithWhite:0.7 alpha:1.0];
NSColor *bgColor2 = [NSColor clearColor]; //[NSColor colorWithWhite:0.5 alpha:1.0];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSArray *gradientColors = [NSArray arrayWithObjects:(id)bgColor.CGColor, bgColor2.CGColor, nil];
CGFloat gradientLocations[] = {0, 1};
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations);
CGPoint startPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
- (BOOL)isFlipped {
return YES;
}
// Returns TRUE for ISO keyboards or when the .kvk file requests the 102nd key
// to right of the Left Shift key.
- (BOOL)use102ndKey {
/*
Note: LMGetKbdType() does not appear to work reliably; it seems to always
return ANSI even when there is a European keyboard plugged in to my Macbook.
We'll use it anyway in case better results are found for Macs with native
ISO keyboards.
*/
UInt8 kbdType = LMGetKbdType();
PhysicalKeyboardLayoutType kbdLayoutType = KBGetLayoutType(kbdType);
switch(kbdLayoutType) {
case kKeyboardANSI: return _kvk != nil && _kvk.flags & KVKH_102;
case kKeyboardJIS:
case kKeyboardISO: return YES;
}
// We don't know what the keyboard is, so let's err on the side of
// more keys, not fewer
return YES;
}
- (void)setKvk:(KVKFile *)kvk {
os_log_debug([KMELogs oskLog], "OSKView setKvk, forces keyboard to re-layout");
_kvk = kvk;
// Force the keyboard to re-layout
_oskLayout = nil;
_oskDefaultNKeys = nil;
[self updateKeyLabelsForCurrentLayer];
}
- (void)initOSKKeys {
os_log_debug([KMELogs oskLog], "OSKView initOSKKeys");
CGFloat viewWidth = self.frame.size.width;
CGFloat viewHeight = self.frame.size.height;
CGFloat margin = 2.0;
CGFloat keyHeight = (viewHeight - margin*2)/self.oskLayout.count;
CGFloat keyWidth = (viewWidth - margin*2)/14.5;
CGFloat px;
CGFloat py = margin;
for (NSArray *row in self.oskLayout) {
px = margin;
NSUInteger len = [row count];
for (int i = 0; i < len; i++) {
OSKKey *key = (OSKKey *)[row objectAtIndex:i];
CGFloat width = keyWidth * key.scale;
if ((i+1) == len && (px + width + margin) < viewWidth)
width += (viewWidth - (px + width + margin));
NSRect rect = NSInsetRect(NSMakeRect(px, py, width, keyHeight), 2, 2);
KeyView *keyView = [[KeyView alloc] initWithFrame:rect];;
[keyView setKey:key];
[keyView setTarget:self];
if (self.oskShiftState && (keyView.key.keyCode == MVK_LEFT_SHIFT || keyView.key.keyCode == MVK_RIGHT_SHIFT))
[keyView setKeyPressed:YES];
else if (self.oskOptionState && (keyView.key.keyCode == MVK_LEFT_ALT || keyView.key.keyCode == MVK_RIGHT_ALT))
[keyView setKeyPressed:YES];
[self addSubview:keyView];
px += width;
}
py += keyHeight;
}
[self updateKeyLabelsForCurrentLayer];
}
- (NSArray *)oskLayout {
if (_oskLayout == nil) {
os_log_debug([KMELogs oskLog], "oskLayout -> creating new arrays of OSKKey objects");
NSArray *row1 = [NSArray arrayWithObjects:
[[OSKKey alloc] initWithKeyCode:MVK_GRAVE caption:@"`" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_1 caption:@"1" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_2 caption:@"2" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_3 caption:@"3" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_4 caption:@"4" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_5 caption:@"5" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_6 caption:@"6" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_7 caption:@"7" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_8 caption:@"8" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_9 caption:@"9" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_0 caption:@"0" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_MINUS caption:@"-" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_EQUAL caption:@"=" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_BACKSPACE caption:@"⬅︎" scale:1.5], nil];
NSArray *row2 = [NSArray arrayWithObjects:
[[OSKKey alloc] initWithKeyCode:MVK_TAB caption:@"↹" scale:1.5],
[[OSKKey alloc] initWithKeyCode:MVK_Q caption:@"Q" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_W caption:@"W" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_E caption:@"E" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_R caption:@"R" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_T caption:@"T" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_Y caption:@"Y" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_U caption:@"U" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_I caption:@"I" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_O caption:@"O" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_P caption:@"P" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_BRACKET caption:@"[" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_RIGHT_BRACKET caption:@"]" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_BACKSLASH caption:@"\\" scale:1.0], nil];
NSArray *row3 = [NSArray arrayWithObjects:
[[OSKKey alloc] initWithKeyCode:MVK_CAPS_LOCK caption:@"Caps Lock" scale:1.75],
[[OSKKey alloc] initWithKeyCode:MVK_A caption:@"A" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_S caption:@"S" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_D caption:@"D" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_F caption:@"F" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_G caption:@"G" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_H caption:@"H" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_J caption:@"J" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_K caption:@"K" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_L caption:@"L" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_SEMICOLON caption:@";" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_QUOTE caption:@"'" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_ENTER caption:@"↵" scale:1.75], nil];
NSArray *row4a = [self use102ndKey] ?
[NSArray arrayWithObjects:
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:1.25],
[[OSKKey alloc] initWithKeyCode:MVK_OEM102 caption:@"\\" scale:1.0], nil] :
[NSArray arrayWithObjects:
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_SHIFT caption:@"⇧" scale:2.25], nil];
NSArray *row4b = [NSArray arrayWithObjects:
[[OSKKey alloc] initWithKeyCode:MVK_Z caption:@"Z" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_X caption:@"X" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_C caption:@"C" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_V caption:@"V" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_B caption:@"B" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_N caption:@"N" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_M caption:@"M" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_COMMA caption:@"," scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_PERIOD caption:@"." scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_SLASH caption:@"/" scale:1.0],
[[OSKKey alloc] initWithKeyCode:MVK_RIGHT_SHIFT caption:@"⇧" scale:2.25], nil];
NSArray *row4 = [row4a arrayByAddingObjectsFromArray:row4b];
NSArray *row5 = [NSArray arrayWithObjects:
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_CTRL caption:@"Ctrl" scale:1.75],
[[OSKKey alloc] initWithKeyCode:MVK_LEFT_ALT caption:@"Alt" scale:1.5],
[[OSKKey alloc] initWithKeyCode:MVK_SPACE caption:@"" scale:8.0],
[[OSKKey alloc] initWithKeyCode:MVK_RIGHT_ALT caption:@"Alt" scale:1.5],
[[OSKKey alloc] initWithKeyCode:MVK_RIGHT_CTRL caption:@"Ctrl" scale:1.75], nil];
_oskLayout = [NSArray arrayWithObjects:row1, row2, row3, row4, row5, nil];
}
return _oskLayout;
}
- (NSArray *)oskDefaultNKeys {
if (_oskDefaultNKeys == nil) {
os_log_debug([KMELogs oskLog], "oskDefaultNKeys -> creating new arrays of default number OSKKey objects");
NSMutableArray *defNKeys = [[NSMutableArray alloc] initWithCapacity:0];
// row 1
NKey *nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_GRAVE; nkey1.text = @"`"; nkey1.bitmap = nil;
NKey *nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_GRAVE; nkey2.text = @"~"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_1; nkey1.text = @"1"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_1; nkey2.text = @"!"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_2; nkey1.text = @"2"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_2; nkey2.text = @"@"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_3; nkey1.text = @"3"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_3; nkey2.text = @"#"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_4; nkey1.text = @"4"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_4; nkey2.text = @"$"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_5; nkey1.text = @"5"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_5; nkey2.text = @"%"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_6; nkey1.text = @"6"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_6; nkey2.text = @"^"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_7; nkey1.text = @"7"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_7; nkey2.text = @"&"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_8; nkey1.text = @"8"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_8; nkey2.text = @"*"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_9; nkey1.text = @"9"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_9; nkey2.text = @"("; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_0; nkey1.text = @"0"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_0; nkey2.text = @")"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_MINUS; nkey1.text = @"-"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_MINUS; nkey2.text = @"_"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_EQUAL; nkey1.text = @"="; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_EQUAL; nkey2.text = @"+"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
// row 2
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_Q; nkey1.text = @"q"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_Q; nkey2.text = @"Q"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_W; nkey1.text = @"w"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_W; nkey2.text = @"W"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_E; nkey1.text = @"e"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_E; nkey2.text = @"E"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_R; nkey1.text = @"r"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_R; nkey2.text = @"R"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_T; nkey1.text = @"t"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_T; nkey2.text = @"T"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_Y; nkey1.text = @"y"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_Y; nkey2.text = @"Y"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_U; nkey1.text = @"u"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_U; nkey2.text = @"U"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_I; nkey1.text = @"i"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_I; nkey2.text = @"I"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_O; nkey1.text = @"o"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_O; nkey2.text = @"O"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_P; nkey1.text = @"p"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_P; nkey2.text = @"P"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_LEFT_BRACKET; nkey1.text = @"["; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_LEFT_BRACKET; nkey2.text = @"{"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_RIGHT_BRACKET; nkey1.text = @"]"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_RIGHT_BRACKET; nkey2.text = @"}"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_BACKSLASH; nkey1.text = @"\\"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_BACKSLASH; nkey2.text = @"|"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
// row 3
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_A; nkey1.text = @"a"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_A; nkey2.text = @"A"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_S; nkey1.text = @"s"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_S; nkey2.text = @"S"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_D; nkey1.text = @"d"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_D; nkey2.text = @"D"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_F; nkey1.text = @"f"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_F; nkey2.text = @"F"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_G; nkey1.text = @"g"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_G; nkey2.text = @"G"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_H; nkey1.text = @"h"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_H; nkey2.text = @"H"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_J; nkey1.text = @"j"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_J; nkey2.text = @"J"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_K; nkey1.text = @"k"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_K; nkey2.text = @"K"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_L; nkey1.text = @"l"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_L; nkey2.text = @"L"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_SEMICOLON; nkey1.text = @";"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_SEMICOLON; nkey2.text = @":"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_QUOTE; nkey1.text = @"'"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_QUOTE; nkey2.text = @"\""; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
if([self use102ndKey]) {
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_OEM_102; nkey1.text = @"\\"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_OEM_102; nkey2.text = @"|"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
}
// row 4
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_Z; nkey1.text = @"z"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_Z; nkey2.text = @"Z"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_X; nkey1.text = @"x"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_X; nkey2.text = @"X"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_C; nkey1.text = @"c"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_C; nkey2.text = @"C"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_V; nkey1.text = @"v"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_V; nkey2.text = @"V"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_B; nkey1.text = @"b"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_B; nkey2.text = @"B"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_N; nkey1.text = @"n"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_N; nkey2.text = @"N"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_KEY_M; nkey1.text = @"m"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_KEY_M; nkey2.text = @"M"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_COMMA; nkey1.text = @","; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_COMMA; nkey2.text = @"<"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_PERIOD; nkey1.text = @"."; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_PERIOD; nkey2.text = @">"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
nkey1 = [[NKey alloc] init]; nkey1.typeFlags = 2; nkey1.modifierFlags = 0; nkey1.keyCode = VK_SLASH; nkey1.text = @"/"; nkey1.bitmap = nil;
nkey2 = [[NKey alloc] init]; nkey2.typeFlags = 2; nkey2.modifierFlags = 1; nkey2.keyCode = VK_SLASH; nkey2.text = @"?"; nkey2.bitmap = nil;
[defNKeys addObjectsFromArray:@[nkey1, nkey2]];
_oskDefaultNKeys = [[NSArray alloc] initWithArray:defNKeys];
}
return _oskDefaultNKeys;
}
/**
* called when closing the OSK
* when the OSK is not visible then modifier state is determined solely by the physical keyboard
*/
- (void)clearOskModifiers {
_oskShiftState = NO;
_oskOptionState = NO;
_oskControlState = NO;
[self updateModifierKeysForState];
[self updateKeyLabelsForCurrentLayer];
}
- (void)resetOSK {
[self setOskShiftState:NO];
[self setOskOptionState:NO];
[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self initOSKKeys];
}
- (void)resizeOSKLayout {
os_log_debug([KMELogs oskLog], "OSKView resizeOSKLayout, removing all superviews");
[self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[self initOSKKeys];
}
- (void)keyAction:(id)sender {
KeyView *keyView = (KeyView *)sender;
NSUInteger keyCode = [keyView.key keyCode];
os_log_debug([KMELogs oskLog], "OSKView keyAction, self: %{public}@, keyView: %{public}@", self, keyView);
if (keyCode < 0x100) {
NSRunningApplication *app = NSWorkspace.sharedWorkspace.frontmostApplication;
pid_t processId = app.processIdentifier;
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
CGEventRef keyDownEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, true);
CGEventRef keyUpEvent = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, false);
CGEventSetIntegerValueField(keyDownEvent, kCGEventSourceUserData, [self createOskEventUserData]);
os_log_debug([KMELogs oskLog], "OSKView keyAction, keyDownEvent: %{public}@, modifier flags: 0x%llX", keyDownEvent, CGEventGetFlags(keyDownEvent));
CGEventPostToPid(processId, keyDownEvent);
CGEventPostToPid(processId, keyUpEvent);
CFRelease(keyDownEvent);
CFRelease(keyUpEvent);
CFRelease(source);
}
else {
if (keyCode == MVK_LEFT_SHIFT || keyCode == MVK_RIGHT_SHIFT) {
[self setOskShiftState:!self.oskShiftState];
}
else if (keyCode == MVK_LEFT_ALT || keyCode == MVK_RIGHT_ALT) {
[self setOskOptionState:!self.oskOptionState];
}
else if (keyCode == MVK_LEFT_CTRL || keyCode == MVK_RIGHT_CTRL) {
[self setOskControlState:!self.oskControlState];
}
}
}
/**
* get the event modifier flags representing the current state of the osk modifiers
*/
- (NSEventModifierFlags)getOskEventModifierFlags {
return [self getEventModifierFlags:self.oskShiftState optionFlag:self.oskOptionState controlFlag:self.oskControlState];
}
/**
* get the event modifier flags that represent the combined state of the physical and osk modifiers
*/
- (NSEventModifierFlags) getCombinedEventModifierFlags {
BOOL shift = self.physicalShiftState | self.oskShiftState;
BOOL option = self.physicalOptionState | self.oskOptionState;
BOOL control = self.physicalControlState | self.oskControlState;
return [self getEventModifierFlags:shift optionFlag:option controlFlag:control];
}
/**
* get the NSEventModifierFlags value that corresponds to the specified modifier states
*/
- (NSEventModifierFlags)getEventModifierFlags:(BOOL)shift optionFlag:(BOOL)option controlFlag:(BOOL)control {
NSEventModifierFlags modifierFlags = 0;
if (shift) {
modifierFlags = modifierFlags | NSEventModifierFlagShift;
}
/**
* Both left and right option keys on the OSK cause oskOptionState to be true without distinction of left or right.
* However, the generated event is a right alt so that it will trigger the right alt rules in the Keyman keyboard.
*/
if (option) {
modifierFlags = modifierFlags | MK_RIGHT_ALT_MASK;
}
if (control) {
modifierFlags = modifierFlags | NSEventModifierFlagControl;
}
return modifierFlags;
}
/**
* Create the 64-bit value to pass in the kCGEventSourceUserData field of the generated CGEvent
* The upper-most bit is set to distinguish it from the default value of zero, and the lower 32 bits
* store the modifier state of the OSK at the time that the keydown event was generated.
* This data is safely conveys the modifier information to the eventTap function.
* If the modifiers themselves were instead set by calling the function `CGEventSetFlags`
* directly on the generated CGEvent, then there would be no way to distinguish between the left
* and right option keys.
*
*/
- (int64_t) createOskEventUserData {
// set bit to identify this user data as originating from the OSK
int64_t oskEventData = OSK_EVENT_FLAG;
NSEventModifierFlags eventModifierFlags = [self getCombinedEventModifierFlags];
return oskEventData | eventModifierFlags;
}
- (void)handleKeyEvent:(NSEvent *)event {
os_log_debug([KMELogs oskLog], "OSKView handleKeyEvent event.type: %lu", event.type);
NSView *view = [self viewWithTag:event.keyCode|0x1000];
if (view == nil || ![view isKindOfClass:[KeyView class]])
return;
KeyView *keyView = (KeyView *)view;
if (event.type == NSEventTypeKeyDown)
[keyView setKeyPressed:YES];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(setKeyPressedOff:) object:keyView];
[self performSelector:@selector(setKeyPressedOff:) withObject:keyView afterDelay:0.1];
}
- (void)setKeyPressedOff:(KeyView *)keyView {
[keyView setKeyPressed:NO];
}
/**
* get the Keyman modifier flags that represent the combined state of the physical and osk modifiers
*/
- (WORD) getKeymanModifierFlagsForCurrentLayer {
BOOL shift = self.physicalShiftState | self.oskShiftState;
BOOL option = self.physicalOptionState | self.oskOptionState;
BOOL control = self.physicalControlState | self.oskControlState;
return [self getKeymanModifierFlags:shift optionFlag:option controlFlag:control];
}
/**
* get Keyman modifier flags for the specified modifier states
*/
- (WORD)getKeymanModifierFlags:(BOOL)shift optionFlag:(BOOL)option controlFlag:(BOOL)control {
WORD flags = 0;
if (shift) {
flags |= KVKS_SHIFT;
}
if (option) {
if (self.kvk.containsRightAltKeys) {
flags |= KVKS_RALT;
} else if (self.kvk.containsAltKeys) {
flags |= KVKS_ALT;
}
}
if (control) {
flags |= KVKS_RCTRL;
}
return flags;
}
/**
* Display the key labels that correspond to the current state of the modifier keys.
* The layer shown depends on both the physical modifier state and the osk modifier state.
*/
- (void)updateKeyLabelsForCurrentLayer {
os_log_debug([KMELogs oskLog], "OSKView updateKeyLabelsForState, phsyical modifiers [shift: %d, option: %d, control: %d]\nosk modifiers [shift: %d, option: %d, control: %d]", self.physicalShiftState, self.physicalOptionState, self.physicalControlState, self.oskShiftState, self.oskOptionState, self.oskControlState);
[self resetKeyLabels];
NSMutableArray *mKeys = [[self keyTags] mutableCopy];
NSArray *nkeys = [self.kvk keys];
if (nkeys == nil)
nkeys = self.oskDefaultNKeys;
WORD keymanFlagsForCurrentLayer = [self getKeymanModifierFlagsForCurrentLayer];
NSString *ansiFont = [self ansiFont];
NSString *unicodeFont = [self unicodeFont];
unsigned short keyCode;
for (NKey *nkey in nkeys) {
if (nkey.modifierFlags == keymanFlagsForCurrentLayer) {
keyCode = [self MacKeyCode:nkey.keyCode];
os_log_debug([KMELogs keyLog], "keyCode: %d, %x for key: %{public}@", keyCode, keyCode, nkey);
if (keyCode < USHRT_MAX) {
NSView *view = [self viewWithTag:keyCode|0x1000];
if (view == nil || ![view isKindOfClass:[KeyView class]])
continue;
KeyView *keyView = (KeyView *)view;
[keyView setLabelFont:ansiFont];
if (nkey.typeFlags & KVKK_UNICODE) {
[keyView setLabelText:nkey.text];
NSString* label = nkey.text;
NSData* data = [label dataUsingEncoding:NSUTF8StringEncoding];
os_log_debug([KMELogs keyLog], "setLabelText to %{public}@, utf8data %{public}@", label, data);
[keyView setLabelFont:unicodeFont];
[mKeys removeObject:[NSNumber numberWithInteger:(keyCode|0x1000)]];
}
if (nkey.typeFlags & KVKK_BITMAP) {
[keyView setBitmap:nkey.bitmap];
}
[keyView setNeedsDisplay:YES];
}
}
}
/*
for (NSNumber *t in mKeys) {
NSView *view = [self viewWithTag:[t integerValue]|0x1000];
if (view == nil || ![view isKindOfClass:[KeyView class]])
continue;
KeyView *keyView = (KeyView *)view;
[keyView setLabelText:@""];
}*/
}
- (NSArray *)keyTags {
NSMutableArray *keyTags = [NSMutableArray arrayWithCapacity:0];
NSArray *views = [self subviews];
for (NSView *view in views) {
if (![view isKindOfClass:[KeyView class]])
continue;
[keyTags addObject:[NSNumber numberWithInteger:[view tag]]];
}
return keyTags;
}
- (void)resetKeyLabels {
NSArray *views = [self subviews];
for (NSView *view in views) {
if (![view isKindOfClass:[KeyView class]])
continue;
[(KeyView *)view setKey:[(KeyView *)view key]];
[(KeyView *)view setBitmap:nil];
[(KeyView *)view setNeedsDisplay:YES];
}
}
- (void)setPhysicalShiftState:(BOOL)state {
if (_physicalShiftState != state) {
_physicalShiftState = state;
/**
* When setting the physical shift state, clear the OSK shift state
* The state of the physical key overrides the modifier key clicked in the OSK.
*/
_oskShiftState = NO;
os_log_debug([KMELogs oskLog], "hardware shift key released");
[self updateKeyLabelsForCurrentLayer];
[self updateShiftKeysForState];
}
}
- (void)setOskShiftState:(BOOL)state {
if (_oskShiftState != state && !self.physicalShiftState) {
_oskShiftState = state;
[self updateKeyLabelsForCurrentLayer];
[self updateShiftKeysForState];
}
}
- (void)setPhysicalOptionState:(BOOL)state {
if (_physicalOptionState != state) {
_physicalOptionState = state;
/**
* When setting the physical option state, clear the OSK option state
* The state of the physical key overrides the modifier key clicked in the OSK.
*/
_oskOptionState = NO;
[self updateKeyLabelsForCurrentLayer];
[self updateOptionKeysForState];
}
}
- (void)setOskOptionState:(BOOL)state {
if (_oskOptionState != state && !self.physicalOptionState) {
_oskOptionState = state;
[self updateKeyLabelsForCurrentLayer];
[self updateOptionKeysForState];
}
}
- (void)setPhysicalControlState:(BOOL)state {
if (_physicalControlState != state) {
_physicalControlState = state;
/**
* When setting the physical control state, clear the OSK control state
* The state of the physical key overrides the modifier key clicked in the OSK.
*/
_oskControlState = NO;
[self updateKeyLabelsForCurrentLayer];
[self updateControlKeysForState];
}
}
- (void)setOskControlState:(BOOL)state {
if (_oskControlState != state && !self.physicalControlState) {
_oskControlState = state;
[self updateKeyLabelsForCurrentLayer];
[self updateControlKeysForState];
}
}
- (void)updateModifierKeysForState {
[self updateShiftKeysForState];
[self updateOptionKeysForState];
[self updateControlKeysForState];
}
- (void)updateShiftKeysForState {
BOOL pressed = self.oskShiftState || self.physicalShiftState;
KeyView *leftShiftKey = (KeyView *)[self viewWithTag:MVK_LEFT_SHIFT|0x1000];
KeyView *rightShiftKey = (KeyView *)[self viewWithTag:MVK_RIGHT_SHIFT|0x1000];
[leftShiftKey setKeyPressed:pressed];
[rightShiftKey setKeyPressed:pressed];
}
- (void)updateOptionKeysForState{
BOOL pressed = self.oskOptionState || self.physicalOptionState;
KeyView *leftOptionKey = (KeyView *)[self viewWithTag:MVK_LEFT_ALT|0x1000];
KeyView *rightOptionKey = (KeyView *)[self viewWithTag:MVK_RIGHT_ALT|0x1000];
[leftOptionKey setKeyPressed:pressed];
[rightOptionKey setKeyPressed:pressed];
}
- (void)updateControlKeysForState {
BOOL pressed = self.oskControlState || self.physicalControlState;
KeyView *leftControlKey = (KeyView *)[self viewWithTag:MVK_LEFT_CTRL|0x1000];
KeyView *rightControlKey = (KeyView *)[self viewWithTag:MVK_RIGHT_CTRL|0x1000];
[leftControlKey setKeyPressed:pressed];
[rightControlKey setKeyPressed:pressed];
}
- (NSString *)ansiFont {
return [self.kvk ansiFont].name;
}
- (NSString *)unicodeFont {
return [self.kvk unicodeFont].name;
}
// Converts a Windows VK code to Mac VK code
- (unsigned short)MacKeyCode:(unsigned short)vkCode {
unsigned short keyCode = USHRT_MAX;
for (unsigned short i = 0; i < 0x80; i++) {
if (VirtualKeyMap[i] == vkCode) {
keyCode = i;
break;
}
}
return keyCode;
}
@end