20 #include <freerdp/config.h>
28 #include <freerdp/client.h>
30 #include <freerdp/freerdp.h>
31 #include <freerdp/addin.h>
32 #include <freerdp/assistance.h>
33 #include <freerdp/client/file.h>
34 #include <freerdp/utils/passphrase.h>
35 #include <freerdp/client/cmdline.h>
36 #include <freerdp/client/channels.h>
37 #include <freerdp/utils/smartcardlogon.h>
39 #if defined(CHANNEL_AINPUT_CLIENT)
40 #include <freerdp/client/ainput.h>
41 #include <freerdp/channels/ainput.h>
44 #if defined(CHANNEL_VIDEO_CLIENT)
45 #include <freerdp/client/video.h>
46 #include <freerdp/channels/video.h>
49 #if defined(CHANNEL_RDPGFX_CLIENT)
50 #include <freerdp/client/rdpgfx.h>
51 #include <freerdp/channels/rdpgfx.h>
52 #include <freerdp/gdi/gfx.h>
55 #if defined(CHANNEL_GEOMETRY_CLIENT)
56 #include <freerdp/client/geometry.h>
57 #include <freerdp/channels/geometry.h>
60 #if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
61 #include <freerdp/gdi/video.h>
65 #include <freerdp/utils/http.h>
66 #include <freerdp/utils/aad.h>
69 #include <freerdp/log.h>
70 #define TAG CLIENT_TAG("common")
72 static void set_default_callbacks(freerdp* instance)
74 WINPR_ASSERT(instance);
75 instance->AuthenticateEx = client_cli_authenticate_ex;
76 instance->ChooseSmartcard = client_cli_choose_smartcard;
77 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
78 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
79 instance->PresentGatewayMessage = client_cli_present_gateway_message;
80 instance->LogonErrorInfo = client_cli_logon_error_info;
81 instance->GetAccessToken = client_cli_get_access_token;
82 instance->RetryDialog = client_common_retry_dialog;
85 static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
87 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
89 WINPR_ASSERT(instance);
90 WINPR_ASSERT(context);
92 instance->LoadChannels = freerdp_client_load_channels;
93 set_default_callbacks(instance);
95 pEntryPoints = instance->pClientEntryPoints;
96 WINPR_ASSERT(pEntryPoints);
97 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
100 static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
102 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
104 WINPR_ASSERT(instance);
105 WINPR_ASSERT(context);
107 pEntryPoints = instance->pClientEntryPoints;
108 WINPR_ASSERT(pEntryPoints);
109 IFCALL(pEntryPoints->ClientFree, instance, context);
114 rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
116 freerdp* instance = NULL;
117 rdpContext* context = NULL;
122 IFCALL(pEntryPoints->GlobalInit);
123 instance = freerdp_new();
128 instance->ContextSize = pEntryPoints->ContextSize;
129 instance->ContextNew = freerdp_client_common_new;
130 instance->ContextFree = freerdp_client_common_free;
131 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
133 if (!instance->pClientEntryPoints)
136 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
138 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
141 context = instance->context;
142 context->instance = instance;
144 #if defined(WITH_CHANNELS)
145 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
152 free(instance->pClientEntryPoints);
154 freerdp_free(instance);
158 void freerdp_client_context_free(rdpContext* context)
160 freerdp* instance = NULL;
165 instance = context->instance;
169 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
170 freerdp_context_free(instance);
173 IFCALL(pEntryPoints->GlobalUninit);
175 free(instance->pClientEntryPoints);
176 freerdp_free(instance);
180 int freerdp_client_start(rdpContext* context)
182 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
184 if (!context || !context->instance || !context->instance->pClientEntryPoints)
185 return ERROR_BAD_ARGUMENTS;
188 set_default_callbacks(context->instance);
190 pEntryPoints = context->instance->pClientEntryPoints;
191 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
194 int freerdp_client_stop(rdpContext* context)
196 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
198 if (!context || !context->instance || !context->instance->pClientEntryPoints)
199 return ERROR_BAD_ARGUMENTS;
201 pEntryPoints = context->instance->pClientEntryPoints;
202 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
205 freerdp* freerdp_client_get_instance(rdpContext* context)
207 if (!context || !context->instance)
210 return context->instance;
213 HANDLE freerdp_client_get_thread(rdpContext* context)
218 return ((rdpClientContext*)context)->thread;
221 static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
246 settings, FreeRDP_GatewayPassword,
286 int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
290 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown, NULL,
294 int freerdp_client_settings_parse_command_line_ex(
297 void* handle_userdata)
307 status = freerdp_client_settings_parse_command_line_arguments_ex(
308 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
315 if (!freerdp_client_settings_post_process(settings))
318 const char* name = (argc > 0) ? argv[0] :
"argc < 1";
319 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
320 freerdp_get_build_config());
324 int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
326 rdpFile* file = NULL;
328 file = freerdp_client_rdp_file_new();
333 if (!freerdp_client_parse_rdp_file(file, filename))
336 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
341 freerdp_client_rdp_file_free(file);
345 int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
348 rdpFile* file = NULL;
350 file = freerdp_client_rdp_file_new();
355 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
356 freerdp_client_populate_settings_from_rdp_file(file, settings))
361 freerdp_client_rdp_file_free(file);
365 int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
368 rdpFile* file = NULL;
370 file = freerdp_client_rdp_file_new();
375 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
378 if (!freerdp_client_write_rdp_file(file, filename, unicode))
383 freerdp_client_rdp_file_free(file);
387 int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
391 char* filename = NULL;
392 char* password = NULL;
393 rdpAssistanceFile* file = NULL;
395 if (!settings || !argv || (argc < 2))
400 for (
int x = 2; x < argc; x++)
402 const char* key = strstr(argv[x],
"assistance:");
405 password = strchr(key,
':') + 1;
408 file = freerdp_assistance_file_new();
413 status = freerdp_assistance_parse_file(file, filename, password);
418 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
423 freerdp_assistance_file_free(file);
440 static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
441 char** password,
char** domain)
443 static const size_t password_size = 512;
444 const char* auth[] = {
"Username: ",
"Domain: ",
"Password: " };
445 const char* authPin[] = {
"Username: ",
"Domain: ",
"Smartcard-Pin: " };
446 const char* gw[] = {
"GatewayUsername: ",
"GatewayDomain: ",
"GatewayPassword: " };
447 const char** prompt = NULL;
448 BOOL pinOnly = FALSE;
450 WINPR_ASSERT(instance);
451 WINPR_ASSERT(instance->context);
452 WINPR_ASSERT(instance->context->settings);
456 case AUTH_SMARTCARD_PIN:
474 if (!username || !password || !domain)
477 if (!*username && !pinOnly)
479 size_t username_size = 0;
480 printf(
"%s", prompt[0]);
481 (void)fflush(stdout);
483 if (freerdp_interruptible_get_line(instance->context, username, &username_size, stdin) < 0)
485 char ebuffer[256] = { 0 };
486 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
487 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
493 *username = StrSep(username,
"\r");
494 *username = StrSep(username,
"\n");
498 if (!*domain && !pinOnly)
500 size_t domain_size = 0;
501 printf(
"%s", prompt[1]);
502 (void)fflush(stdout);
504 if (freerdp_interruptible_get_line(instance->context, domain, &domain_size, stdin) < 0)
506 char ebuffer[256] = { 0 };
507 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
508 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
514 *domain = StrSep(domain,
"\r");
515 *domain = StrSep(domain,
"\n");
521 *password = calloc(password_size,
sizeof(
char));
526 const BOOL fromStdin =
528 if (freerdp_passphrase_read(instance->context, prompt[2], *password, password_size,
544 BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
545 rdp_auth_reason reason)
547 WINPR_ASSERT(instance);
548 WINPR_ASSERT(username);
549 WINPR_ASSERT(password);
550 WINPR_ASSERT(domain);
559 case AUTH_SMARTCARD_PIN:
560 if ((*username) && (*password))
571 return client_cli_authenticate_raw(instance, reason, username, password, domain);
574 BOOL client_cli_choose_smartcard(freerdp* instance,
SmartcardCertInfo** cert_list, DWORD count,
575 DWORD* choice, BOOL gateway)
577 unsigned long answer = 0;
580 printf(
"Multiple smartcards are available for use:\n");
581 for (DWORD i = 0; i < count; i++)
584 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
585 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
588 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
589 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
590 cert->issuer, cert->upn);
593 free(container_name);
598 char input[10] = { 0 };
600 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
601 gateway ?
"gateway authentication" :
"logon", count - 1);
602 (void)fflush(stdout);
603 if (!fgets(input, 10, stdin))
605 WLog_ERR(TAG,
"could not read from stdin");
609 answer = strtoul(input, &p, 10);
610 if ((*p ==
'\n' && p != input) && answer < count)
612 *choice = (UINT32)answer;
618 #if defined(WITH_FREERDP_DEPRECATED)
619 BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
623 WLog_INFO(TAG,
"Authentication via smartcard");
627 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
630 BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
632 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
636 static DWORD client_cli_accept_certificate(freerdp* instance)
640 WINPR_ASSERT(instance);
641 WINPR_ASSERT(instance->context);
643 const rdpSettings* settings = instance->context->settings;
644 WINPR_ASSERT(settings);
652 printf(
"Do you trust the above certificate? (Y/T/N) ");
653 (void)fflush(stdout);
654 answer = freerdp_interruptible_getc(instance->context, stdin);
656 if ((answer == EOF) || feof(stdin))
658 printf(
"\nError: Could not read answer from stdin.\n");
666 answer = freerdp_interruptible_getc(instance->context, stdin);
673 answer = freerdp_interruptible_getc(instance->context, stdin);
680 answer = freerdp_interruptible_getc(instance->context, stdin);
706 #if defined(WITH_FREERDP_DEPRECATED)
707 DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
708 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
710 WINPR_UNUSED(common_name);
711 WINPR_UNUSED(host_mismatch);
713 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
714 printf(
"Certificate details:\n");
715 printf(
"\tSubject: %s\n", subject);
716 printf(
"\tIssuer: %s\n", issuer);
717 printf(
"\tThumbprint: %s\n", fingerprint);
718 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
719 "the CA certificate in your certificate store, or the certificate has expired.\n"
720 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
721 return client_cli_accept_certificate(instance);
725 static char* client_cli_pem_cert(
const char* pem)
727 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
731 char* fp = freerdp_certificate_get_fingerprint(cert);
732 char* start = freerdp_certificate_get_validity(cert, TRUE);
733 char* end = freerdp_certificate_get_validity(cert, FALSE);
734 freerdp_certificate_free(cert);
738 winpr_asprintf(&str, &slen,
741 "\tThumbprint: %s\n",
764 DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
765 const char* common_name,
const char* subject,
766 const char* issuer,
const char* fingerprint, DWORD flags)
768 const char* type =
"RDP-Server";
770 WINPR_ASSERT(instance);
771 WINPR_ASSERT(instance->context);
772 WINPR_ASSERT(instance->context->settings);
774 if (flags & VERIFY_CERT_FLAG_GATEWAY)
775 type =
"RDP-Gateway";
777 if (flags & VERIFY_CERT_FLAG_REDIRECT)
778 type =
"RDP-Redirect";
780 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
781 printf(
"\tCommon Name: %s\n", common_name);
782 printf(
"\tSubject: %s\n", subject);
783 printf(
"\tIssuer: %s\n", issuer);
787 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
789 char* str = client_cli_pem_cert(fingerprint);
794 printf(
"\tThumbprint: %s\n", fingerprint);
796 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
797 "the CA certificate in your certificate store, or the certificate has expired.\n"
798 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
799 return client_cli_accept_certificate(instance);
817 #if defined(WITH_FREERDP_DEPRECATED)
818 DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
819 const char* subject,
const char* issuer,
820 const char* fingerprint,
const char* old_subject,
821 const char* old_issuer,
const char* old_fingerprint)
823 WINPR_UNUSED(common_name);
825 printf(
"WARNING: This callback is deprecated, migrate to "
826 "client_cli_verify_changed_certificate_ex\n");
827 printf(
"!!! Certificate has changed !!!\n");
829 printf(
"New Certificate details:\n");
830 printf(
"\tSubject: %s\n", subject);
831 printf(
"\tIssuer: %s\n", issuer);
832 printf(
"\tThumbprint: %s\n", fingerprint);
834 printf(
"Old Certificate details:\n");
835 printf(
"\tSubject: %s\n", old_subject);
836 printf(
"\tIssuer: %s\n", old_issuer);
837 printf(
"\tThumbprint: %s\n", old_fingerprint);
839 printf(
"The above X.509 certificate does not match the certificate used for previous "
841 "This may indicate that the certificate has been tampered with.\n"
842 "Please contact the administrator of the RDP server and clarify.\n");
843 return client_cli_accept_certificate(instance);
866 DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
867 const char* common_name,
const char* subject,
868 const char* issuer,
const char* fingerprint,
869 const char* old_subject,
const char* old_issuer,
870 const char* old_fingerprint, DWORD flags)
872 const char* type =
"RDP-Server";
874 WINPR_ASSERT(instance);
875 WINPR_ASSERT(instance->context);
876 WINPR_ASSERT(instance->context->settings);
878 if (flags & VERIFY_CERT_FLAG_GATEWAY)
879 type =
"RDP-Gateway";
881 if (flags & VERIFY_CERT_FLAG_REDIRECT)
882 type =
"RDP-Redirect";
884 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
886 printf(
"New Certificate details:\n");
887 printf(
"\tCommon Name: %s\n", common_name);
888 printf(
"\tSubject: %s\n", subject);
889 printf(
"\tIssuer: %s\n", issuer);
893 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
895 char* str = client_cli_pem_cert(fingerprint);
900 printf(
"\tThumbprint: %s\n", fingerprint);
902 printf(
"Old Certificate details:\n");
903 printf(
"\tSubject: %s\n", old_subject);
904 printf(
"\tIssuer: %s\n", old_issuer);
908 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
910 char* str = client_cli_pem_cert(old_fingerprint);
915 printf(
"\tThumbprint: %s\n", old_fingerprint);
917 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
919 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
920 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
921 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
922 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
925 printf(
"The above X.509 certificate does not match the certificate used for previous "
927 "This may indicate that the certificate has been tampered with.\n"
928 "Please contact the administrator of the RDP server and clarify.\n");
929 return client_cli_accept_certificate(instance);
932 BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
933 BOOL isConsentMandatory,
size_t length,
934 const WCHAR* message)
937 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
939 WINPR_ASSERT(instance);
940 WINPR_ASSERT(instance->context);
941 WINPR_ASSERT(instance->context->settings);
943 if (!isDisplayMandatory && !isConsentMandatory)
946 printf(
"%s:\n", msgType);
948 printf(
"%.*S\n", (
int)length, message);
951 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR), NULL);
954 printf(
"Failed to convert message!\n");
962 while (isConsentMandatory)
964 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
965 (void)fflush(stdout);
966 answer = freerdp_interruptible_getc(instance->context, stdin);
968 if ((answer == EOF) || feof(stdin))
970 printf(
"\nError: Could not read answer from stdin.\n");
978 answer = freerdp_interruptible_getc(instance->context, stdin);
985 (void)freerdp_interruptible_getc(instance->context, stdin);
998 static char* extract_authorization_code(
char* url)
1002 for (
char* p = strchr(url,
'?'); p++ != NULL; p = strchr(p,
'&'))
1004 if (strncmp(p,
"code=", 5) != 0)
1010 end = strchr(p,
'&');
1020 static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1021 const char* req_cnf,
char** token)
1025 char* token_request = NULL;
1026 const char* client_id =
"a85cf173-4192-42f8-81fa-777a763e6e2c";
1027 const char* redirect_uri =
1028 "https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient";
1030 WINPR_ASSERT(instance);
1031 WINPR_ASSERT(scope);
1032 WINPR_ASSERT(req_cnf);
1033 WINPR_ASSERT(token);
1037 printf(
"Browse to: https://login.microsoftonline.com/common/oauth2/v2.0/"
1038 "authorize?client_id=%s&response_type="
1039 "code&scope=%s&redirect_uri=%s"
1041 client_id, scope, redirect_uri);
1042 printf(
"Paste redirect URL here: \n");
1044 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1048 char* code = extract_authorization_code(url);
1052 if (winpr_asprintf(&token_request, &size,
1053 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%"
1055 code, client_id, scope, redirect_uri, req_cnf) <= 0)
1058 rc = client_common_get_access_token(instance, token_request, token);
1061 free(token_request);
1063 return rc && (*token != NULL);
1066 static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1070 char* token_request = NULL;
1071 const char* client_id =
"a85cf173-4192-42f8-81fa-777a763e6e2c";
1072 const char* redirect_uri =
1073 "https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient";
1074 const char* scope =
"https%3A%2F%2Fwww.wvd.microsoft.com%2F.default";
1076 WINPR_ASSERT(instance);
1077 WINPR_ASSERT(token);
1081 printf(
"Browse to: https://login.microsoftonline.com/common/oauth2/v2.0/"
1082 "authorize?client_id=%s&response_type="
1083 "code&scope=%s&redirect_uri=%s"
1085 client_id, scope, redirect_uri);
1086 printf(
"Paste redirect URL here: \n");
1088 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1092 char* code = extract_authorization_code(url);
1097 &token_request, &size,
1098 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s", code,
1099 client_id, scope, redirect_uri) <= 0)
1102 rc = client_common_get_access_token(instance, token_request, token);
1105 free(token_request);
1107 return rc && (*token != NULL);
1110 BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1113 WINPR_ASSERT(instance);
1114 WINPR_ASSERT(token);
1117 case ACCESS_TOKEN_TYPE_AAD:
1122 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1129 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1133 va_start(ap, count);
1134 const char* scope = va_arg(ap,
const char*);
1135 const char* req_cnf = va_arg(ap,
const char*);
1136 const BOOL rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1140 case ACCESS_TOKEN_TYPE_AVD:
1143 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1146 return client_cli_get_avd_access_token(instance, token);
1148 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%" PRIuz
"], aborting", tokenType);
1153 BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1156 WINPR_ASSERT(request);
1157 WINPR_ASSERT(token);
1161 BYTE* response = NULL;
1162 size_t response_length = 0;
1164 wLog* log = WLog_Get(TAG);
1166 if (!freerdp_http_request(
"https://login.microsoftonline.com/common/oauth2/v2.0/token", request,
1167 &resp_code, &response, &response_length))
1169 WLog_ERR(TAG,
"access token request failed");
1173 if (resp_code != HTTP_STATUS_OK)
1175 char buffer[64] = { 0 };
1177 WLog_Print(log, WLOG_ERROR,
1178 "Server unwilling to provide access token; returned status code %s",
1179 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1180 if (response_length > 0)
1181 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1185 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1197 SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1200 WINPR_UNUSED(instance);
1201 WINPR_ASSERT(instance->context);
1202 WINPR_UNUSED(userarg);
1203 WINPR_ASSERT(instance);
1206 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1208 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1214 if (strcmp(what,
"arm-transport") == 0)
1215 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1218 const rdpSettings* settings = instance->context->settings;
1222 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1231 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1232 "tech support for help if this keeps happening.",
1237 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1238 what, current, max, delay);
1242 BOOL client_auto_reconnect(freerdp* instance)
1244 return client_auto_reconnect_ex(instance, NULL);
1247 BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1251 UINT32 numRetries = 0;
1252 rdpSettings* settings = NULL;
1257 WINPR_ASSERT(instance->context);
1259 settings = instance->context->settings;
1260 WINPR_ASSERT(settings);
1262 const UINT32 maxRetries =
1266 error = freerdp_error_info(instance);
1269 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1271 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1272 freerdp_get_error_info_string(error));
1274 case ERRINFO_SUCCESS:
1276 WLog_INFO(TAG,
"Network disconnect!");
1288 switch (freerdp_get_last_error(instance->context))
1290 case FREERDP_ERROR_CONNECT_CANCELLED:
1291 WLog_WARN(TAG,
"Connection aborted by user");
1301 if ((maxRetries > 0) && (numRetries++ >= maxRetries))
1307 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1309 IFCALL(instance->RetryDialog, instance,
"connection", numRetries, NULL);
1311 if (freerdp_reconnect(instance))
1314 switch (freerdp_get_last_error(instance->context))
1316 case FREERDP_ERROR_CONNECT_CANCELLED:
1317 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1322 for (UINT32 x = 0; x < 50; x++)
1324 if (!IFCALLRESULT(TRUE, window_events, instance))
1331 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1335 int freerdp_client_common_stop(rdpContext* context)
1337 rdpClientContext* cctx = (rdpClientContext*)context;
1340 freerdp_abort_connect_context(&cctx->context);
1344 (void)WaitForSingleObject(cctx->thread, INFINITE);
1345 (void)CloseHandle(cctx->thread);
1346 cctx->thread = NULL;
1352 #if defined(CHANNEL_ENCOMSP_CLIENT)
1353 BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1355 rdpClientContext* cctx = NULL;
1361 cctx = (rdpClientContext*)encomsp->custom;
1363 state = cctx->controlToggle;
1364 cctx->controlToggle = !cctx->controlToggle;
1365 return freerdp_client_encomsp_set_control(encomsp, state);
1368 BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1375 pdu.ParticipantId = encomsp->participantId;
1376 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1379 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1381 encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1387 client_encomsp_participant_created(EncomspClientContext* context,
1390 rdpClientContext* cctx = NULL;
1391 rdpSettings* settings = NULL;
1394 if (!context || !context->custom || !participantCreated)
1395 return ERROR_INVALID_PARAMETER;
1397 cctx = (rdpClientContext*)context->custom;
1400 settings = cctx->context.settings;
1401 WINPR_ASSERT(settings);
1403 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1404 context->participantId = participantCreated->ParticipantId;
1407 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1408 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1410 if (!freerdp_client_encomsp_set_control(context, TRUE))
1411 return ERROR_INTERNAL_ERROR;
1417 return ERROR_INTERNAL_ERROR;
1420 return CHANNEL_RC_OK;
1423 static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1425 cctx->encomsp = encomsp;
1426 encomsp->custom = (
void*)cctx;
1427 encomsp->ParticipantCreated = client_encomsp_participant_created;
1430 static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1434 encomsp->custom = NULL;
1435 encomsp->ParticipantCreated = NULL;
1439 cctx->encomsp = NULL;
1443 void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1444 const ChannelConnectedEventArgs* e)
1446 rdpClientContext* cctx = (rdpClientContext*)context;
1454 #if defined(CHANNEL_AINPUT_CLIENT)
1455 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1456 cctx->ainput = (AInputClientContext*)e->pInterface;
1458 #
if defined(CHANNEL_RDPEI_CLIENT)
1459 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1461 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1464 #if defined(CHANNEL_RDPGFX_CLIENT)
1465 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1467 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1470 #if defined(CHANNEL_GEOMETRY_CLIENT)
1471 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1473 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1476 #if defined(CHANNEL_VIDEO_CLIENT)
1477 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1479 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1481 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1483 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1486 #if defined(CHANNEL_ENCOMSP_CLIENT)
1487 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1489 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1494 void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1495 const ChannelDisconnectedEventArgs* e)
1497 rdpClientContext* cctx = (rdpClientContext*)context;
1505 #if defined(CHANNEL_AINPUT_CLIENT)
1506 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1507 cctx->ainput = NULL;
1509 #if defined(CHANNEL_RDPEI_CLIENT)
1510 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1515 #if defined(CHANNEL_RDPGFX_CLIENT)
1516 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1518 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1521 #if defined(CHANNEL_GEOMETRY_CLIENT)
1522 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1524 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1527 #if defined(CHANNEL_VIDEO_CLIENT)
1528 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1530 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1532 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1534 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1537 #if defined(CHANNEL_ENCOMSP_CLIENT)
1538 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1540 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1545 BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1547 BOOL handled = FALSE;
1551 #if defined(CHANNEL_AINPUT_CLIENT)
1558 INT32 value = mflags & 0xFF;
1560 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1561 value = -1 * (0x100 - value);
1567 if (mflags & PTR_FLAGS_WHEEL)
1569 flags |= AINPUT_FLAGS_WHEEL;
1573 if (mflags & PTR_FLAGS_HWHEEL)
1575 flags |= AINPUT_FLAGS_WHEEL;
1579 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1580 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1581 if (rc == CHANNEL_RC_OK)
1587 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1592 #if defined(CHANNEL_AINPUT_CLIENT)
1593 static INLINE BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1598 WINPR_ASSERT(cctx->ainput);
1599 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1601 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1603 return rc == CHANNEL_RC_OK;
1607 BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1610 BOOL handled = FALSE;
1614 const BOOL haveRelative =
1616 if (relative && haveRelative)
1618 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags, x, y);
1621 #if defined(CHANNEL_AINPUT_CLIENT)
1626 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1627 flags |= AINPUT_FLAGS_HAVE_REL;
1630 flags |= AINPUT_FLAGS_REL;
1632 if (mflags & PTR_FLAGS_DOWN)
1633 flags |= AINPUT_FLAGS_DOWN;
1634 if (mflags & PTR_FLAGS_BUTTON1)
1635 flags |= AINPUT_FLAGS_BUTTON1;
1636 if (mflags & PTR_FLAGS_BUTTON2)
1637 flags |= AINPUT_FLAGS_BUTTON2;
1638 if (mflags & PTR_FLAGS_BUTTON3)
1639 flags |= AINPUT_FLAGS_BUTTON3;
1640 if (mflags & PTR_FLAGS_MOVE)
1641 flags |= AINPUT_FLAGS_MOVE;
1642 handled = ainput_send_diff_event(cctx, flags, x, y);
1652 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1659 freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1660 (UINT16)cctx->lastY);
1665 BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1668 BOOL handled = FALSE;
1671 const BOOL haveRelative =
1673 if (relative && haveRelative)
1675 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags, x, y);
1678 #if defined(CHANNEL_AINPUT_CLIENT)
1684 flags |= AINPUT_FLAGS_REL;
1685 if (mflags & PTR_XFLAGS_DOWN)
1686 flags |= AINPUT_FLAGS_DOWN;
1687 if (mflags & PTR_XFLAGS_BUTTON1)
1688 flags |= AINPUT_XFLAGS_BUTTON1;
1689 if (mflags & PTR_XFLAGS_BUTTON2)
1690 flags |= AINPUT_XFLAGS_BUTTON2;
1692 handled = ainput_send_diff_event(cctx, flags, x, y);
1702 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1709 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1710 (UINT16)cctx->lastY);
1716 static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1719 WINPR_ASSERT(contact);
1721 #if defined(CHANNEL_RDPEI_CLIENT)
1722 RdpeiClientContext* rdpei = cctx->rdpei;
1727 flags |= PTR_FLAGS_BUTTON1;
1729 WINPR_ASSERT(contact->x <= UINT16_MAX);
1730 WINPR_ASSERT(contact->y <= UINT16_MAX);
1731 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1737 if (rdpei->TouchRawEvent)
1739 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1740 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1741 ? CONTACT_DATA_PRESSURE_PRESENT
1744 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1745 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1746 RDPINPUT_CONTACT_FLAG_INCONTACT,
1747 contactFlags, contact->pressure);
1748 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1749 contactFlags, contact->pressure);
1753 WINPR_ASSERT(rdpei->TouchEnd);
1754 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1758 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1759 "-DWITH_CHANNELS=ON");
1765 static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1768 WINPR_ASSERT(contact);
1770 #if defined(CHANNEL_RDPEI_CLIENT)
1771 RdpeiClientContext* rdpei = cctx->rdpei;
1777 flags |= PTR_FLAGS_DOWN;
1778 flags |= PTR_FLAGS_MOVE;
1779 flags |= PTR_FLAGS_BUTTON1;
1781 WINPR_ASSERT(contact->x <= UINT16_MAX);
1782 WINPR_ASSERT(contact->y <= UINT16_MAX);
1783 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1789 if (rdpei->TouchRawEvent)
1791 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1792 RDPINPUT_CONTACT_FLAG_INCONTACT;
1793 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1794 ? CONTACT_DATA_PRESSURE_PRESENT
1796 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1797 contactFlags, contact->pressure);
1801 WINPR_ASSERT(rdpei->TouchBegin);
1802 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1806 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1807 "-DWITH_CHANNELS=ON");
1813 static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1816 WINPR_ASSERT(contact);
1818 #if defined(CHANNEL_RDPEI_CLIENT)
1819 RdpeiClientContext* rdpei = cctx->rdpei;
1824 flags |= PTR_FLAGS_MOVE;
1826 WINPR_ASSERT(contact->x <= UINT16_MAX);
1827 WINPR_ASSERT(contact->y <= UINT16_MAX);
1828 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1834 if (rdpei->TouchRawEvent)
1836 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1837 RDPINPUT_CONTACT_FLAG_INCONTACT;
1838 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1839 ? CONTACT_DATA_PRESSURE_PRESENT
1841 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1842 contactFlags, contact->pressure);
1846 WINPR_ASSERT(rdpei->TouchUpdate);
1847 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1851 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1852 "-DWITH_CHANNELS=ON");
1858 static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
1859 UINT32 pressure, INT32 x, INT32 y,
1863 WINPR_ASSERT(pcontact);
1865 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
1869 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
1870 if (newcontact || (contact->id == touchId))
1872 contact->id = touchId;
1873 contact->flags = flags;
1874 contact->pressure = pressure;
1878 *pcontact = *contact;
1880 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
1893 BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
1894 UINT32 pressure, INT32 x, INT32 y)
1896 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
1901 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
1904 switch (flags & mask)
1906 case FREERDP_TOUCH_DOWN:
1907 return freerdp_handle_touch_down(cctx, &contact);
1908 case FREERDP_TOUCH_UP:
1909 return freerdp_handle_touch_up(cctx, &contact);
1910 case FREERDP_TOUCH_MOTION:
1911 return freerdp_handle_touch_motion(cctx, &contact);
1913 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %d, ignoring", flags);
1918 BOOL freerdp_client_load_channels(freerdp* instance)
1920 WINPR_ASSERT(instance);
1921 WINPR_ASSERT(instance->context);
1923 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
1925 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
1931 int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
1933 const char* str_data = freerdp_get_logon_error_info_data(data);
1934 const char* str_type = freerdp_get_logon_error_info_type(type);
1936 if (!instance || !instance->context)
1939 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
1943 static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
1948 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
1951 if (deviceid == pen->deviceid)
1961 static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
1964 static const INT32 null_deviceid = 0;
1967 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
1968 if (freerdp_client_is_pen(cctx, deviceid))
1970 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
1981 pen->deviceid = deviceid;
1982 pen->max_pressure = pressure;
1985 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
1989 WLog_WARN(TAG,
"No free slots for an additiona pen device, skipping");
1993 BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
1995 if ((flags & FREERDP_PEN_REGISTER) != 0)
1999 va_start(args, deviceid);
2000 double pressure = va_arg(args,
double);
2002 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2008 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2012 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2014 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2016 RdpeiClientContext* rdpei = cctx->rdpei;
2017 WINPR_ASSERT(rdpei);
2019 UINT32 normalizedpressure = 1024;
2022 UINT16 rotation = 0;
2026 va_start(args, deviceid);
2028 x = va_arg(args, INT32);
2029 y = va_arg(args, INT32);
2030 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2032 const double pressure = va_arg(args,
double);
2033 const double np = (pressure * 1024.0) / pen->max_pressure;
2034 normalizedpressure = (UINT32)lround(np);
2035 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2036 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2038 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2040 rotation = va_arg(args,
unsigned);
2041 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2043 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2045 tiltX = va_arg(args,
int);
2046 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2048 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2050 tiltX = va_arg(args,
int);
2051 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2055 if ((flags & FREERDP_PEN_PRESS) != 0)
2059 flags = FREERDP_PEN_MOTION |
2060 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2061 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2062 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2064 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2066 if (!pen->pressed ||
2067 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2068 flags = FREERDP_PEN_MOTION |
2069 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2071 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2074 flags |= pen->flags;
2075 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2076 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2077 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2078 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2082 if ((flags & FREERDP_PEN_PRESS) != 0)
2084 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2085 pen->hovering = FALSE;
2086 pen->pressed = TRUE;
2088 WINPR_ASSERT(rdpei->PenBegin);
2089 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2090 normalizedpressure, rotation, tiltX, tiltY);
2091 return rc == CHANNEL_RC_OK;
2093 else if ((flags & FREERDP_PEN_MOTION) != 0)
2095 UINT rc = ERROR_INTERNAL_ERROR;
2098 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2101 WINPR_ASSERT(rdpei->PenUpdate);
2102 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2103 rotation, tiltX, tiltY);
2105 else if (pen->hovering)
2107 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2109 WINPR_ASSERT(rdpei->PenHoverUpdate);
2110 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2111 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2115 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2116 pen->hovering = TRUE;
2118 WINPR_ASSERT(rdpei->PenHoverBegin);
2119 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2120 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2122 return rc == CHANNEL_RC_OK;
2124 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2126 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2127 pen->pressed = FALSE;
2128 pen->hovering = TRUE;
2130 WINPR_ASSERT(rdpei->PenUpdate);
2131 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2132 normalizedpressure, rotation, tiltX, tiltY);
2133 if (rc != CHANNEL_RC_OK)
2135 WINPR_ASSERT(rdpei->PenEnd);
2136 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2137 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2138 return re == CHANNEL_RC_OK;
2141 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2145 BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2149 RdpeiClientContext* rdpei = cctx->rdpei;
2154 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2159 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2160 pen->hovering = FALSE;
2161 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2167 BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2174 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2177 if (pen->deviceid == deviceid)
2184 BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2186 WINPR_ASSERT(ccontext);
2188 const rdpSettings* settings = ccontext->context.settings;
2191 BOOL ainput = FALSE;
2192 #if defined(CHANNEL_AINPUT_CLIENT)
2193 ainput = ccontext->ainput != NULL;
2196 return useRelative && (haveRelative || ainput);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *param)
Sets a string settings value. The param is copied.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.