Blame client/Mac/Keyboard.m

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * MacFreeRDP
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#import "Keyboard.h"
Packit Service fa4841
Packit Service fa4841
#include <CoreFoundation/CoreFoundation.h>
Packit Service fa4841
Packit Service b1ea74
#include <IOKit/IOKitLib.h>
Packit Service b1ea74
#include <IOKit/hid/IOHIDManager.h>
Packit Service fa4841
Packit Service fa4841
struct _APPLE_KEYBOARD_DESC
Packit Service fa4841
{
Packit Service fa4841
	uint32_t ProductId;
Packit Service fa4841
	enum APPLE_KEYBOARD_TYPE Type;
Packit Service fa4841
};
Packit Service fa4841
typedef struct _APPLE_KEYBOARD_DESC APPLE_KEYBOARD_DESC;
Packit Service fa4841
Packit Service fa4841
/* VendorID: 0x05AC (Apple, Inc.) */
Packit Service fa4841
Packit Service b1ea74
static const APPLE_KEYBOARD_DESC APPLE_KEYBOARDS[] = {
Packit Service fa4841
	{ 0x200, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x201, APPLE_KEYBOARD_TYPE_ANSI }, /* USB Keyboard [Alps or Logitech, M2452] */
Packit Service fa4841
	{ 0x202, APPLE_KEYBOARD_TYPE_ANSI }, /* Keyboard [ALPS] */
Packit Service fa4841
	{ 0x203, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x204, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x205, APPLE_KEYBOARD_TYPE_ANSI }, /* Extended Keyboard [Mitsumi] */
Packit Service fa4841
	{ 0x206, APPLE_KEYBOARD_TYPE_ANSI }, /* Extended Keyboard [Mitsumi] */
Packit Service fa4841
	{ 0x207, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x208, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x209, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x20A, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x20B, APPLE_KEYBOARD_TYPE_ANSI }, /* Pro Keyboard [Mitsumi, A1048/US layout] */
Packit Service fa4841
	{ 0x20C, APPLE_KEYBOARD_TYPE_ANSI }, /* Extended Keyboard [Mitsumi] */
Packit Service fa4841
	{ 0x20D, APPLE_KEYBOARD_TYPE_ANSI }, /* Pro Keyboard [Mitsumi, A1048/JIS layout] */
Packit Service fa4841
	{ 0x20E, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x20F, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service fa4841
	{ 0x210, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x211, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x212, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x213, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x214, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x215, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x216, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x217, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x218, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x219, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x21A, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x21B, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x21C, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x21D, APPLE_KEYBOARD_TYPE_ANSI }, /* Aluminum Mini Keyboard (ANSI) */
Packit Service b1ea74
	{ 0x21E, APPLE_KEYBOARD_TYPE_ISO },  /* Aluminum Mini Keyboard (ISO) */
Packit Service b1ea74
	{ 0x21F, APPLE_KEYBOARD_TYPE_JIS },  /* Aluminum Mini Keyboard (JIS) */
Packit Service fa4841
	{ 0x220, APPLE_KEYBOARD_TYPE_ANSI }, /* Aluminum Keyboard (ANSI) */
Packit Service b1ea74
	{ 0x221, APPLE_KEYBOARD_TYPE_JIS },  /* Aluminum Keyboard (JIS) */
Packit Service b1ea74
	{ 0x222, APPLE_KEYBOARD_TYPE_JIS },  /* Aluminum Keyboard (JIS) */
Packit Service fa4841
	{ 0x223, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x224, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x225, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x226, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x227, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x228, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x229, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (MacBook Pro) (ANSI) */
Packit Service b1ea74
	{ 0x22A, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (MacBook Pro) (ISO) */
Packit Service b1ea74
	{ 0x22B, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (MacBook Pro) (JIS) */
Packit Service fa4841
	{ 0x22C, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x22D, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x22E, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x22F, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x230, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (MacBook Pro 4,1) (ANSI) */
Packit Service b1ea74
	{ 0x231, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (MacBook Pro 4,1) (ISO) */
Packit Service b1ea74
	{ 0x232, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (MacBook Pro 4,1) (JIS) */
Packit Service fa4841
	{ 0x233, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x234, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x235, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x236, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x237, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x238, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x239, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x23A, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x23B, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x23C, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x23D, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x23E, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x23F, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x240, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x241, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x242, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x243, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x244, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x245, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x246, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x247, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x248, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x249, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x24A, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (MacBook Air) (ISO) */
Packit Service fa4841
	{ 0x24B, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x24C, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x24D, APPLE_KEYBOARD_TYPE_ISO }, /* Internal Keyboard/Trackpad (MacBook Air) (ISO) */
Packit Service fa4841
	{ 0x24E, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x24F, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x250, APPLE_KEYBOARD_TYPE_ISO }, /* Aluminium Keyboard (ISO) */
Packit Service fa4841
	{ 0x251, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x252, APPLE_KEYBOARD_TYPE_ANSI }, /* Internal Keyboard/Trackpad (ANSI) */
Packit Service b1ea74
	{ 0x253, APPLE_KEYBOARD_TYPE_ISO },  /* Internal Keyboard/Trackpad (ISO) */
Packit Service b1ea74
	{ 0x254, APPLE_KEYBOARD_TYPE_JIS },  /* Internal Keyboard/Trackpad (JIS) */
Packit Service fa4841
	{ 0x255, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x256, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x257, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x258, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x259, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x25A, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x25B, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x25C, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x25D, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x25E, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x25F, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x260, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x261, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x262, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x263, APPLE_KEYBOARD_TYPE_ANSI }, /* Apple Internal Keyboard / Trackpad (MacBook Retina) */
Packit Service fa4841
	{ 0x264, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x265, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x266, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x267, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x268, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x269, APPLE_KEYBOARD_TYPE_ANSI },
Packit Service fa4841
	{ 0x26A, APPLE_KEYBOARD_TYPE_ANSI }
Packit Service fa4841
};
Packit Service fa4841
Packit Service b1ea74
static enum APPLE_KEYBOARD_TYPE mac_identify_keyboard_type(uint32_t vendorID, uint32_t productID)
Packit Service fa4841
{
Packit Service fa4841
	enum APPLE_KEYBOARD_TYPE type = APPLE_KEYBOARD_TYPE_ANSI;
Packit Service fa4841
Packit Service fa4841
	if (vendorID != 0x05AC) /* Apple, Inc. */
Packit Service fa4841
		return type;
Packit Service fa4841
Packit Service fa4841
	if ((productID < 0x200) || (productID > 0x26A))
Packit Service fa4841
		return type;
Packit Service fa4841
Packit Service fa4841
	type = APPLE_KEYBOARDS[productID - 0x200].Type;
Packit Service fa4841
	return type;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
enum APPLE_KEYBOARD_TYPE mac_detect_keyboard_type(void)
Packit Service fa4841
{
Packit Service fa4841
	CFSetRef deviceCFSetRef = NULL;
Packit Service fa4841
	IOHIDDeviceRef inIOHIDDeviceRef = NULL;
Packit Service fa4841
	IOHIDManagerRef tIOHIDManagerRef = NULL;
Packit Service b1ea74
	IOHIDDeviceRef *tIOHIDDeviceRefs = nil;
Packit Service fa4841
	enum APPLE_KEYBOARD_TYPE type = APPLE_KEYBOARD_TYPE_ANSI;
Packit Service b1ea74
	tIOHIDManagerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
Packit Service fa4841
Packit Service fa4841
	if (!tIOHIDManagerRef)
Packit Service fa4841
		return type;
Packit Service fa4841
Packit Service fa4841
	IOHIDManagerSetDeviceMatching(tIOHIDManagerRef, NULL);
Packit Service fa4841
	IOReturn tIOReturn = IOHIDManagerOpen(tIOHIDManagerRef, kIOHIDOptionsTypeNone);
Packit Service fa4841
Packit Service fa4841
	if (noErr != tIOReturn)
Packit Service fa4841
		return type;
Packit Service fa4841
Packit Service fa4841
	deviceCFSetRef = IOHIDManagerCopyDevices(tIOHIDManagerRef);
Packit Service fa4841
Packit Service fa4841
	if (!deviceCFSetRef)
Packit Service fa4841
		return type;
Packit Service fa4841
Packit Service fa4841
	CFIndex deviceIndex, deviceCount = CFSetGetCount(deviceCFSetRef);
Packit Service fa4841
	tIOHIDDeviceRefs = malloc(sizeof(IOHIDDeviceRef) * deviceCount);
Packit Service fa4841
Packit Service fa4841
	if (!tIOHIDDeviceRefs)
Packit Service fa4841
		return type;
Packit Service fa4841
Packit Service b1ea74
	CFSetGetValues(deviceCFSetRef, (const void **)tIOHIDDeviceRefs);
Packit Service fa4841
	CFRelease(deviceCFSetRef);
Packit Service fa4841
	deviceCFSetRef = NULL;
Packit Service fa4841
Packit Service fa4841
	for (deviceIndex = 0; deviceIndex < deviceCount; deviceIndex++)
Packit Service fa4841
	{
Packit Service fa4841
		CFTypeRef tCFTypeRef;
Packit Service fa4841
		uint32_t vendorID = 0;
Packit Service fa4841
		uint32_t productID = 0;
Packit Service fa4841
		uint32_t countryCode = 0;
Packit Service fa4841
		enum APPLE_KEYBOARD_TYPE ltype;
Packit Service fa4841
Packit Service fa4841
		if (!tIOHIDDeviceRefs[deviceIndex])
Packit Service fa4841
			continue;
Packit Service fa4841
Packit Service fa4841
		inIOHIDDeviceRef = tIOHIDDeviceRefs[deviceIndex];
Packit Service fa4841
		tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey));
Packit Service fa4841
Packit Service fa4841
		if (tCFTypeRef)
Packit Service b1ea74
			CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &vendorID);
Packit Service fa4841
Packit Service b1ea74
		tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey));
Packit Service fa4841
Packit Service fa4841
		if (tCFTypeRef)
Packit Service b1ea74
			CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &productID);
Packit Service fa4841
Packit Service b1ea74
		tCFTypeRef = IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDCountryCodeKey));
Packit Service fa4841
Packit Service fa4841
		if (tCFTypeRef)
Packit Service b1ea74
			CFNumberGetValue((CFNumberRef)tCFTypeRef, kCFNumberSInt32Type, &countryCode);
Packit Service fa4841
Packit Service fa4841
		ltype = mac_identify_keyboard_type(vendorID, productID);
Packit Service fa4841
Packit Service fa4841
		if (ltype != APPLE_KEYBOARD_TYPE_ANSI)
Packit Service fa4841
		{
Packit Service fa4841
			type = ltype;
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(tIOHIDDeviceRefs);
Packit Service fa4841
Packit Service fa4841
	if (deviceCFSetRef)
Packit Service fa4841
	{
Packit Service fa4841
		CFRelease(deviceCFSetRef);
Packit Service fa4841
		deviceCFSetRef = NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (tIOHIDManagerRef)
Packit Service fa4841
		CFRelease(tIOHIDManagerRef);
Packit Service fa4841
Packit Service fa4841
	return type;
Packit Service fa4841
}