FreeRDP/client/Mac/MRDPView.m

1432 lines
38 KiB
Mathematica
Raw Normal View History

2013-02-22 08:52:51 +04:00
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* MacFreeRDP
*
* Copyright 2012 Thomas Goddard
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2013-07-18 00:04:55 +04:00
#include <winpr/windows.h>
#include "mf_client.h"
#import "mfreerdp.h"
#import "MRDPView.h"
#import "MRDPCursor.h"
#import "Clipboard.h"
2013-03-11 05:32:05 +04:00
#import "PasswordDialog.h"
2018-11-29 19:23:09 +03:00
#import "CertificateDialog.h"
2013-03-11 07:14:40 +04:00
#include <winpr/crt.h>
#include <winpr/assert.h>
2013-03-11 07:14:40 +04:00
#include <winpr/input.h>
#include <winpr/synch.h>
#include <winpr/sysinfo.h>
2013-03-11 07:14:40 +04:00
#include <freerdp/constants.h>
#import "freerdp/freerdp.h"
#import "freerdp/types.h"
#import "freerdp/channels/channels.h"
#import "freerdp/gdi/gdi.h"
2013-12-11 23:31:54 +04:00
#import "freerdp/gdi/dc.h"
#import "freerdp/gdi/region.h"
#import "freerdp/graphics.h"
#import "freerdp/client/file.h"
#import "freerdp/client/cmdline.h"
2014-09-12 19:13:01 +04:00
#import "freerdp/log.h"
2018-11-29 17:46:37 +03:00
#import <CoreGraphics/CoreGraphics.h>
2014-09-12 19:13:01 +04:00
#define TAG CLIENT_TAG("mac")
2019-11-06 17:24:51 +03:00
static BOOL mf_Pointer_New(rdpContext *context, rdpPointer *pointer);
static void mf_Pointer_Free(rdpContext *context, rdpPointer *pointer);
static BOOL mf_Pointer_Set(rdpContext *context, const rdpPointer *pointer);
static BOOL mf_Pointer_SetNull(rdpContext *context);
static BOOL mf_Pointer_SetDefault(rdpContext *context);
static BOOL mf_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y);
2019-11-06 17:24:51 +03:00
static BOOL mac_begin_paint(rdpContext *context);
static BOOL mac_end_paint(rdpContext *context);
static BOOL mac_desktop_resize(rdpContext *context);
2019-11-06 17:24:51 +03:00
static void input_activity_cb(freerdp *instance);
2019-11-06 17:24:51 +03:00
static DWORD WINAPI mac_client_thread(void *param);
2013-07-18 00:04:55 +04:00
@implementation MRDPView
@synthesize is_connected;
2019-11-06 17:24:51 +03:00
- (int)rdpStart:(rdpContext *)rdp_context
{
2019-11-06 17:24:51 +03:00
rdpSettings *settings;
2013-06-23 04:27:23 +04:00
EmbedWindowEventArgs e;
[self initializeView];
WINPR_ASSERT(rdp_context);
2013-06-23 06:55:51 +04:00
context = rdp_context;
2019-11-06 17:24:51 +03:00
mfc = (mfContext *)rdp_context;
2013-06-23 06:55:51 +04:00
instance = context->instance;
WINPR_ASSERT(instance);
settings = context->settings;
WINPR_ASSERT(settings);
2013-06-23 04:27:23 +04:00
EventArgsInit(&e, "mfreerdp");
e.embed = TRUE;
2019-11-06 17:24:51 +03:00
e.handle = (void *)self;
2013-06-23 04:27:23 +04:00
PubSub_OnEmbedWindow(context->pubSub, context, &e);
2019-11-06 17:24:51 +03:00
NSScreen *screen = [[NSScreen screens] objectAtIndex:0];
NSRect screenFrame = [screen frame];
if (settings->Fullscreen)
{
settings->DesktopWidth = screenFrame.size.width;
settings->DesktopHeight = screenFrame.size.height;
2016-02-02 11:50:23 +03:00
[self enterFullScreenMode:[NSScreen mainScreen] withOptions:nil];
}
else
{
[self exitFullScreenModeWithOptions:nil];
}
mfc->client_height = settings->DesktopHeight;
mfc->client_width = settings->DesktopWidth;
2013-06-23 04:27:23 +04:00
if (!(mfc->common.thread =
2019-11-06 17:24:51 +03:00
CreateThread(NULL, 0, mac_client_thread, (void *)context, 0, &mfc->mainThreadId)))
{
WLog_ERR(TAG, "failed to create client thread");
return -1;
}
2013-07-18 00:04:55 +04:00
return 0;
}
2019-11-06 17:24:51 +03:00
DWORD WINAPI mac_client_thread(void *param)
2013-07-18 00:04:55 +04:00
{
@autoreleasepool
{
int status;
DWORD rc;
HANDLE events[16] = { 0 };
HANDLE inputEvent;
DWORD nCount;
DWORD nCountTmp;
DWORD nCountBase;
2019-11-06 17:24:51 +03:00
rdpContext *context = (rdpContext *)param;
mfContext *mfc = (mfContext *)context;
freerdp *instance = context->instance;
MRDPView *view = mfc->view;
rdpSettings *settings = context->settings;
status = freerdp_connect(context->instance);
2016-08-03 16:29:24 +03:00
if (!status)
{
[view setIs_connected:0];
return 0;
}
2016-08-03 16:29:24 +03:00
[view setIs_connected:1];
nCount = 0;
events[nCount++] = mfc->stopEvent;
2016-08-03 16:29:24 +03:00
if (!(inputEvent = freerdp_get_message_queue_event_handle(instance,
2019-11-06 17:24:51 +03:00
FREERDP_INPUT_MESSAGE_QUEUE)))
{
WLog_ERR(TAG, "failed to get input event handle");
goto disconnect;
}
2016-08-03 16:29:24 +03:00
events[nCount++] = inputEvent;
nCountBase = nCount;
while (!freerdp_shall_disconnect(instance))
{
nCount = nCountBase;
{
2019-11-06 17:24:51 +03:00
if (!(nCountTmp = freerdp_get_event_handles(context, &events[nCount], 16 - nCount)))
{
WLog_ERR(TAG, "freerdp_get_event_handles failed");
break;
}
2016-08-03 16:29:24 +03:00
nCount += nCountTmp;
}
rc = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (rc >= (WAIT_OBJECT_0 + nCount))
{
WLog_ERR(TAG, "WaitForMultipleObjects failed (0x%08X)", rc);
break;
}
if (rc == WAIT_OBJECT_0)
{
/* stop event triggered */
break;
}
if (WaitForSingleObject(inputEvent, 0) == WAIT_OBJECT_0)
{
input_activity_cb(instance);
}
{
if (!freerdp_check_event_handles(context))
{
WLog_ERR(TAG, "freerdp_check_event_handles failed");
break;
}
}
}
2016-08-03 16:29:24 +03:00
disconnect:
[view setIs_connected:0];
freerdp_disconnect(instance);
ExitThread(0);
return 0;
}
}
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
2016-08-03 16:29:24 +03:00
2013-02-22 07:04:09 +04:00
if (self)
{
2013-02-22 06:42:47 +04:00
// Initialization code here.
}
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
return self;
}
2019-11-06 17:24:51 +03:00
- (void)viewDidLoad
{
[self initializeView];
}
2013-06-23 04:27:23 +04:00
2019-11-06 17:24:51 +03:00
- (void)initializeView
{
if (!initialized)
{
cursors = [[NSMutableArray alloc] initWithCapacity:10];
// setup a mouse tracking area
2019-11-06 17:24:51 +03:00
NSTrackingArea *trackingArea = [[NSTrackingArea alloc]
initWithRect:[self visibleRect]
options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved |
NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag |
NSTrackingActiveWhenFirstResponder
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
// Set the default cursor
currentCursor = [NSCursor arrowCursor];
initialized = YES;
}
}
2019-11-06 17:24:51 +03:00
- (void)setCursor:(NSCursor *)cursor
{
self->currentCursor = cursor;
2019-11-06 17:24:51 +03:00
dispatch_async(dispatch_get_main_queue(), ^{
[[self window] invalidateCursorRectsForView:self];
});
}
2019-11-06 17:24:51 +03:00
- (void)resetCursorRects
{
[self addCursorRect:[self visibleRect] cursor:currentCursor];
}
2013-02-22 06:42:47 +04:00
- (BOOL)acceptsFirstResponder
{
return YES;
}
2019-11-06 17:24:51 +03:00
- (void)mouseMoved:(NSEvent *)event
2013-02-22 06:42:47 +04:00
{
[super mouseMoved:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
NSPoint loc = [event locationInWindow];
2019-11-06 17:24:51 +03:00
int x = (int)loc.x;
int y = (int)loc.y;
2022-01-19 15:11:34 +03:00
mf_scale_mouse_event(context, PTR_FLAGS_MOVE, x, y);
}
2019-11-06 17:24:51 +03:00
- (void)mouseDown:(NSEvent *)event
{
2013-02-22 06:42:47 +04:00
[super mouseDown:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
NSPoint loc = [event locationInWindow];
2019-11-06 17:24:51 +03:00
int x = (int)loc.x;
int y = (int)loc.y;
2022-01-19 15:11:34 +03:00
mf_press_mouse_button(context, 0, x, y, TRUE);
}
2019-11-06 17:24:51 +03:00
- (void)mouseUp:(NSEvent *)event
{
2013-02-22 06:42:47 +04:00
[super mouseUp:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
NSPoint loc = [event locationInWindow];
2019-11-06 17:24:51 +03:00
int x = (int)loc.x;
int y = (int)loc.y;
2022-01-19 15:11:34 +03:00
mf_press_mouse_button(context, 0, x, y, FALSE);
}
2019-11-06 17:24:51 +03:00
- (void)rightMouseDown:(NSEvent *)event
{
2013-02-22 06:42:47 +04:00
[super rightMouseDown:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
NSPoint loc = [event locationInWindow];
2019-11-06 17:24:51 +03:00
int x = (int)loc.x;
int y = (int)loc.y;
2022-01-19 15:11:34 +03:00
mf_press_mouse_button(context, 1, x, y, TRUE);
}
2019-11-06 17:24:51 +03:00
- (void)rightMouseUp:(NSEvent *)event
{
2013-02-22 06:42:47 +04:00
[super rightMouseUp:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
NSPoint loc = [event locationInWindow];
2019-11-06 17:24:51 +03:00
int x = (int)loc.x;
int y = (int)loc.y;
2022-01-19 15:11:34 +03:00
mf_press_mouse_button(context, 1, x, y, FALSE);
}
2019-11-06 17:24:51 +03:00
- (void)otherMouseDown:(NSEvent *)event
{
2013-02-22 06:42:47 +04:00
[super otherMouseDown:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
NSPoint loc = [event locationInWindow];
2019-11-06 17:24:51 +03:00
int x = (int)loc.x;
int y = (int)loc.y;
int pressed = [event buttonNumber];
2022-01-19 15:11:34 +03:00
mf_press_mouse_button(context, pressed, x, y, TRUE);
}
2019-11-06 17:24:51 +03:00
- (void)otherMouseUp:(NSEvent *)event
{
2013-02-22 06:42:47 +04:00
[super otherMouseUp:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
NSPoint loc = [event locationInWindow];
2019-11-06 17:24:51 +03:00
int x = (int)loc.x;
int y = (int)loc.y;
int pressed = [event buttonNumber];
2022-01-19 15:11:34 +03:00
mf_press_mouse_button(context, pressed, x, y, FALSE);
}
2019-11-06 17:24:51 +03:00
- (void)scrollWheel:(NSEvent *)event
{
2013-02-22 08:07:35 +04:00
UINT16 flags;
2013-02-22 06:42:47 +04:00
[super scrollWheel:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
float dx = [event deltaX];
float dy = [event deltaY];
/* 1 event = 120 units */
UINT16 units = 0;
if (fabsf(dy) > FLT_EPSILON)
{
flags = PTR_FLAGS_WHEEL;
units = fabsf(dy) * 120;
if (dy < 0)
flags |= PTR_FLAGS_WHEEL_NEGATIVE;
}
else if (fabsf(dx) > FLT_EPSILON)
{
flags = PTR_FLAGS_HWHEEL;
units = fabsf(dx) * 120;
if (dx > 0)
flags |= PTR_FLAGS_WHEEL_NEGATIVE;
}
else
return;
/* Wheel rotation steps:
*
* positive: 0 ... 0xFF -> slow ... fast
* negative: 0 ... 0xFF -> fast ... slow
*/
UINT16 step = units;
if (step > 0xFF)
step = 0xFF;
/* Negative rotation, so count down steps from top
* 9bit twos complement */
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
step = 0x100 - step;
2022-01-19 15:11:34 +03:00
mf_scale_mouse_event(context, flags | step, 0, 0);
}
2019-11-06 17:24:51 +03:00
- (void)mouseDragged:(NSEvent *)event
{
2013-02-22 06:42:47 +04:00
[super mouseDragged:event];
2016-08-03 16:29:24 +03:00
if (!self.is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
NSPoint loc = [event locationInWindow];
2019-11-06 17:24:51 +03:00
int x = (int)loc.x;
int y = (int)loc.y;
2013-02-22 06:42:47 +04:00
// send mouse motion event to RDP server
2022-01-19 15:11:34 +03:00
mf_scale_mouse_event(context, PTR_FLAGS_MOVE, x, y);
}
DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type)
{
/**
* In 99% of cases, the given key code is truly keyboard independent.
* This function handles the remaining 1% of edge cases.
*
* Hungarian Keyboard: This is 'QWERTZ' and not 'QWERTY'.
* The '0' key is on the left of the '1' key, where '~' is on a US keyboard.
* A special 'i' letter key with acute is found on the right of the left shift key.
* On the hungarian keyboard, the 'i' key is at the left of the 'Y' key
* Some international keyboards have a corresponding key which would be at
* the left of the 'Z' key when using a QWERTY layout.
*
* The Apple Hungarian keyboard sends inverted key codes for the '0' and 'i' keys.
* When using the US keyboard layout, key codes are left as-is (inverted).
* When using the Hungarian keyboard layout, key codes are swapped (non-inverted).
* This means that when using the Hungarian keyboard layout with a US keyboard,
* the keys corresponding to '0' and 'i' will effectively be inverted.
*
* To fix the '0' and 'i' key inversion, we use the corresponding output character
* provided by OS X and check for a character to key code mismatch: for instance,
* when the output character is '0' for the key code corresponding to the 'i' key.
*/
#if 0
switch (keyChar)
{
case '0':
case 0x00A7: /* section sign */
if (keyCode == APPLE_VK_ISO_Section)
keyCode = APPLE_VK_ANSI_Grave;
2016-08-03 16:29:24 +03:00
break;
2016-08-03 16:29:24 +03:00
case 0x00ED: /* latin small letter i with acute */
case 0x00CD: /* latin capital letter i with acute */
if (keyCode == APPLE_VK_ANSI_Grave)
keyCode = APPLE_VK_ISO_Section;
2016-08-03 16:29:24 +03:00
break;
}
2016-08-03 16:29:24 +03:00
#endif
2016-08-03 16:29:24 +03:00
/* Perform keycode correction for all ISO keyboards */
2016-08-03 16:29:24 +03:00
if (type == APPLE_KEYBOARD_TYPE_ISO)
{
if (keyCode == APPLE_VK_ANSI_Grave)
keyCode = APPLE_VK_ISO_Section;
else if (keyCode == APPLE_VK_ISO_Section)
keyCode = APPLE_VK_ANSI_Grave;
}
2016-08-03 16:29:24 +03:00
return keyCode;
}
2019-11-06 17:24:51 +03:00
- (void)keyDown:(NSEvent *)event
{
DWORD keyCode;
DWORD keyFlags;
2013-03-11 07:14:40 +04:00
DWORD vkcode;
DWORD scancode;
unichar keyChar;
2019-11-06 17:24:51 +03:00
NSString *characters;
2016-08-03 16:29:24 +03:00
2013-02-22 07:04:09 +04:00
if (!is_connected)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
keyFlags = KBD_FLAGS_DOWN;
keyCode = [event keyCode];
characters = [event charactersIgnoringModifiers];
2016-08-03 16:29:24 +03:00
if ([characters length] > 0)
{
keyChar = [characters characterAtIndex:0];
keyCode = fixKeyCode(keyCode, keyChar, mfc->appleKeyboardType);
}
2016-08-03 16:29:24 +03:00
vkcode = GetVirtualKeyCodeFromKeycode(keyCode + 8, KEYCODE_TYPE_APPLE);
2013-03-11 07:14:40 +04:00
scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4);
keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0;
scancode &= 0xFF;
vkcode &= 0xFF;
#if 0
2016-08-03 16:29:24 +03:00
WLog_ERR(TAG,
"keyDown: keyCode: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s",
keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode));
#endif
2017-11-20 13:46:32 +03:00
sync_keyboard_state(instance);
WINPR_ASSERT(instance->context);
freerdp_input_send_keyboard_event(instance->context->input, keyFlags, scancode);
}
2019-11-06 17:24:51 +03:00
- (void)keyUp:(NSEvent *)event
{
DWORD keyCode;
DWORD keyFlags;
2013-03-11 07:14:40 +04:00
DWORD vkcode;
DWORD scancode;
unichar keyChar;
2019-11-06 17:24:51 +03:00
NSString *characters;
2013-02-22 07:04:09 +04:00
if (!is_connected)
2013-02-22 06:42:47 +04:00
return;
keyFlags = KBD_FLAGS_RELEASE;
keyCode = [event keyCode];
characters = [event charactersIgnoringModifiers];
2016-08-03 16:29:24 +03:00
if ([characters length] > 0)
{
keyChar = [characters characterAtIndex:0];
keyCode = fixKeyCode(keyCode, keyChar, mfc->appleKeyboardType);
}
vkcode = GetVirtualKeyCodeFromKeycode(keyCode + 8, KEYCODE_TYPE_APPLE);
2013-03-11 07:14:40 +04:00
scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4);
keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0;
scancode &= 0xFF;
vkcode &= 0xFF;
#if 0
2016-08-03 16:29:24 +03:00
WLog_DBG(TAG,
"keyUp: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X keyFlags: %d name: %s",
keyCode, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode));
#endif
WINPR_ASSERT(instance->context);
freerdp_input_send_keyboard_event(instance->context->input, keyFlags, scancode);
}
2019-11-06 17:24:51 +03:00
- (void)flagsChanged:(NSEvent *)event
{
int key;
DWORD keyFlags;
DWORD vkcode;
DWORD scancode;
DWORD modFlags;
rdpInput *input;
2013-02-22 08:07:35 +04:00
if (!is_connected)
2013-02-22 06:42:47 +04:00
return;
keyFlags = 0;
key = [event keyCode] + 8;
2022-02-01 18:19:43 +03:00
modFlags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
vkcode = GetVirtualKeyCodeFromKeycode(key, KEYCODE_TYPE_APPLE);
scancode = GetVirtualScanCodeFromVirtualKeyCode(vkcode, 4);
keyFlags |= (scancode & KBDEXT) ? KBDEXT : 0;
scancode &= 0xFF;
vkcode &= 0xFF;
#if 0
2016-08-03 16:29:24 +03:00
WLog_DBG(TAG,
"flagsChanged: key: 0x%04X scancode: 0x%04X vkcode: 0x%04X extended: %d name: %s modFlags: 0x%04X",
key - 8, scancode, vkcode, keyFlags, GetVirtualKeyName(vkcode), modFlags);
2022-02-01 18:19:43 +03:00
if (modFlags & NSEventModifierFlagCapsLock)
WLog_DBG(TAG, "NSEventModifierFlagCapsLock");
2022-02-01 18:19:43 +03:00
if (modFlags & NSEventModifierFlagShift)
WLog_DBG(TAG, "NSEventModifierFlagShift");
2022-02-01 18:19:43 +03:00
if (modFlags & NSEventModifierFlagControl)
WLog_DBG(TAG, "NSEventModifierFlagControl");
2022-02-01 18:19:43 +03:00
if (modFlags & NSEventModifierFlagOption)
WLog_DBG(TAG, "NSEventModifierFlagOption");
2022-02-01 18:19:43 +03:00
if (modFlags & NSEventModifierFlagCommand)
WLog_DBG(TAG, "NSEventModifierFlagCommand");
2022-02-01 18:19:43 +03:00
if (modFlags & NSEventModifierFlagNumericPad)
WLog_DBG(TAG, "NSEventModifierFlagNumericPad");
2022-02-01 18:19:43 +03:00
if (modFlags & NSEventModifierFlagHelp)
WLog_DBG(TAG, "NSEventModifierFlagHelp");
2016-08-03 16:29:24 +03:00
#endif
WINPR_ASSERT(instance);
WINPR_ASSERT(instance->context);
input = instance->context->input;
2022-02-01 18:19:43 +03:00
if ((modFlags & NSEventModifierFlagCapsLock) && !(kbdModFlags & NSEventModifierFlagCapsLock))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode);
2022-02-01 18:19:43 +03:00
else if (!(modFlags & NSEventModifierFlagCapsLock) && (kbdModFlags & NSEventModifierFlagCapsLock))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode);
2022-02-01 18:19:43 +03:00
if ((modFlags & NSEventModifierFlagShift) && !(kbdModFlags & NSEventModifierFlagShift))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode);
2022-02-01 18:19:43 +03:00
else if (!(modFlags & NSEventModifierFlagShift) && (kbdModFlags & NSEventModifierFlagShift))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode);
2022-02-01 18:19:43 +03:00
if ((modFlags & NSEventModifierFlagControl) && !(kbdModFlags & NSEventModifierFlagControl))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode);
2022-02-01 18:19:43 +03:00
else if (!(modFlags & NSEventModifierFlagControl) && (kbdModFlags & NSEventModifierFlagControl))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode);
2022-02-01 18:19:43 +03:00
if ((modFlags & NSEventModifierFlagOption) && !(kbdModFlags & NSEventModifierFlagOption))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode);
2022-02-01 18:19:43 +03:00
else if (!(modFlags & NSEventModifierFlagOption) && (kbdModFlags & NSEventModifierFlagOption))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode);
2022-02-01 18:19:43 +03:00
if ((modFlags & NSEventModifierFlagCommand) && !(kbdModFlags & NSEventModifierFlagCommand))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode);
2022-02-01 18:19:43 +03:00
else if (!(modFlags & NSEventModifierFlagCommand) && (kbdModFlags & NSEventModifierFlagCommand))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode);
2022-02-01 18:19:43 +03:00
if ((modFlags & NSEventModifierFlagNumericPad) && !(kbdModFlags & NSEventModifierFlagNumericPad))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode);
2022-02-01 18:19:43 +03:00
else if (!(modFlags & NSEventModifierFlagNumericPad) && (kbdModFlags & NSEventModifierFlagNumericPad))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode);
2022-02-01 18:19:43 +03:00
if ((modFlags & NSEventModifierFlagHelp) && !(kbdModFlags & NSEventModifierFlagHelp))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_DOWN, scancode);
2022-02-01 18:19:43 +03:00
else if (!(modFlags & NSEventModifierFlagHelp) && (kbdModFlags & NSEventModifierFlagHelp))
freerdp_input_send_keyboard_event(input, keyFlags | KBD_FLAGS_RELEASE, scancode);
kbdModFlags = modFlags;
}
2019-11-06 17:24:51 +03:00
- (void)releaseResources
{
2013-02-22 06:42:47 +04:00
int i;
2013-02-22 06:42:47 +04:00
for (i = 0; i < argc; i++)
2015-05-11 10:07:39 +03:00
free(argv[i]);
2013-02-22 06:42:47 +04:00
if (!is_connected)
return;
2015-05-11 10:07:39 +03:00
free(pixel_data);
}
2019-11-06 17:24:51 +03:00
- (void)drawRect:(NSRect)rect
{
2013-06-23 06:55:51 +04:00
if (!context)
2013-02-22 06:42:47 +04:00
return;
2016-08-03 16:29:24 +03:00
2013-06-23 06:55:51 +04:00
if (self->bitmap_context)
{
2022-02-01 18:19:43 +03:00
CGContextRef cgContext = [[NSGraphicsContext currentContext] CGContext];
2013-06-23 04:27:23 +04:00
CGImageRef cgImage = CGBitmapContextCreateImage(self->bitmap_context);
CGContextSaveGState(cgContext);
2019-11-06 17:24:51 +03:00
CGContextClipToRect(
cgContext, CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height));
CGContextDrawImage(cgContext,
CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height),
cgImage);
CGContextRestoreGState(cgContext);
CGImageRelease(cgImage);
}
2013-06-23 04:27:23 +04:00
else
{
/* Fill the screen with black */
[[NSColor blackColor] set];
2013-06-23 04:27:23 +04:00
NSRectFill([self bounds]);
}
}
2019-11-06 17:24:51 +03:00
- (void)onPasteboardTimerFired:(NSTimer *)timer
{
const void *data;
UINT32 size;
UINT32 formatId;
BOOL formatMatch;
int changeCount;
2019-11-06 17:24:51 +03:00
NSData *formatData;
NSString *formatString;
2019-11-06 17:24:51 +03:00
const char *formatType;
NSPasteboardItem *item;
changeCount = (int)[pasteboard_rd changeCount];
2016-08-03 16:29:24 +03:00
if (changeCount == pasteboard_changecount)
return;
2016-08-03 16:29:24 +03:00
pasteboard_changecount = changeCount;
2019-11-06 17:24:51 +03:00
NSArray *items = [pasteboard_rd pasteboardItems];
2016-08-03 16:29:24 +03:00
if ([items count] < 1)
return;
2016-08-03 16:29:24 +03:00
item = [items objectAtIndex:0];
/**
* System-Declared Uniform Type Identifiers:
* https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html
*/
formatMatch = FALSE;
2016-08-03 16:29:24 +03:00
2019-11-06 17:24:51 +03:00
for (NSString *type in [item types])
2013-02-22 06:42:47 +04:00
{
formatType = [type UTF8String];
2016-08-03 16:29:24 +03:00
if (strcmp(formatType, "public.utf8-plain-text") == 0)
2013-02-22 06:42:47 +04:00
{
formatData = [item dataForType:type];
if (formatData == nil)
{
break;
}
formatString = [[NSString alloc] initWithData:formatData encoding:NSUTF8StringEncoding];
size = strlen([formatString UTF8String]) + 1;
data = [formatString UTF8String];
formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING");
ClipboardSetData(mfc->clipboard, formatId, data, size);
[formatString release];
formatMatch = TRUE;
break;
2013-02-22 06:42:47 +04:00
}
}
2016-08-03 16:29:24 +03:00
if (!formatMatch)
ClipboardEmpty(mfc->clipboard);
2016-08-03 16:29:24 +03:00
if (mfc->clipboardSync)
mac_cliprdr_send_client_format_list(mfc->cliprdr);
}
2019-11-06 17:24:51 +03:00
- (void)pause
{
2019-11-06 17:24:51 +03:00
dispatch_async(dispatch_get_main_queue(), ^{
[self->pasteboard_timer invalidate];
});
2019-11-06 17:24:51 +03:00
NSArray *trackingAreas = self.trackingAreas;
2016-08-03 16:29:24 +03:00
2019-11-06 17:24:51 +03:00
for (NSTrackingArea *ta in trackingAreas)
{
[self removeTrackingArea:ta];
}
}
- (void)resume
{
if (!self.is_connected)
return;
2019-11-06 17:24:51 +03:00
dispatch_async(dispatch_get_main_queue(), ^{
self->pasteboard_timer =
[NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:@selector(onPasteboardTimerFired:)
userInfo:nil
repeats:YES];
NSTrackingArea *trackingArea = [[NSTrackingArea alloc]
initWithRect:[self visibleRect]
options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved |
NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag |
NSTrackingActiveWhenFirstResponder
owner:self
userInfo:nil];
[self addTrackingArea:trackingArea];
[trackingArea release];
});
}
2019-11-06 17:24:51 +03:00
- (void)setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height
{
WINPR_ASSERT(mfc);
mfc->yCurrentScroll = yOffset;
mfc->xCurrentScroll = xOffset;
mfc->client_height = height;
mfc->client_width = width;
}
static void mac_OnChannelConnectedEventHandler(void *context, const ChannelConnectedEventArgs *e)
2014-09-13 20:02:53 +04:00
{
rdpSettings *settings;
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)context;
WINPR_ASSERT(mfc);
WINPR_ASSERT(e);
settings = mfc->common.context.settings;
WINPR_ASSERT(settings);
2016-08-03 16:29:24 +03:00
2022-01-19 13:05:55 +03:00
if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
{
2019-11-06 17:24:51 +03:00
mac_cliprdr_init(mfc, (CliprdrClientContext *)e->pInterface);
}
2014-09-13 20:02:53 +04:00
else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
{
}
2022-01-19 13:05:55 +03:00
else
freerdp_client_OnChannelConnectedEventHandler(context, e);
2014-09-13 20:02:53 +04:00
}
static void mac_OnChannelDisconnectedEventHandler(void *context,
const ChannelDisconnectedEventArgs *e)
2014-09-13 20:02:53 +04:00
{
rdpSettings *settings;
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)context;
WINPR_ASSERT(mfc);
WINPR_ASSERT(e);
settings = mfc->common.context.settings;
WINPR_ASSERT(settings);
2016-08-03 16:29:24 +03:00
2022-01-19 13:05:55 +03:00
if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0)
{
2019-11-06 17:24:51 +03:00
mac_cliprdr_uninit(mfc, (CliprdrClientContext *)e->pInterface);
}
2014-09-13 20:02:53 +04:00
else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
{
}
2022-01-19 13:05:55 +03:00
else
freerdp_client_OnChannelDisconnectedEventHandler(context, e);
2014-09-13 20:02:53 +04:00
}
2019-11-06 17:24:51 +03:00
BOOL mac_pre_connect(freerdp *instance)
{
2019-11-06 17:24:51 +03:00
rdpSettings *settings;
rdpUpdate *update;
WINPR_ASSERT(instance);
WINPR_ASSERT(instance->context);
update = instance->context->update;
WINPR_ASSERT(update);
update->BeginPaint = mac_begin_paint;
update->EndPaint = mac_end_paint;
update->DesktopResize = mac_desktop_resize;
settings = instance->context->settings;
WINPR_ASSERT(settings);
2013-06-23 04:27:23 +04:00
if (!settings->ServerHostname)
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "error: server hostname was not specified with /v:<server>[:port]");
2020-10-20 10:08:37 +03:00
return FALSE;
2013-06-23 04:27:23 +04:00
}
settings->OsMajorType = OSMAJORTYPE_MACINTOSH;
settings->OsMinorType = OSMINORTYPE_MACINTOSH;
2019-11-06 17:24:51 +03:00
PubSub_SubscribeChannelConnected(instance->context->pubSub, mac_OnChannelConnectedEventHandler);
2014-09-13 20:02:53 +04:00
PubSub_SubscribeChannelDisconnected(instance->context->pubSub,
2018-02-14 12:14:33 +03:00
mac_OnChannelDisconnectedEventHandler);
if (!freerdp_client_load_addins(instance->context->channels, settings))
return FALSE;
2013-02-22 06:42:47 +04:00
return TRUE;
}
2019-11-06 17:24:51 +03:00
BOOL mac_post_connect(freerdp *instance)
{
2019-11-06 17:24:51 +03:00
rdpGdi *gdi;
rdpPointer rdp_pointer = { 0 };
mfContext *mfc;
MRDPView *view;
WINPR_ASSERT(instance);
mfc = (mfContext *)instance->context;
WINPR_ASSERT(mfc);
view = (MRDPView *)mfc->view;
WINPR_ASSERT(view);
2013-02-22 06:42:47 +04:00
rdp_pointer.size = sizeof(rdpPointer);
2013-03-11 20:14:44 +04:00
rdp_pointer.New = mf_Pointer_New;
rdp_pointer.Free = mf_Pointer_Free;
rdp_pointer.Set = mf_Pointer_Set;
rdp_pointer.SetNull = mf_Pointer_SetNull;
rdp_pointer.SetDefault = mf_Pointer_SetDefault;
2017-11-09 12:22:16 +03:00
rdp_pointer.SetPosition = mf_Pointer_SetPosition;
2016-08-01 19:14:17 +03:00
2016-10-04 10:00:00 +03:00
if (!gdi_init(instance, PIXEL_FORMAT_BGRX32))
return FALSE;
2016-08-03 16:29:24 +03:00
gdi = instance->context->gdi;
view->bitmap_context = mac_create_bitmap_context(instance->context);
2013-02-22 08:07:35 +04:00
graphics_register_pointer(instance->context->graphics, &rdp_pointer);
2013-03-11 20:14:44 +04:00
/* setup pasteboard (aka clipboard) for copy operations (write only) */
view->pasteboard_wr = [NSPasteboard generalPasteboard];
2013-03-11 20:14:44 +04:00
/* setup pasteboard for read operations */
2019-11-06 17:24:51 +03:00
dispatch_async(dispatch_get_main_queue(), ^{
view->pasteboard_rd = [NSPasteboard generalPasteboard];
view->pasteboard_changecount = -1;
});
[view resume];
mfc->appleKeyboardType = mac_detect_keyboard_type();
2013-02-22 06:42:47 +04:00
return TRUE;
}
2019-11-06 17:24:51 +03:00
void mac_post_disconnect(freerdp *instance)
2018-11-29 18:29:07 +03:00
{
2019-11-06 17:24:51 +03:00
mfContext *mfc;
MRDPView *view;
2018-11-29 18:29:07 +03:00
if (!instance || !instance->context)
return;
2019-11-06 17:24:51 +03:00
mfc = (mfContext *)instance->context;
view = (MRDPView *)mfc->view;
[view pause];
2019-11-06 17:24:51 +03:00
PubSub_UnsubscribeChannelConnected(instance->context->pubSub,
mac_OnChannelConnectedEventHandler);
PubSub_UnsubscribeChannelDisconnected(instance->context->pubSub,
mac_OnChannelDisconnectedEventHandler);
2018-11-29 18:29:07 +03:00
gdi_free(instance);
}
2019-11-06 17:24:51 +03:00
static BOOL mac_authenticate_int(NSString *title, freerdp *instance, char **username,
char **password, char **domain)
2013-03-11 05:32:05 +04:00
{
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)instance->context;
MRDPView *view = (MRDPView *)mfc->view;
PasswordDialog *dialog = [PasswordDialog new];
2018-11-29 18:29:07 +03:00
dialog.serverHostname = title;
2013-03-11 05:32:05 +04:00
2013-03-11 08:35:15 +04:00
if (*username)
2019-11-06 17:24:51 +03:00
dialog.username = [NSString stringWithCString:*username encoding:NSUTF8StringEncoding];
2013-03-11 05:32:05 +04:00
2013-03-11 08:35:15 +04:00
if (*password)
2019-11-06 17:24:51 +03:00
dialog.password = [NSString stringWithCString:*password encoding:NSUTF8StringEncoding];
2013-03-11 05:32:05 +04:00
if (*domain)
2019-11-06 17:24:51 +03:00
dialog.domain = [NSString stringWithCString:*domain encoding:NSUTF8StringEncoding];
2013-06-23 04:27:23 +04:00
2019-11-06 17:24:51 +03:00
dispatch_sync(dispatch_get_main_queue(), ^{
[dialog performSelectorOnMainThread:@selector(runModal:)
withObject:[view window]
waitUntilDone:TRUE];
});
BOOL ok = dialog.modalCode;
2016-10-20 18:22:08 +03:00
if (ok)
2013-03-11 08:35:15 +04:00
{
2018-08-24 10:54:25 +03:00
size_t ulen, plen, dlen;
2019-11-06 17:24:51 +03:00
const char *submittedUsername = [dialog.username cStringUsingEncoding:NSUTF8StringEncoding];
2018-08-24 10:54:25 +03:00
ulen = (strlen(submittedUsername) + 1) * sizeof(char);
*username = malloc(ulen);
if (!(*username))
return FALSE;
sprintf_s(*username, ulen, "%s", submittedUsername);
2019-11-06 17:24:51 +03:00
const char *submittedPassword = [dialog.password cStringUsingEncoding:NSUTF8StringEncoding];
2018-08-24 10:54:25 +03:00
plen = (strlen(submittedPassword) + 1) * sizeof(char);
*password = malloc(plen);
if (!(*password))
return FALSE;
sprintf_s(*password, plen, "%s", submittedPassword);
2019-11-06 17:24:51 +03:00
const char *submittedDomain = [dialog.domain cStringUsingEncoding:NSUTF8StringEncoding];
2018-08-24 10:54:25 +03:00
dlen = (strlen(submittedDomain) + 1) * sizeof(char);
*domain = malloc(dlen);
if (!(*domain))
return FALSE;
sprintf_s(*domain, dlen, "%s", submittedDomain);
2013-03-11 08:35:15 +04:00
}
return ok;
2013-03-11 05:32:05 +04:00
}
2019-11-06 17:24:51 +03:00
BOOL mac_authenticate(freerdp *instance, char **username, char **password, char **domain)
2018-11-29 18:29:07 +03:00
{
rdpSettings *settings;
WINPR_ASSERT(instance);
WINPR_ASSERT(instance->context);
settings = instance->context->settings;
WINPR_ASSERT(settings);
2019-11-06 17:24:51 +03:00
NSString *title =
[NSString stringWithFormat:@"%@:%u",
[NSString stringWithCString:settings->ServerHostname
2019-11-06 17:24:51 +03:00
encoding:NSUTF8StringEncoding],
settings -> ServerPort];
2018-11-29 18:29:07 +03:00
return mac_authenticate_int(title, instance, username, password, domain);
}
2019-11-06 17:24:51 +03:00
BOOL mac_gw_authenticate(freerdp *instance, char **username, char **password, char **domain)
2018-11-29 18:29:07 +03:00
{
rdpSettings *settings;
WINPR_ASSERT(instance);
WINPR_ASSERT(instance->context);
settings = instance->context->settings;
WINPR_ASSERT(settings);
2019-11-06 17:24:51 +03:00
NSString *title =
[NSString stringWithFormat:@"%@:%u",
[NSString stringWithCString:settings->GatewayHostname
2019-11-06 17:24:51 +03:00
encoding:NSUTF8StringEncoding],
settings -> GatewayPort];
2018-11-29 18:29:07 +03:00
return mac_authenticate_int(title, instance, username, password, domain);
}
2019-11-06 17:24:51 +03:00
DWORD mac_verify_certificate_ex(freerdp *instance, const char *host, UINT16 port,
const char *common_name, const char *subject, const char *issuer,
const char *fingerprint, DWORD flags)
2018-11-29 18:29:07 +03:00
{
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)instance->context;
MRDPView *view = (MRDPView *)mfc->view;
CertificateDialog *dialog = [CertificateDialog new];
const char *type = "RDP-Server";
char hostname[8192];
if (flags & VERIFY_CERT_FLAG_GATEWAY)
type = "RDP-Gateway";
if (flags & VERIFY_CERT_FLAG_REDIRECT)
type = "RDP-Redirect";
2019-11-06 17:24:51 +03:00
sprintf_s(hostname, sizeof(hostname), "%s %s:%" PRIu16, type, host, port);
2022-02-01 18:19:43 +03:00
dialog.serverHostname = [NSString stringWithCString:hostname encoding:NSUTF8StringEncoding];
2019-11-06 17:24:51 +03:00
dialog.commonName = [NSString stringWithCString:common_name encoding:NSUTF8StringEncoding];
dialog.subject = [NSString stringWithCString:subject encoding:NSUTF8StringEncoding];
dialog.issuer = [NSString stringWithCString:issuer encoding:NSUTF8StringEncoding];
dialog.fingerprint = [NSString stringWithCString:fingerprint encoding:NSUTF8StringEncoding];
if (flags & VERIFY_CERT_FLAG_MISMATCH)
dialog.hostMismatch = TRUE;
if (flags & VERIFY_CERT_FLAG_CHANGED)
dialog.changed = TRUE;
2019-11-06 17:24:51 +03:00
[dialog performSelectorOnMainThread:@selector(runModal:)
withObject:[view window]
waitUntilDone:TRUE];
2018-11-29 19:23:09 +03:00
return dialog.result;
2018-11-29 18:29:07 +03:00
}
2019-11-06 17:24:51 +03:00
DWORD mac_verify_changed_certificate_ex(freerdp *instance, const char *host, UINT16 port,
const char *common_name, const char *subject,
const char *issuer, const char *fingerprint,
const char *old_subject, const char *old_issuer,
const char *old_fingerprint, DWORD flags)
2018-11-29 18:29:07 +03:00
{
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)instance->context;
MRDPView *view = (MRDPView *)mfc->view;
CertificateDialog *dialog = [CertificateDialog new];
const char *type = "RDP-Server";
char hostname[8192];
if (flags & VERIFY_CERT_FLAG_GATEWAY)
type = "RDP-Gateway";
if (flags & VERIFY_CERT_FLAG_REDIRECT)
type = "RDP-Redirect";
2019-11-06 17:24:51 +03:00
sprintf_s(hostname, sizeof(hostname), "%s %s:%" PRIu16, type, host, port);
2022-02-01 18:19:43 +03:00
dialog.serverHostname = [NSString stringWithCString:hostname encoding:NSUTF8StringEncoding];
2019-11-06 17:24:51 +03:00
dialog.commonName = [NSString stringWithCString:common_name encoding:NSUTF8StringEncoding];
dialog.subject = [NSString stringWithCString:subject encoding:NSUTF8StringEncoding];
dialog.issuer = [NSString stringWithCString:issuer encoding:NSUTF8StringEncoding];
dialog.fingerprint = [NSString stringWithCString:fingerprint encoding:NSUTF8StringEncoding];
if (flags & VERIFY_CERT_FLAG_MISMATCH)
dialog.hostMismatch = TRUE;
if (flags & VERIFY_CERT_FLAG_CHANGED)
dialog.changed = TRUE;
2019-11-06 17:24:51 +03:00
[dialog performSelectorOnMainThread:@selector(runModal:)
withObject:[view window]
waitUntilDone:TRUE];
return dialog.result;
2018-11-29 18:29:07 +03:00
}
2019-11-06 17:24:51 +03:00
int mac_logon_error_info(freerdp *instance, UINT32 data, UINT32 type)
2018-11-29 18:29:07 +03:00
{
2019-11-06 17:24:51 +03:00
const char *str_data = freerdp_get_logon_error_info_data(data);
const char *str_type = freerdp_get_logon_error_info_type(type);
2018-11-29 18:29:07 +03:00
// TODO: Error message dialog
WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type);
return 1;
}
2019-11-06 17:24:51 +03:00
BOOL mf_Pointer_New(rdpContext *context, rdpPointer *pointer)
{
2019-11-06 17:24:51 +03:00
rdpGdi *gdi;
2013-03-11 20:14:44 +04:00
NSRect rect;
2019-11-06 17:24:51 +03:00
NSImage *image;
2013-03-11 20:14:44 +04:00
NSPoint hotSpot;
2019-11-06 17:24:51 +03:00
NSCursor *cursor;
BYTE *cursor_data;
NSMutableArray *ma;
NSBitmapImageRep *bmiRep;
MRDPCursor *mrdpCursor = [[MRDPCursor alloc] init];
mfContext *mfc = (mfContext *)context;
MRDPView *view;
2016-10-04 10:00:00 +03:00
UINT32 format;
2016-08-03 16:29:24 +03:00
2016-10-04 10:00:00 +03:00
if (!mfc || !context || !pointer)
return FALSE;
2016-08-03 16:29:24 +03:00
2019-11-06 17:24:51 +03:00
view = (MRDPView *)mfc->view;
2016-10-04 10:00:00 +03:00
gdi = context->gdi;
2016-08-03 16:29:24 +03:00
2016-10-04 10:00:00 +03:00
if (!gdi || !view)
return FALSE;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
rect.size.width = pointer->width;
rect.size.height = pointer->height;
rect.origin.x = pointer->xPos;
rect.origin.y = pointer->yPos;
2019-11-06 17:24:51 +03:00
cursor_data = (BYTE *)malloc(rect.size.width * rect.size.height * 4);
2016-08-03 16:29:24 +03:00
if (!cursor_data)
return FALSE;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
mrdpCursor->cursor_data = cursor_data;
2016-10-04 10:00:00 +03:00
format = PIXEL_FORMAT_RGBA32;
2015-08-06 15:11:36 +03:00
2019-11-06 17:24:51 +03:00
if (!freerdp_image_copy_from_pointer_data(cursor_data, format, 0, 0, 0, pointer->width,
pointer->height, pointer->xorMaskData,
pointer->lengthXorMask, pointer->andMaskData,
pointer->lengthAndMask, pointer->xorBpp, NULL))
2015-08-06 15:11:36 +03:00
{
free(cursor_data);
mrdpCursor->cursor_data = NULL;
return FALSE;
}
2013-03-11 20:14:44 +04:00
/* store cursor bitmap image in representation - required by NSImage */
2019-11-06 17:24:51 +03:00
bmiRep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:(unsigned char **)&cursor_data
pixelsWide:rect.size.width
pixelsHigh:rect.size.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bitmapFormat:0
bytesPerRow:rect.size.width * GetBytesPerPixel(format)
bitsPerPixel:0];
2013-02-22 06:42:47 +04:00
mrdpCursor->bmiRep = bmiRep;
2013-03-11 20:14:44 +04:00
/* create an image using above representation */
image = [[NSImage alloc] initWithSize:[bmiRep size]];
2019-11-06 17:24:51 +03:00
[image addRepresentation:bmiRep];
2013-02-22 06:42:47 +04:00
mrdpCursor->nsImage = image;
2013-03-11 20:14:44 +04:00
/* need hotspot to create cursor */
2013-02-22 06:42:47 +04:00
hotSpot.x = pointer->xPos;
hotSpot.y = pointer->yPos;
2019-11-06 17:24:51 +03:00
cursor = [[NSCursor alloc] initWithImage:image hotSpot:hotSpot];
2013-02-22 06:42:47 +04:00
mrdpCursor->nsCursor = cursor;
mrdpCursor->pointer = pointer;
2013-03-11 20:14:44 +04:00
/* save cursor for later use in mf_Pointer_Set() */
ma = view->cursors;
2013-02-22 06:42:47 +04:00
[ma addObject:mrdpCursor];
return TRUE;
2013-02-22 06:42:47 +04:00
}
2019-11-06 17:24:51 +03:00
void mf_Pointer_Free(rdpContext *context, rdpPointer *pointer)
{
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)context;
MRDPView *view = (MRDPView *)mfc->view;
NSMutableArray *ma = view->cursors;
2016-08-03 16:29:24 +03:00
2019-11-06 17:24:51 +03:00
for (MRDPCursor *cursor in ma)
2013-02-22 06:42:47 +04:00
{
2013-02-22 07:04:09 +04:00
if (cursor->pointer == pointer)
{
2013-02-22 06:42:47 +04:00
cursor->nsImage = nil;
cursor->nsCursor = nil;
cursor->bmiRep = nil;
free(cursor->cursor_data);
[ma removeObject:cursor];
return;
}
}
}
2019-11-06 17:24:51 +03:00
BOOL mf_Pointer_Set(rdpContext *context, const rdpPointer *pointer)
{
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)context;
MRDPView *view = (MRDPView *)mfc->view;
NSMutableArray *ma = view->cursors;
2013-03-19 07:28:19 +04:00
2019-11-06 17:24:51 +03:00
for (MRDPCursor *cursor in ma)
2013-02-22 06:42:47 +04:00
{
2013-02-22 07:04:09 +04:00
if (cursor->pointer == pointer)
{
[view setCursor:cursor->nsCursor];
return TRUE;
2013-02-22 06:42:47 +04:00
}
}
NSLog(@"Cursor not found");
return TRUE;
}
2019-11-06 17:24:51 +03:00
BOOL mf_Pointer_SetNull(rdpContext *context)
{
return TRUE;
}
2019-11-06 17:24:51 +03:00
BOOL mf_Pointer_SetDefault(rdpContext *context)
{
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)context;
MRDPView *view = (MRDPView *)mfc->view;
[view setCursor:[NSCursor arrowCursor]];
return TRUE;
}
2019-11-06 17:24:51 +03:00
static BOOL mf_Pointer_SetPosition(rdpContext *context, UINT32 x, UINT32 y)
2017-11-09 12:22:16 +03:00
{
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)context;
2017-11-09 12:22:16 +03:00
if (!mfc)
return FALSE;
/* TODO: Set pointer position */
return TRUE;
}
2019-11-06 17:24:51 +03:00
CGContextRef mac_create_bitmap_context(rdpContext *context)
{
CGContextRef bitmap_context;
2019-11-06 17:24:51 +03:00
rdpGdi *gdi = context->gdi;
2016-08-03 16:29:24 +03:00
UINT32 bpp = GetBytesPerPixel(gdi->dstFormat);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
2016-08-03 16:29:24 +03:00
2016-08-01 19:14:17 +03:00
if (bpp == 2)
{
2019-11-06 17:24:51 +03:00
bitmap_context = CGBitmapContextCreate(
gdi->primary_buffer, gdi->width, gdi->height, 5, gdi->stride, colorSpace,
kCGBitmapByteOrder16Little | kCGImageAlphaNoneSkipFirst);
}
else
{
2019-11-06 17:24:51 +03:00
bitmap_context = CGBitmapContextCreate(
gdi->primary_buffer, gdi->width, gdi->height, 8, gdi->stride, colorSpace,
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst);
}
2016-08-03 16:29:24 +03:00
CGColorSpaceRelease(colorSpace);
return bitmap_context;
}
2019-11-06 17:24:51 +03:00
BOOL mac_begin_paint(rdpContext *context)
{
2019-11-06 17:24:51 +03:00
rdpGdi *gdi = context->gdi;
2016-08-03 16:29:24 +03:00
if (!gdi)
return FALSE;
2016-08-03 16:29:24 +03:00
2016-10-06 14:41:52 +03:00
gdi->primary->hdc->hwnd->invalid->null = TRUE;
return TRUE;
}
2019-11-06 17:24:51 +03:00
BOOL mac_end_paint(rdpContext *context)
{
2019-11-06 17:24:51 +03:00
rdpGdi *gdi;
2013-12-11 23:31:54 +04:00
HGDI_RGN invalid;
NSRect newDrawRect;
int ww, wh, dw, dh;
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)context;
MRDPView *view = (MRDPView *)mfc->view;
gdi = context->gdi;
2016-08-03 16:29:24 +03:00
if (!gdi)
return FALSE;
2016-08-03 16:29:24 +03:00
ww = mfc->client_width;
wh = mfc->client_height;
dw = mfc->common.context.settings->DesktopWidth;
dh = mfc->common.context.settings->DesktopHeight;
2013-12-11 23:31:54 +04:00
if ((!context) || (!context->gdi))
return FALSE;
2016-08-03 16:29:24 +03:00
2013-02-22 06:42:47 +04:00
if (context->gdi->primary->hdc->hwnd->invalid->null)
return TRUE;
2013-06-23 04:27:23 +04:00
2013-12-11 23:31:54 +04:00
invalid = gdi->primary->hdc->hwnd->invalid;
newDrawRect.origin.x = invalid->x;
newDrawRect.origin.y = invalid->y;
newDrawRect.size.width = invalid->w;
newDrawRect.size.height = invalid->h;
if (mfc->common.context.settings->SmartSizing && (ww != dw || wh != dh))
2013-12-11 23:31:54 +04:00
{
newDrawRect.origin.y = newDrawRect.origin.y * wh / dh - 1;
newDrawRect.size.height = newDrawRect.size.height * wh / dh + 1;
newDrawRect.origin.x = newDrawRect.origin.x * ww / dw - 1;
newDrawRect.size.width = newDrawRect.size.width * ww / dw + 1;
}
else
{
newDrawRect.origin.y = newDrawRect.origin.y - 1;
newDrawRect.size.height = newDrawRect.size.height + 1;
newDrawRect.origin.x = newDrawRect.origin.x - 1;
newDrawRect.size.width = newDrawRect.size.width + 1;
}
2013-12-11 23:31:54 +04:00
windows_to_apple_cords(mfc->view, &newDrawRect);
2019-11-06 17:24:51 +03:00
dispatch_sync(dispatch_get_main_queue(), ^{
[view setNeedsDisplayInRect:newDrawRect];
});
2013-02-22 06:42:47 +04:00
gdi->primary->hdc->hwnd->ninvalid = 0;
return TRUE;
}
2019-11-06 17:24:51 +03:00
BOOL mac_desktop_resize(rdpContext *context)
{
2015-11-05 19:57:47 +03:00
ResizeWindowEventArgs e;
2019-11-06 17:24:51 +03:00
mfContext *mfc = (mfContext *)context;
MRDPView *view = (MRDPView *)mfc->view;
rdpSettings *settings = context->settings;
2017-07-20 13:33:56 +03:00
if (!context->gdi)
return TRUE;
/**
* TODO: Fix resizing race condition. We should probably implement a message to be
* put on the update message queue to be able to properly flush pending updates,
* resize, and then continue with post-resizing graphical updates.
*/
CGContextRef old_context = view->bitmap_context;
view->bitmap_context = NULL;
CGContextRelease(old_context);
mfc->width = settings->DesktopWidth;
mfc->height = settings->DesktopHeight;
2016-08-03 16:29:24 +03:00
if (!gdi_resize(context->gdi, mfc->width, mfc->height))
return FALSE;
2016-08-03 16:29:24 +03:00
view->bitmap_context = mac_create_bitmap_context(context);
2016-08-03 16:29:24 +03:00
if (!view->bitmap_context)
return FALSE;
2016-08-03 16:29:24 +03:00
2015-11-05 19:57:47 +03:00
mfc->client_width = mfc->width;
mfc->client_height = mfc->height;
[view setFrameSize:NSMakeSize(mfc->width, mfc->height)];
EventArgsInit(&e, "mfreerdp");
e.width = settings->DesktopWidth;
e.height = settings->DesktopHeight;
PubSub_OnResizeWindow(context->pubSub, context, &e);
return TRUE;
}
2019-11-06 17:24:51 +03:00
void input_activity_cb(freerdp *instance)
{
2013-06-23 04:27:23 +04:00
int status;
wMessage message;
2019-11-06 17:24:51 +03:00
wMessageQueue *queue;
2013-06-23 04:27:23 +04:00
status = 1;
queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
2013-06-23 04:27:23 +04:00
if (queue)
{
while (MessageQueue_Peek(queue, &message, TRUE))
{
2019-11-06 17:24:51 +03:00
status = freerdp_message_queue_process_message(instance, FREERDP_INPUT_MESSAGE_QUEUE,
&message);
2013-06-23 04:27:23 +04:00
if (!status)
break;
}
}
else
{
2019-11-06 17:24:51 +03:00
WLog_ERR(TAG, "input_activity_cb: No queue!");
}
}
/**
* given a rect with 0,0 at the top left (windows cords)
* convert it to a rect with 0,0 at the bottom left (apple cords)
*
* Note: the formula works for conversions in both directions.
*
*/
2019-11-06 17:24:51 +03:00
void windows_to_apple_cords(MRDPView *view, NSRect *r)
{
2019-11-06 17:24:51 +03:00
dispatch_sync(dispatch_get_main_queue(), ^{
r->origin.y = [view frame].size.height - (r->origin.y + r->size.height);
});
}
2019-11-06 17:24:51 +03:00
void sync_keyboard_state(freerdp *instance)
2018-02-14 12:14:33 +03:00
{
2017-11-20 13:46:32 +03:00
UINT32 flags = 0;
CGEventFlags currentFlags = CGEventSourceFlagsState(kCGEventSourceStateHIDSystemState);
mfContext *context;
WINPR_ASSERT(instance);
context = (mfContext *)instance->context;
WINPR_ASSERT(context);
2017-11-20 13:46:32 +03:00
if (context->kbdFlags != currentFlags)
{
if (currentFlags & kCGEventFlagMaskAlphaShift)
flags |= KBD_SYNC_CAPS_LOCK;
if (currentFlags & kCGEventFlagMaskNumericPad)
flags |= KBD_SYNC_NUM_LOCK;
freerdp_input_send_synchronize_event(instance->context->input, flags);
2017-11-20 13:46:32 +03:00
context->kbdFlags = currentFlags;
}
}
@end