20 #include <winpr/cast.h>
22 #include <freerdp/config.h>
30 #include <freerdp/client.h>
32 #include <freerdp/freerdp.h>
33 #include <freerdp/addin.h>
34 #include <freerdp/assistance.h>
35 #include <freerdp/client/file.h>
36 #include <freerdp/utils/passphrase.h>
37 #include <freerdp/client/cmdline.h>
38 #include <freerdp/client/channels.h>
39 #include <freerdp/utils/smartcardlogon.h>
41 #if defined(CHANNEL_AINPUT_CLIENT)
42 #include <freerdp/client/ainput.h>
43 #include <freerdp/channels/ainput.h>
46 #if defined(CHANNEL_VIDEO_CLIENT)
47 #include <freerdp/client/video.h>
48 #include <freerdp/channels/video.h>
51 #if defined(CHANNEL_RDPGFX_CLIENT)
52 #include <freerdp/client/rdpgfx.h>
53 #include <freerdp/channels/rdpgfx.h>
54 #include <freerdp/gdi/gfx.h>
57 #if defined(CHANNEL_GEOMETRY_CLIENT)
58 #include <freerdp/client/geometry.h>
59 #include <freerdp/channels/geometry.h>
62 #if defined(CHANNEL_GEOMETRY_CLIENT) || defined(CHANNEL_VIDEO_CLIENT)
63 #include <freerdp/gdi/video.h>
67 #include <freerdp/utils/http.h>
68 #include <freerdp/utils/aad.h>
71 #include <freerdp/log.h>
72 #define TAG CLIENT_TAG("common")
74 static void set_default_callbacks(freerdp* instance)
76 WINPR_ASSERT(instance);
77 instance->AuthenticateEx = client_cli_authenticate_ex;
78 instance->ChooseSmartcard = client_cli_choose_smartcard;
79 instance->VerifyCertificateEx = client_cli_verify_certificate_ex;
80 instance->VerifyChangedCertificateEx = client_cli_verify_changed_certificate_ex;
81 instance->PresentGatewayMessage = client_cli_present_gateway_message;
82 instance->LogonErrorInfo = client_cli_logon_error_info;
83 instance->GetAccessToken = client_cli_get_access_token;
84 instance->RetryDialog = client_common_retry_dialog;
87 static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
89 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
91 WINPR_ASSERT(instance);
92 WINPR_ASSERT(context);
94 instance->LoadChannels = freerdp_client_load_channels;
95 set_default_callbacks(instance);
97 pEntryPoints = instance->pClientEntryPoints;
98 WINPR_ASSERT(pEntryPoints);
99 return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
102 static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
104 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
106 WINPR_ASSERT(instance);
107 WINPR_ASSERT(context);
109 pEntryPoints = instance->pClientEntryPoints;
110 WINPR_ASSERT(pEntryPoints);
111 IFCALL(pEntryPoints->ClientFree, instance, context);
116 rdpContext* freerdp_client_context_new(
const RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
118 freerdp* instance = NULL;
119 rdpContext* context = NULL;
124 IFCALL(pEntryPoints->GlobalInit);
125 instance = freerdp_new();
130 instance->ContextSize = pEntryPoints->ContextSize;
131 instance->ContextNew = freerdp_client_common_new;
132 instance->ContextFree = freerdp_client_common_free;
133 instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
135 if (!instance->pClientEntryPoints)
138 CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
140 if (!freerdp_context_new_ex(instance, pEntryPoints->settings))
143 context = instance->context;
144 context->instance = instance;
146 #if defined(WITH_CHANNELS)
147 if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
154 free(instance->pClientEntryPoints);
156 freerdp_free(instance);
160 void freerdp_client_context_free(rdpContext* context)
162 freerdp* instance = NULL;
167 instance = context->instance;
171 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
172 freerdp_context_free(instance);
175 IFCALL(pEntryPoints->GlobalUninit);
177 free(instance->pClientEntryPoints);
178 freerdp_free(instance);
182 int freerdp_client_start(rdpContext* context)
184 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
186 if (!context || !context->instance || !context->instance->pClientEntryPoints)
187 return ERROR_BAD_ARGUMENTS;
190 set_default_callbacks(context->instance);
192 pEntryPoints = context->instance->pClientEntryPoints;
193 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
196 int freerdp_client_stop(rdpContext* context)
198 RDP_CLIENT_ENTRY_POINTS* pEntryPoints = NULL;
200 if (!context || !context->instance || !context->instance->pClientEntryPoints)
201 return ERROR_BAD_ARGUMENTS;
203 pEntryPoints = context->instance->pClientEntryPoints;
204 return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
207 freerdp* freerdp_client_get_instance(rdpContext* context)
209 if (!context || !context->instance)
212 return context->instance;
215 HANDLE freerdp_client_get_thread(rdpContext* context)
220 return ((rdpClientContext*)context)->thread;
223 static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
248 settings, FreeRDP_GatewayPassword,
288 int freerdp_client_settings_parse_command_line(rdpSettings* settings,
int argc,
char** argv,
292 return freerdp_client_settings_parse_command_line_ex(settings, argc, argv, allowUnknown, NULL,
296 int freerdp_client_settings_parse_command_line_ex(
299 void* handle_userdata)
309 status = freerdp_client_settings_parse_command_line_arguments_ex(
310 settings, argc, argv, allowUnknown, args, count, handle_option, handle_userdata);
317 if (!freerdp_client_settings_post_process(settings))
320 const char* name = (argc > 0) ? argv[0] :
"argc < 1";
321 WLog_DBG(TAG,
"This is [%s] %s %s", name, freerdp_get_version_string(),
322 freerdp_get_build_config());
326 int freerdp_client_settings_parse_connection_file(rdpSettings* settings,
const char* filename)
328 rdpFile* file = NULL;
330 file = freerdp_client_rdp_file_new();
335 if (!freerdp_client_parse_rdp_file(file, filename))
338 if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
343 freerdp_client_rdp_file_free(file);
347 int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings,
const BYTE* buffer,
350 rdpFile* file = NULL;
352 file = freerdp_client_rdp_file_new();
357 if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
358 freerdp_client_populate_settings_from_rdp_file(file, settings))
363 freerdp_client_rdp_file_free(file);
367 int freerdp_client_settings_write_connection_file(
const rdpSettings* settings,
const char* filename,
370 rdpFile* file = NULL;
372 file = freerdp_client_rdp_file_new();
377 if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
380 if (!freerdp_client_write_rdp_file(file, filename, unicode))
385 freerdp_client_rdp_file_free(file);
389 int freerdp_client_settings_parse_assistance_file(rdpSettings* settings,
int argc,
char* argv[])
393 char* filename = NULL;
394 char* password = NULL;
395 rdpAssistanceFile* file = NULL;
397 if (!settings || !argv || (argc < 2))
402 for (
int x = 2; x < argc; x++)
404 const char* key = strstr(argv[x],
"assistance:");
407 password = strchr(key,
':') + 1;
410 file = freerdp_assistance_file_new();
415 status = freerdp_assistance_parse_file(file, filename, password);
420 if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
425 freerdp_assistance_file_free(file);
442 static BOOL client_cli_authenticate_raw(freerdp* instance, rdp_auth_reason reason,
char** username,
443 char** password,
char** domain)
445 static const size_t password_size = 512;
446 const char* auth[] = {
"Username: ",
"Domain: ",
"Password: " };
447 const char* authPin[] = {
"Username: ",
"Domain: ",
"Smartcard-Pin: " };
448 const char* gw[] = {
"GatewayUsername: ",
"GatewayDomain: ",
"GatewayPassword: " };
449 const char** prompt = NULL;
450 BOOL pinOnly = FALSE;
452 WINPR_ASSERT(instance);
453 WINPR_ASSERT(instance->context);
454 WINPR_ASSERT(instance->context->settings);
458 case AUTH_SMARTCARD_PIN:
476 if (!username || !password || !domain)
479 if (!*username && !pinOnly)
481 size_t username_size = 0;
482 printf(
"%s", prompt[0]);
483 (void)fflush(stdout);
485 if (freerdp_interruptible_get_line(instance->context, username, &username_size, stdin) < 0)
487 char ebuffer[256] = { 0 };
488 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
489 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
495 *username = StrSep(username,
"\r");
496 *username = StrSep(username,
"\n");
500 if (!*domain && !pinOnly)
502 size_t domain_size = 0;
503 printf(
"%s", prompt[1]);
504 (void)fflush(stdout);
506 if (freerdp_interruptible_get_line(instance->context, domain, &domain_size, stdin) < 0)
508 char ebuffer[256] = { 0 };
509 WLog_ERR(TAG,
"freerdp_interruptible_get_line returned %s [%d]",
510 winpr_strerror(errno, ebuffer,
sizeof(ebuffer)), errno);
516 *domain = StrSep(domain,
"\r");
517 *domain = StrSep(domain,
"\n");
523 *password = calloc(password_size,
sizeof(
char));
528 const BOOL fromStdin =
530 if (freerdp_passphrase_read(instance->context, prompt[2], *password, password_size,
546 BOOL client_cli_authenticate_ex(freerdp* instance,
char** username,
char** password,
char** domain,
547 rdp_auth_reason reason)
549 WINPR_ASSERT(instance);
550 WINPR_ASSERT(username);
551 WINPR_ASSERT(password);
552 WINPR_ASSERT(domain);
561 case AUTH_SMARTCARD_PIN:
562 if ((*username) && (*password))
573 return client_cli_authenticate_raw(instance, reason, username, password, domain);
576 BOOL client_cli_choose_smartcard(freerdp* instance,
SmartcardCertInfo** cert_list, DWORD count,
577 DWORD* choice, BOOL gateway)
579 unsigned long answer = 0;
582 printf(
"Multiple smartcards are available for use:\n");
583 for (DWORD i = 0; i < count; i++)
586 char* reader = ConvertWCharToUtf8Alloc(cert->reader, NULL);
587 char* container_name = ConvertWCharToUtf8Alloc(cert->containerName, NULL);
590 "] %s\n\tReader: %s\n\tUser: %s@%s\n\tSubject: %s\n\tIssuer: %s\n\tUPN: %s\n",
591 i, container_name, reader, cert->userHint, cert->domainHint, cert->subject,
592 cert->issuer, cert->upn);
595 free(container_name);
600 char input[10] = { 0 };
602 printf(
"\nChoose a smartcard to use for %s (0 - %" PRIu32
"): ",
603 gateway ?
"gateway authentication" :
"logon", count - 1);
604 (void)fflush(stdout);
605 if (!fgets(input, 10, stdin))
607 WLog_ERR(TAG,
"could not read from stdin");
611 answer = strtoul(input, &p, 10);
612 if ((*p ==
'\n' && p != input) && answer < count)
614 *choice = (UINT32)answer;
620 #if defined(WITH_FREERDP_DEPRECATED)
621 BOOL client_cli_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
625 WLog_INFO(TAG,
"Authentication via smartcard");
629 return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
632 BOOL client_cli_gw_authenticate(freerdp* instance,
char** username,
char** password,
char** domain)
634 return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
638 static DWORD client_cli_accept_certificate(freerdp* instance)
642 WINPR_ASSERT(instance);
643 WINPR_ASSERT(instance->context);
645 const rdpSettings* settings = instance->context->settings;
646 WINPR_ASSERT(settings);
654 printf(
"Do you trust the above certificate? (Y/T/N) ");
655 (void)fflush(stdout);
656 answer = freerdp_interruptible_getc(instance->context, stdin);
658 if ((answer == EOF) || feof(stdin))
660 printf(
"\nError: Could not read answer from stdin.\n");
668 answer = freerdp_interruptible_getc(instance->context, stdin);
675 answer = freerdp_interruptible_getc(instance->context, stdin);
682 answer = freerdp_interruptible_getc(instance->context, stdin);
708 #if defined(WITH_FREERDP_DEPRECATED)
709 DWORD client_cli_verify_certificate(freerdp* instance,
const char* common_name,
const char* subject,
710 const char* issuer,
const char* fingerprint, BOOL host_mismatch)
712 WINPR_UNUSED(common_name);
713 WINPR_UNUSED(host_mismatch);
715 printf(
"WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
716 printf(
"Certificate details:\n");
717 printf(
"\tSubject: %s\n", subject);
718 printf(
"\tIssuer: %s\n", issuer);
719 printf(
"\tThumbprint: %s\n", fingerprint);
720 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
721 "the CA certificate in your certificate store, or the certificate has expired.\n"
722 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
723 return client_cli_accept_certificate(instance);
727 static char* client_cli_pem_cert(
const char* pem)
729 rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
733 char* fp = freerdp_certificate_get_fingerprint(cert);
734 char* start = freerdp_certificate_get_validity(cert, TRUE);
735 char* end = freerdp_certificate_get_validity(cert, FALSE);
736 freerdp_certificate_free(cert);
740 winpr_asprintf(&str, &slen,
743 "\tThumbprint: %s\n",
766 DWORD client_cli_verify_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
767 const char* common_name,
const char* subject,
768 const char* issuer,
const char* fingerprint, DWORD flags)
770 const char* type =
"RDP-Server";
772 WINPR_ASSERT(instance);
773 WINPR_ASSERT(instance->context);
774 WINPR_ASSERT(instance->context->settings);
776 if (flags & VERIFY_CERT_FLAG_GATEWAY)
777 type =
"RDP-Gateway";
779 if (flags & VERIFY_CERT_FLAG_REDIRECT)
780 type =
"RDP-Redirect";
782 printf(
"Certificate details for %s:%" PRIu16
" (%s):\n", host, port, type);
783 printf(
"\tCommon Name: %s\n", common_name);
784 printf(
"\tSubject: %s\n", subject);
785 printf(
"\tIssuer: %s\n", issuer);
789 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
791 char* str = client_cli_pem_cert(fingerprint);
796 printf(
"\tThumbprint: %s\n", fingerprint);
798 printf(
"The above X.509 certificate could not be verified, possibly because you do not have\n"
799 "the CA certificate in your certificate store, or the certificate has expired.\n"
800 "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
801 return client_cli_accept_certificate(instance);
819 #if defined(WITH_FREERDP_DEPRECATED)
820 DWORD client_cli_verify_changed_certificate(freerdp* instance,
const char* common_name,
821 const char* subject,
const char* issuer,
822 const char* fingerprint,
const char* old_subject,
823 const char* old_issuer,
const char* old_fingerprint)
825 WINPR_UNUSED(common_name);
827 printf(
"WARNING: This callback is deprecated, migrate to "
828 "client_cli_verify_changed_certificate_ex\n");
829 printf(
"!!! Certificate has changed !!!\n");
831 printf(
"New Certificate details:\n");
832 printf(
"\tSubject: %s\n", subject);
833 printf(
"\tIssuer: %s\n", issuer);
834 printf(
"\tThumbprint: %s\n", fingerprint);
836 printf(
"Old Certificate details:\n");
837 printf(
"\tSubject: %s\n", old_subject);
838 printf(
"\tIssuer: %s\n", old_issuer);
839 printf(
"\tThumbprint: %s\n", old_fingerprint);
841 printf(
"The above X.509 certificate does not match the certificate used for previous "
843 "This may indicate that the certificate has been tampered with.\n"
844 "Please contact the administrator of the RDP server and clarify.\n");
845 return client_cli_accept_certificate(instance);
868 DWORD client_cli_verify_changed_certificate_ex(freerdp* instance,
const char* host, UINT16 port,
869 const char* common_name,
const char* subject,
870 const char* issuer,
const char* fingerprint,
871 const char* old_subject,
const char* old_issuer,
872 const char* old_fingerprint, DWORD flags)
874 const char* type =
"RDP-Server";
876 WINPR_ASSERT(instance);
877 WINPR_ASSERT(instance->context);
878 WINPR_ASSERT(instance->context->settings);
880 if (flags & VERIFY_CERT_FLAG_GATEWAY)
881 type =
"RDP-Gateway";
883 if (flags & VERIFY_CERT_FLAG_REDIRECT)
884 type =
"RDP-Redirect";
886 printf(
"!!!Certificate for %s:%" PRIu16
" (%s) has changed!!!\n", host, port, type);
888 printf(
"New Certificate details:\n");
889 printf(
"\tCommon Name: %s\n", common_name);
890 printf(
"\tSubject: %s\n", subject);
891 printf(
"\tIssuer: %s\n", issuer);
895 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
897 char* str = client_cli_pem_cert(fingerprint);
902 printf(
"\tThumbprint: %s\n", fingerprint);
904 printf(
"Old Certificate details:\n");
905 printf(
"\tSubject: %s\n", old_subject);
906 printf(
"\tIssuer: %s\n", old_issuer);
910 if (flags & VERIFY_CERT_FLAG_FP_IS_PEM)
912 char* str = client_cli_pem_cert(old_fingerprint);
917 printf(
"\tThumbprint: %s\n", old_fingerprint);
919 if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
921 printf(
"\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
922 printf(
"\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
923 printf(
"\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
924 printf(
"\tAll manually accepted certificates must be reconfirmed!\n");
927 printf(
"The above X.509 certificate does not match the certificate used for previous "
929 "This may indicate that the certificate has been tampered with.\n"
930 "Please contact the administrator of the RDP server and clarify.\n");
931 return client_cli_accept_certificate(instance);
934 BOOL client_cli_present_gateway_message(freerdp* instance, UINT32 type, BOOL isDisplayMandatory,
935 BOOL isConsentMandatory,
size_t length,
936 const WCHAR* message)
939 const char* msgType = (type == GATEWAY_MESSAGE_CONSENT) ?
"Consent message" :
"Service message";
941 WINPR_ASSERT(instance);
942 WINPR_ASSERT(instance->context);
943 WINPR_ASSERT(instance->context->settings);
945 if (!isDisplayMandatory && !isConsentMandatory)
948 printf(
"%s:\n", msgType);
950 printf(
"%.*S\n", (
int)length, message);
953 LPSTR msg = ConvertWCharNToUtf8Alloc(message, length /
sizeof(WCHAR), NULL);
956 printf(
"Failed to convert message!\n");
964 while (isConsentMandatory)
966 printf(
"I understand and agree to the terms of this policy (Y/N) \n");
967 (void)fflush(stdout);
968 answer = freerdp_interruptible_getc(instance->context, stdin);
970 if ((answer == EOF) || feof(stdin))
972 printf(
"\nError: Could not read answer from stdin.\n");
980 answer = freerdp_interruptible_getc(instance->context, stdin);
987 (void)freerdp_interruptible_getc(instance->context, stdin);
1000 static char* extract_authorization_code(
char* url)
1004 for (
char* p = strchr(url,
'?'); p++ != NULL; p = strchr(p,
'&'))
1006 if (strncmp(p,
"code=", 5) != 0)
1012 end = strchr(p,
'&');
1022 #if defined(WITH_AAD)
1023 static BOOL client_cli_get_rdsaad_access_token(freerdp* instance,
const char* scope,
1024 const char* req_cnf,
char** token)
1026 WINPR_ASSERT(instance);
1027 WINPR_ASSERT(instance->context);
1031 char* token_request = NULL;
1032 char* redirect_uri = NULL;
1033 size_t redirec_uri_len = 0;
1035 WINPR_ASSERT(scope);
1036 WINPR_ASSERT(req_cnf);
1037 WINPR_ASSERT(token);
1042 const char* client_id =
1047 winpr_asprintf(&redirect_uri, &redirec_uri_len,
1048 "ms-appx-web%%3a%%2f%%2fMicrosoft.AAD.BrokerPlugin%%2f%s", client_id);
1052 const char* ep = freerdp_utils_aad_get_wellknown_string(instance->context,
1053 AAD_WELLKNOWN_authorization_endpoint);
1054 printf(
"Browse to: %s?client_id=%s&response_type="
1055 "code&scope=%s&redirect_uri=%s"
1057 ep, client_id, scope, redirect_uri);
1058 printf(
"Paste redirect URL here: \n");
1060 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1063 char* code = extract_authorization_code(url);
1067 if (winpr_asprintf(&token_request, &size,
1068 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%"
1070 code, client_id, scope, redirect_uri, req_cnf) <= 0)
1073 rc = client_common_get_access_token(instance, token_request, token);
1077 free(token_request);
1079 return rc && (*token != NULL);
1082 static BOOL client_cli_get_avd_access_token(freerdp* instance,
char** token)
1084 WINPR_ASSERT(instance);
1085 WINPR_ASSERT(instance->context);
1089 char* token_request = NULL;
1090 char* redirect_uri = NULL;
1091 size_t redirec_uri_len = 0;
1092 const char* scope =
"https%3A%2F%2Fwww.wvd.microsoft.com%2F.default";
1094 WINPR_ASSERT(token);
1100 const char* client_id =
1103 FreeRDP_GatewayAzureActiveDirectory);
1104 const BOOL useTenant =
1106 const char* tenantid =
"common";
1110 if (!base || !tenantid || !client_id)
1113 winpr_asprintf(&redirect_uri, &redirec_uri_len,
1114 "https%%3A%%2F%%2F%s%%2F%s%%2Foauth2%%2Fnativeclient", base, tenantid);
1118 const char* ep = freerdp_utils_aad_get_wellknown_string(instance->context,
1119 AAD_WELLKNOWN_authorization_endpoint);
1120 printf(
"Browse to: %s?client_id=%s&response_type="
1121 "code&scope=%s&redirect_uri=%s"
1123 ep, client_id, scope, redirect_uri);
1124 printf(
"Paste redirect URL here: \n");
1126 if (freerdp_interruptible_get_line(instance->context, &url, &size, stdin) < 0)
1129 char* code = extract_authorization_code(url);
1134 &token_request, &size,
1135 "grant_type=authorization_code&code=%s&client_id=%s&scope=%s&redirect_uri=%s", code,
1136 client_id, scope, redirect_uri) <= 0)
1139 rc = client_common_get_access_token(instance, token_request, token);
1143 free(token_request);
1145 return rc && (*token != NULL);
1149 BOOL client_cli_get_access_token(freerdp* instance, AccessTokenType tokenType,
char** token,
1152 WINPR_ASSERT(instance);
1153 WINPR_ASSERT(token);
1155 #if !defined(WITH_AAD)
1156 WLog_ERR(TAG,
"Build does not support AAD authentication");
1161 case ACCESS_TOKEN_TYPE_AAD:
1166 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1173 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
1177 va_start(ap, count);
1178 const char* scope = va_arg(ap,
const char*);
1179 const char* req_cnf = va_arg(ap,
const char*);
1180 const BOOL rc = client_cli_get_rdsaad_access_token(instance, scope, req_cnf, token);
1184 case ACCESS_TOKEN_TYPE_AVD:
1187 "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
1190 return client_cli_get_avd_access_token(instance, token);
1192 WLog_ERR(TAG,
"Unexpected value for AccessTokenType [%" PRIuz
"], aborting", tokenType);
1198 BOOL client_common_get_access_token(freerdp* instance,
const char* request,
char** token)
1201 WINPR_ASSERT(request);
1202 WINPR_ASSERT(token);
1206 BYTE* response = NULL;
1207 size_t response_length = 0;
1209 wLog* log = WLog_Get(TAG);
1211 const char* token_ep =
1212 freerdp_utils_aad_get_wellknown_string(instance->context, AAD_WELLKNOWN_token_endpoint);
1213 if (!freerdp_http_request(token_ep, request, &resp_code, &response, &response_length))
1215 WLog_ERR(TAG,
"access token request failed");
1219 if (resp_code != HTTP_STATUS_OK)
1221 char buffer[64] = { 0 };
1223 WLog_Print(log, WLOG_ERROR,
1224 "Server unwilling to provide access token; returned status code %s",
1225 freerdp_http_status_string_format(resp_code, buffer,
sizeof(buffer)));
1226 if (response_length > 0)
1227 WLog_Print(log, WLOG_ERROR,
"[status message] %s", response);
1231 *token = freerdp_utils_aad_get_access_token(log, (
const char*)response, response_length);
1243 SSIZE_T client_common_retry_dialog(freerdp* instance,
const char* what,
size_t current,
1246 WINPR_UNUSED(instance);
1247 WINPR_ASSERT(instance->context);
1248 WINPR_UNUSED(userarg);
1249 WINPR_ASSERT(instance);
1252 if ((strcmp(what,
"arm-transport") != 0) && (strcmp(what,
"connection") != 0))
1254 WLog_ERR(TAG,
"Unknown module %s, aborting", what);
1260 if (strcmp(what,
"arm-transport") == 0)
1261 WLog_INFO(TAG,
"[%s] Starting your VM. It may take up to 5 minutes", what);
1264 const rdpSettings* settings = instance->context->settings;
1268 WLog_WARN(TAG,
"Automatic reconnection disabled, terminating. Try to connect again later");
1277 "[%s] retries exceeded. Your VM failed to start. Try again later or contact your "
1278 "tech support for help if this keeps happening.",
1283 WLog_INFO(TAG,
"[%s] retry %" PRIuz
"/%" PRIuz
", delaying %" PRIuz
"ms before next attempt",
1284 what, current, max, delay);
1285 return WINPR_ASSERTING_INT_CAST(SSIZE_T, delay);
1288 BOOL client_auto_reconnect(freerdp* instance)
1290 return client_auto_reconnect_ex(instance, NULL);
1293 BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
1297 UINT32 numRetries = 0;
1298 rdpSettings* settings = NULL;
1303 WINPR_ASSERT(instance->context);
1305 settings = instance->context->settings;
1306 WINPR_ASSERT(settings);
1308 const UINT32 maxRetries =
1312 error = freerdp_error_info(instance);
1315 case ERRINFO_GRAPHICS_SUBSYSTEM_FAILED:
1317 WLog_WARN(TAG,
"Disconnected by server hitting a bug or resource limit [%s]",
1318 freerdp_get_error_info_string(error));
1320 case ERRINFO_SUCCESS:
1322 WLog_INFO(TAG,
"Network disconnect!");
1334 switch (freerdp_get_last_error(instance->context))
1336 case FREERDP_ERROR_CONNECT_CANCELLED:
1337 WLog_WARN(TAG,
"Connection aborted by user");
1347 if ((maxRetries > 0) && (numRetries++ >= maxRetries))
1353 WLog_INFO(TAG,
"Attempting reconnect (%" PRIu32
" of %" PRIu32
")", numRetries, maxRetries);
1355 IFCALL(instance->RetryDialog, instance,
"connection", numRetries, NULL);
1357 if (freerdp_reconnect(instance))
1360 switch (freerdp_get_last_error(instance->context))
1362 case FREERDP_ERROR_CONNECT_CANCELLED:
1363 WLog_WARN(TAG,
"Autoreconnect aborted by user");
1368 for (UINT32 x = 0; x < 50; x++)
1370 if (!IFCALLRESULT(TRUE, window_events, instance))
1377 WLog_ERR(TAG,
"Maximum reconnect retries exceeded");
1381 int freerdp_client_common_stop(rdpContext* context)
1383 rdpClientContext* cctx = (rdpClientContext*)context;
1386 freerdp_abort_connect_context(&cctx->context);
1390 (void)WaitForSingleObject(cctx->thread, INFINITE);
1391 (void)CloseHandle(cctx->thread);
1392 cctx->thread = NULL;
1398 #if defined(CHANNEL_ENCOMSP_CLIENT)
1399 BOOL freerdp_client_encomsp_toggle_control(EncomspClientContext* encomsp)
1401 rdpClientContext* cctx = NULL;
1407 cctx = (rdpClientContext*)encomsp->custom;
1409 state = cctx->controlToggle;
1410 cctx->controlToggle = !cctx->controlToggle;
1411 return freerdp_client_encomsp_set_control(encomsp, state);
1414 BOOL freerdp_client_encomsp_set_control(EncomspClientContext* encomsp, BOOL control)
1421 pdu.ParticipantId = encomsp->participantId;
1422 pdu.Flags = ENCOMSP_REQUEST_VIEW;
1425 pdu.Flags |= ENCOMSP_REQUEST_INTERACT;
1427 encomsp->ChangeParticipantControlLevel(encomsp, &pdu);
1433 client_encomsp_participant_created(EncomspClientContext* context,
1436 rdpClientContext* cctx = NULL;
1437 rdpSettings* settings = NULL;
1440 if (!context || !context->custom || !participantCreated)
1441 return ERROR_INVALID_PARAMETER;
1443 cctx = (rdpClientContext*)context->custom;
1446 settings = cctx->context.settings;
1447 WINPR_ASSERT(settings);
1449 if (participantCreated->Flags & ENCOMSP_IS_PARTICIPANT)
1450 context->participantId = participantCreated->ParticipantId;
1453 if (request && (participantCreated->Flags & ENCOMSP_MAY_VIEW) &&
1454 !(participantCreated->Flags & ENCOMSP_MAY_INTERACT))
1456 if (!freerdp_client_encomsp_set_control(context, TRUE))
1457 return ERROR_INTERNAL_ERROR;
1463 return ERROR_INTERNAL_ERROR;
1466 return CHANNEL_RC_OK;
1469 static void client_encomsp_init(rdpClientContext* cctx, EncomspClientContext* encomsp)
1471 cctx->encomsp = encomsp;
1472 encomsp->custom = (
void*)cctx;
1473 encomsp->ParticipantCreated = client_encomsp_participant_created;
1476 static void client_encomsp_uninit(rdpClientContext* cctx, EncomspClientContext* encomsp)
1480 encomsp->custom = NULL;
1481 encomsp->ParticipantCreated = NULL;
1485 cctx->encomsp = NULL;
1489 void freerdp_client_OnChannelConnectedEventHandler(
void* context,
1490 const ChannelConnectedEventArgs* e)
1492 rdpClientContext* cctx = (rdpClientContext*)context;
1500 #if defined(CHANNEL_AINPUT_CLIENT)
1501 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1502 cctx->ainput = (AInputClientContext*)e->pInterface;
1504 #
if defined(CHANNEL_RDPEI_CLIENT)
1505 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1507 cctx->rdpei = (RdpeiClientContext*)e->pInterface;
1510 #if defined(CHANNEL_RDPGFX_CLIENT)
1511 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1513 gdi_graphics_pipeline_init(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1516 #if defined(CHANNEL_GEOMETRY_CLIENT)
1517 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1519 gdi_video_geometry_init(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1522 #if defined(CHANNEL_VIDEO_CLIENT)
1523 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1525 gdi_video_control_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1527 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1529 gdi_video_data_init(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1532 #if defined(CHANNEL_ENCOMSP_CLIENT)
1533 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1535 client_encomsp_init(cctx, (EncomspClientContext*)e->pInterface);
1540 void freerdp_client_OnChannelDisconnectedEventHandler(
void* context,
1541 const ChannelDisconnectedEventArgs* e)
1543 rdpClientContext* cctx = (rdpClientContext*)context;
1551 #if defined(CHANNEL_AINPUT_CLIENT)
1552 else if (strcmp(e->name, AINPUT_DVC_CHANNEL_NAME) == 0)
1553 cctx->ainput = NULL;
1555 #if defined(CHANNEL_RDPEI_CLIENT)
1556 else if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
1561 #if defined(CHANNEL_RDPGFX_CLIENT)
1562 else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
1564 gdi_graphics_pipeline_uninit(cctx->context.gdi, (RdpgfxClientContext*)e->pInterface);
1567 #if defined(CHANNEL_GEOMETRY_CLIENT)
1568 else if (strcmp(e->name, GEOMETRY_DVC_CHANNEL_NAME) == 0)
1570 gdi_video_geometry_uninit(cctx->context.gdi, (GeometryClientContext*)e->pInterface);
1573 #if defined(CHANNEL_VIDEO_CLIENT)
1574 else if (strcmp(e->name, VIDEO_CONTROL_DVC_CHANNEL_NAME) == 0)
1576 gdi_video_control_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1578 else if (strcmp(e->name, VIDEO_DATA_DVC_CHANNEL_NAME) == 0)
1580 gdi_video_data_uninit(cctx->context.gdi, (VideoClientContext*)e->pInterface);
1583 #if defined(CHANNEL_ENCOMSP_CLIENT)
1584 else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0)
1586 client_encomsp_uninit(cctx, (EncomspClientContext*)e->pInterface);
1591 BOOL freerdp_client_send_wheel_event(rdpClientContext* cctx, UINT16 mflags)
1593 BOOL handled = FALSE;
1597 #if defined(CHANNEL_AINPUT_CLIENT)
1604 INT32 value = mflags & 0xFF;
1606 if (mflags & PTR_FLAGS_WHEEL_NEGATIVE)
1607 value = -1 * (0x100 - value);
1613 if (mflags & PTR_FLAGS_WHEEL)
1615 flags |= AINPUT_FLAGS_WHEEL;
1619 if (mflags & PTR_FLAGS_HWHEEL)
1621 flags |= AINPUT_FLAGS_WHEEL;
1625 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1626 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1627 if (rc == CHANNEL_RC_OK)
1633 freerdp_input_send_mouse_event(cctx->context.input, mflags, 0, 0);
1638 #if defined(CHANNEL_AINPUT_CLIENT)
1639 static INLINE BOOL ainput_send_diff_event(rdpClientContext* cctx, UINT64 flags, INT32 x, INT32 y)
1644 WINPR_ASSERT(cctx->ainput);
1645 WINPR_ASSERT(cctx->ainput->AInputSendInputEvent);
1647 rc = cctx->ainput->AInputSendInputEvent(cctx->ainput, flags, x, y);
1649 return rc == CHANNEL_RC_OK;
1653 BOOL freerdp_client_send_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags, INT32 x,
1656 BOOL handled = FALSE;
1660 const BOOL haveRelative =
1662 if (relative && haveRelative)
1664 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1665 WINPR_ASSERTING_INT_CAST(int16_t, x),
1666 WINPR_ASSERTING_INT_CAST(int16_t, y));
1669 #if defined(CHANNEL_AINPUT_CLIENT)
1674 if (cctx->mouse_grabbed && freerdp_client_use_relative_mouse_events(cctx))
1675 flags |= AINPUT_FLAGS_HAVE_REL;
1678 flags |= AINPUT_FLAGS_REL;
1680 if (mflags & PTR_FLAGS_DOWN)
1681 flags |= AINPUT_FLAGS_DOWN;
1682 if (mflags & PTR_FLAGS_BUTTON1)
1683 flags |= AINPUT_FLAGS_BUTTON1;
1684 if (mflags & PTR_FLAGS_BUTTON2)
1685 flags |= AINPUT_FLAGS_BUTTON2;
1686 if (mflags & PTR_FLAGS_BUTTON3)
1687 flags |= AINPUT_FLAGS_BUTTON3;
1688 if (mflags & PTR_FLAGS_MOVE)
1689 flags |= AINPUT_FLAGS_MOVE;
1690 handled = ainput_send_diff_event(cctx, flags, x, y);
1700 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1707 freerdp_input_send_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1708 (UINT16)cctx->lastY);
1713 BOOL freerdp_client_send_extended_button_event(rdpClientContext* cctx, BOOL relative, UINT16 mflags,
1716 BOOL handled = FALSE;
1719 const BOOL haveRelative =
1721 if (relative && haveRelative)
1723 return freerdp_input_send_rel_mouse_event(cctx->context.input, mflags,
1724 WINPR_ASSERTING_INT_CAST(int16_t, x),
1725 WINPR_ASSERTING_INT_CAST(int16_t, y));
1728 #if defined(CHANNEL_AINPUT_CLIENT)
1734 flags |= AINPUT_FLAGS_REL;
1735 if (mflags & PTR_XFLAGS_DOWN)
1736 flags |= AINPUT_FLAGS_DOWN;
1737 if (mflags & PTR_XFLAGS_BUTTON1)
1738 flags |= AINPUT_XFLAGS_BUTTON1;
1739 if (mflags & PTR_XFLAGS_BUTTON2)
1740 flags |= AINPUT_XFLAGS_BUTTON2;
1742 handled = ainput_send_diff_event(cctx, flags, x, y);
1752 WLog_WARN(TAG,
"Relative mouse input channel not available, sending absolute!");
1759 freerdp_input_send_extended_mouse_event(cctx->context.input, mflags, (UINT16)cctx->lastX,
1760 (UINT16)cctx->lastY);
1766 static BOOL freerdp_handle_touch_up(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1769 WINPR_ASSERT(contact);
1771 #if defined(CHANNEL_RDPEI_CLIENT)
1772 RdpeiClientContext* rdpei = cctx->rdpei;
1777 flags |= PTR_FLAGS_BUTTON1;
1779 WINPR_ASSERT(contact->x <= UINT16_MAX);
1780 WINPR_ASSERT(contact->y <= UINT16_MAX);
1781 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1787 if (rdpei->TouchRawEvent)
1789 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UP;
1790 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1791 ? CONTACT_DATA_PRESSURE_PRESENT
1794 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId,
1795 RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1796 RDPINPUT_CONTACT_FLAG_INCONTACT,
1797 contactFlags, contact->pressure);
1798 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1799 contactFlags, contact->pressure);
1803 WINPR_ASSERT(rdpei->TouchEnd);
1804 rdpei->TouchEnd(rdpei, contact->id, contact->x, contact->y, &contactId);
1808 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1809 "-DWITH_CHANNELS=ON");
1815 static BOOL freerdp_handle_touch_down(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1818 WINPR_ASSERT(contact);
1820 #if defined(CHANNEL_RDPEI_CLIENT)
1821 RdpeiClientContext* rdpei = cctx->rdpei;
1827 flags |= PTR_FLAGS_DOWN;
1828 flags |= PTR_FLAGS_MOVE;
1829 flags |= PTR_FLAGS_BUTTON1;
1831 WINPR_ASSERT(contact->x <= UINT16_MAX);
1832 WINPR_ASSERT(contact->y <= UINT16_MAX);
1833 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1839 if (rdpei->TouchRawEvent)
1841 const UINT32 flags = RDPINPUT_CONTACT_FLAG_DOWN | RDPINPUT_CONTACT_FLAG_INRANGE |
1842 RDPINPUT_CONTACT_FLAG_INCONTACT;
1843 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1844 ? CONTACT_DATA_PRESSURE_PRESENT
1846 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1847 contactFlags, contact->pressure);
1851 WINPR_ASSERT(rdpei->TouchBegin);
1852 rdpei->TouchBegin(rdpei, contact->id, contact->x, contact->y, &contactId);
1856 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1857 "-DWITH_CHANNELS=ON");
1863 static BOOL freerdp_handle_touch_motion(rdpClientContext* cctx,
const FreeRDP_TouchContact* contact)
1866 WINPR_ASSERT(contact);
1868 #if defined(CHANNEL_RDPEI_CLIENT)
1869 RdpeiClientContext* rdpei = cctx->rdpei;
1874 flags |= PTR_FLAGS_MOVE;
1876 WINPR_ASSERT(contact->x <= UINT16_MAX);
1877 WINPR_ASSERT(contact->y <= UINT16_MAX);
1878 return freerdp_client_send_button_event(cctx, FALSE, flags, contact->x, contact->y);
1884 if (rdpei->TouchRawEvent)
1886 const UINT32 flags = RDPINPUT_CONTACT_FLAG_UPDATE | RDPINPUT_CONTACT_FLAG_INRANGE |
1887 RDPINPUT_CONTACT_FLAG_INCONTACT;
1888 const UINT32 contactFlags = ((contact->flags & FREERDP_TOUCH_HAS_PRESSURE) != 0)
1889 ? CONTACT_DATA_PRESSURE_PRESENT
1891 rdpei->TouchRawEvent(rdpei, contact->id, contact->x, contact->y, &contactId, flags,
1892 contactFlags, contact->pressure);
1896 WINPR_ASSERT(rdpei->TouchUpdate);
1897 rdpei->TouchUpdate(rdpei, contact->id, contact->x, contact->y, &contactId);
1901 WLog_WARN(TAG,
"Touch event detected but RDPEI support not compiled in. Recompile with "
1902 "-DWITH_CHANNELS=ON");
1908 static BOOL freerdp_client_touch_update(rdpClientContext* cctx, UINT32 flags, INT32 touchId,
1909 UINT32 pressure, INT32 x, INT32 y,
1913 WINPR_ASSERT(pcontact);
1915 for (
size_t i = 0; i < ARRAYSIZE(cctx->contacts); i++)
1919 const BOOL newcontact = ((contact->id == 0) && ((flags & FREERDP_TOUCH_DOWN) != 0));
1920 if (newcontact || (contact->id == touchId))
1922 contact->id = touchId;
1923 contact->flags = flags;
1924 contact->pressure = pressure;
1928 *pcontact = *contact;
1930 const BOOL resetcontact = (flags & FREERDP_TOUCH_UP) != 0;
1943 BOOL freerdp_client_handle_touch(rdpClientContext* cctx, UINT32 flags, INT32 finger,
1944 UINT32 pressure, INT32 x, INT32 y)
1946 const UINT32 mask = FREERDP_TOUCH_DOWN | FREERDP_TOUCH_UP | FREERDP_TOUCH_MOTION;
1951 if (!freerdp_client_touch_update(cctx, flags, finger, pressure, x, y, &contact))
1954 switch (flags & mask)
1956 case FREERDP_TOUCH_DOWN:
1957 return freerdp_handle_touch_down(cctx, &contact);
1958 case FREERDP_TOUCH_UP:
1959 return freerdp_handle_touch_up(cctx, &contact);
1960 case FREERDP_TOUCH_MOTION:
1961 return freerdp_handle_touch_motion(cctx, &contact);
1963 WLog_WARN(TAG,
"Unhandled FreeRDPTouchEventType %d, ignoring", flags);
1968 BOOL freerdp_client_load_channels(freerdp* instance)
1970 WINPR_ASSERT(instance);
1971 WINPR_ASSERT(instance->context);
1973 if (!freerdp_client_load_addins(instance->context->channels, instance->context->settings))
1975 WLog_ERR(TAG,
"Failed to load addins [%08" PRIx32
"]", GetLastError());
1981 int client_cli_logon_error_info(freerdp* instance, UINT32 data, UINT32 type)
1983 const char* str_data = freerdp_get_logon_error_info_data(data);
1984 const char* str_type = freerdp_get_logon_error_info_type(type);
1986 if (!instance || !instance->context)
1989 WLog_INFO(TAG,
"Logon Error Info %s [%s]", str_data, str_type);
1993 static FreeRDP_PenDevice* freerdp_client_get_pen(rdpClientContext* cctx, INT32 deviceid,
1998 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2001 if (deviceid == pen->deviceid)
2011 static BOOL freerdp_client_register_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid,
2014 static const INT32 null_deviceid = 0;
2017 WINPR_ASSERT((flags & FREERDP_PEN_REGISTER) != 0);
2018 if (freerdp_client_is_pen(cctx, deviceid))
2020 WLog_WARN(TAG,
"trying to double register pen device %" PRId32, deviceid);
2031 pen->deviceid = deviceid;
2032 pen->max_pressure = pressure;
2035 WLog_DBG(TAG,
"registered pen at index %" PRIuz, pos);
2039 WLog_WARN(TAG,
"No free slot for an additional pen device, skipping");
2043 BOOL freerdp_client_handle_pen(rdpClientContext* cctx, UINT32 flags, INT32 deviceid, ...)
2045 if ((flags & FREERDP_PEN_REGISTER) != 0)
2049 va_start(args, deviceid);
2050 double pressure = va_arg(args,
double);
2052 return freerdp_client_register_pen(cctx, flags, deviceid, pressure);
2058 WLog_WARN(TAG,
"unregistered pen device %" PRId32
" event 0x%08" PRIx32, deviceid, flags);
2062 UINT32 fieldFlags = RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT;
2064 ((pen->flags & FREERDP_PEN_IS_INVERTED) != 0) ? RDPINPUT_PEN_FLAG_INVERTED : 0;
2066 RdpeiClientContext* rdpei = cctx->rdpei;
2067 WINPR_ASSERT(rdpei);
2069 UINT32 normalizedpressure = 1024;
2072 UINT16 rotation = 0;
2076 va_start(args, deviceid);
2078 x = va_arg(args, INT32);
2079 y = va_arg(args, INT32);
2080 if ((flags & FREERDP_PEN_HAS_PRESSURE) != 0)
2082 const double pressure = va_arg(args,
double);
2083 const double np = (pressure * 1024.0) / pen->max_pressure;
2084 normalizedpressure = (UINT32)lround(np);
2085 WLog_DBG(TAG,
"pen pressure %lf -> %" PRIu32, pressure, normalizedpressure);
2086 fieldFlags |= RDPINPUT_PEN_CONTACT_PRESSURE_PRESENT;
2088 if ((flags & FREERDP_PEN_HAS_ROTATION) != 0)
2090 const unsigned arg = va_arg(args,
unsigned);
2091 rotation = WINPR_ASSERTING_INT_CAST(UINT16, arg);
2092 fieldFlags |= RDPINPUT_PEN_CONTACT_ROTATION_PRESENT;
2094 if ((flags & FREERDP_PEN_HAS_TILTX) != 0)
2096 const int arg = va_arg(args,
int);
2097 tiltX = WINPR_ASSERTING_INT_CAST(INT16, arg);
2098 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTX_PRESENT;
2100 if ((flags & FREERDP_PEN_HAS_TILTY) != 0)
2102 const int arg = va_arg(args,
int);
2103 tiltY = WINPR_ASSERTING_INT_CAST(INT16, arg);
2104 fieldFlags |= RDPINPUT_PEN_CONTACT_TILTY_PRESENT;
2108 if ((flags & FREERDP_PEN_PRESS) != 0)
2112 flags = FREERDP_PEN_MOTION |
2113 (flags & (UINT32) ~(FREERDP_PEN_PRESS | FREERDP_PEN_BARREL_PRESSED));
2114 else if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2115 pen->flags |= FREERDP_PEN_BARREL_PRESSED;
2117 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2119 if (!pen->pressed ||
2120 ((flags & FREERDP_PEN_BARREL_PRESSED) ^ (pen->flags & FREERDP_PEN_BARREL_PRESSED)))
2121 flags = FREERDP_PEN_MOTION |
2122 (flags & (UINT32) ~(FREERDP_PEN_RELEASE | FREERDP_PEN_BARREL_PRESSED));
2124 pen->flags &= (UINT32)~FREERDP_PEN_BARREL_PRESSED;
2127 flags |= pen->flags;
2128 if ((flags & FREERDP_PEN_ERASER_PRESSED) != 0)
2129 penFlags |= RDPINPUT_PEN_FLAG_ERASER_PRESSED;
2130 if ((flags & FREERDP_PEN_BARREL_PRESSED) != 0)
2131 penFlags |= RDPINPUT_PEN_FLAG_BARREL_PRESSED;
2135 if ((flags & FREERDP_PEN_PRESS) != 0)
2137 WLog_DBG(TAG,
"Pen press %" PRId32, deviceid);
2138 pen->hovering = FALSE;
2139 pen->pressed = TRUE;
2141 WINPR_ASSERT(rdpei->PenBegin);
2142 const UINT rc = rdpei->PenBegin(rdpei, deviceid, fieldFlags, x, y, penFlags,
2143 normalizedpressure, rotation, tiltX, tiltY);
2144 return rc == CHANNEL_RC_OK;
2146 else if ((flags & FREERDP_PEN_MOTION) != 0)
2148 UINT rc = ERROR_INTERNAL_ERROR;
2151 WLog_DBG(TAG,
"Pen update %" PRId32, deviceid);
2154 WINPR_ASSERT(rdpei->PenUpdate);
2155 rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags, normalizedpressure,
2156 rotation, tiltX, tiltY);
2158 else if (pen->hovering)
2160 WLog_DBG(TAG,
"Pen hover update %" PRId32, deviceid);
2162 WINPR_ASSERT(rdpei->PenHoverUpdate);
2163 rc = rdpei->PenHoverUpdate(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2164 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2168 WLog_DBG(TAG,
"Pen hover begin %" PRId32, deviceid);
2169 pen->hovering = TRUE;
2171 WINPR_ASSERT(rdpei->PenHoverBegin);
2172 rc = rdpei->PenHoverBegin(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2173 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2175 return rc == CHANNEL_RC_OK;
2177 else if ((flags & FREERDP_PEN_RELEASE) != 0)
2179 WLog_DBG(TAG,
"Pen release %" PRId32, deviceid);
2180 pen->pressed = FALSE;
2181 pen->hovering = TRUE;
2183 WINPR_ASSERT(rdpei->PenUpdate);
2184 const UINT rc = rdpei->PenUpdate(rdpei, deviceid, fieldFlags, x, y, penFlags,
2185 normalizedpressure, rotation, tiltX, tiltY);
2186 if (rc != CHANNEL_RC_OK)
2188 WINPR_ASSERT(rdpei->PenEnd);
2189 const UINT re = rdpei->PenEnd(rdpei, deviceid, RDPINPUT_PEN_CONTACT_PENFLAGS_PRESENT, x, y,
2190 penFlags, normalizedpressure, rotation, tiltX, tiltY);
2191 return re == CHANNEL_RC_OK;
2194 WLog_WARN(TAG,
"Invalid pen %" PRId32
" flags 0x%08" PRIx32, deviceid, flags);
2198 BOOL freerdp_client_pen_cancel_all(rdpClientContext* cctx)
2202 RdpeiClientContext* rdpei = cctx->rdpei;
2207 for (
size_t i = 0; i < ARRAYSIZE(cctx->pens); i++)
2212 WLog_DBG(TAG,
"unhover pen %" PRId32, pen->deviceid);
2213 pen->hovering = FALSE;
2214 rdpei->PenHoverCancel(rdpei, pen->deviceid, 0, pen->last_x, pen->last_y);
2220 BOOL freerdp_client_is_pen(rdpClientContext* cctx, INT32 deviceid)
2227 for (
size_t x = 0; x < ARRAYSIZE(cctx->pens); x++)
2230 if (pen->deviceid == deviceid)
2237 BOOL freerdp_client_use_relative_mouse_events(rdpClientContext* ccontext)
2239 WINPR_ASSERT(ccontext);
2241 const rdpSettings* settings = ccontext->context.settings;
2244 BOOL ainput = FALSE;
2245 #if defined(CHANNEL_AINPUT_CLIENT)
2246 ainput = ccontext->ainput != NULL;
2249 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.