#include #include #include #include #include #include #include #include #include #include #include #include #include "rdp_backend_api.h" #include "rdp_impl.h" #include "rdp_png.h" const UINT32 ASCII_TO_SCANCODE[256] = { 0, /* 0 */ 0, /* 1 */ 0, /* 2 */ 0, /* 3 */ 0, /* 4 */ 0, /* 5 */ 0, /* 6 */ 0, /* 7 */ RDP_SCANCODE_BACKSPACE, /* 8 */ RDP_SCANCODE_TAB, /* 9 */ VK_KEY_D, /* 10 */ VK_KEY_F, /* 11 */ VK_KEY_H, /* 12 */ RDP_SCANCODE_RETURN, /* 13 */ RDP_SCANCODE_BACKSPACE, /* 14 */ VK_KEY_X, /* 15 */ RDP_SCANCODE_LSHIFT, /* 16 */ RDP_SCANCODE_LCONTROL, /* 17 */ RDP_SCANCODE_LMENU, /* 18 */ RDP_SCANCODE_PAUSE, /* 19 */ RDP_SCANCODE_CAPSLOCK, /* 20 */ VK_KEY_W, /* 21 */ VK_KEY_E, /* 22 */ VK_KEY_R, /* 23 */ VK_KEY_Y, /* 24 */ VK_KEY_A, /* 25 */ VK_KEY_1, /* 26 */ RDP_SCANCODE_ESCAPE, /* 27 */ VK_KEY_3, /* 28 */ VK_KEY_4, /* 29 */ VK_KEY_6, /* 30 */ VK_KEY_5, /* 31 */ RDP_SCANCODE_SPACE, /* 32 */ RDP_SCANCODE_PRIOR, /* 33 */ RDP_SCANCODE_NEXT, /* 34 */ RDP_SCANCODE_END, /* 35 */ RDP_SCANCODE_HOME, /* 36 */ RDP_SCANCODE_LEFT, /* 37 */ RDP_SCANCODE_UP, /* 38 */ RDP_SCANCODE_RIGHT, /* 39 */ RDP_SCANCODE_DOWN, /* 40 */ RDP_SCANCODE_KEY_0, /* 41 */ RDP_SCANCODE_MULTIPLY, /* 42 */ RDP_SCANCODE_ADD, /* 43 */ RDP_SCANCODE_PRINTSCREEN, /* 44 */ RDP_SCANCODE_INSERT, /* 45 */ RDP_SCANCODE_DELETE, /* 46 */ RDP_SCANCODE_DIVIDE, /* 47 */ RDP_SCANCODE_KEY_0, /* 48 */ RDP_SCANCODE_KEY_1, /* 49 */ RDP_SCANCODE_KEY_2, /* 50 */ RDP_SCANCODE_KEY_3, /* 51 */ RDP_SCANCODE_KEY_4, /* 52 */ RDP_SCANCODE_KEY_5, /* 53 */ RDP_SCANCODE_KEY_6, /* 54 */ RDP_SCANCODE_KEY_7, /* 55 */ RDP_SCANCODE_KEY_8, /* 56 */ RDP_SCANCODE_KEY_9, /* 57 */ RDP_SCANCODE_OEM_1, /* 58 */ RDP_SCANCODE_OEM_1, /* 59 */ RDP_SCANCODE_OEM_COMMA, /* 60 */ RDP_SCANCODE_OEM_PLUS, /* 61 */ RDP_SCANCODE_OEM_PERIOD, /* 62 */ RDP_SCANCODE_DIVIDE, /* 63 */ RDP_SCANCODE_KEY_2, /* 64 */ RDP_SCANCODE_KEY_A, /* 65 */ RDP_SCANCODE_KEY_B, /* 66 */ RDP_SCANCODE_KEY_C, /* 67 */ RDP_SCANCODE_KEY_D, /* 68 */ RDP_SCANCODE_KEY_E, /* 69 */ RDP_SCANCODE_KEY_F, /* 70 */ RDP_SCANCODE_KEY_G, /* 71 */ RDP_SCANCODE_KEY_H, /* 72 */ RDP_SCANCODE_KEY_I, /* 73 */ RDP_SCANCODE_KEY_J, /* 74 */ RDP_SCANCODE_KEY_K, /* 75 */ RDP_SCANCODE_KEY_L, /* 76 */ RDP_SCANCODE_KEY_M, /* 77 */ RDP_SCANCODE_KEY_N, /* 78 */ RDP_SCANCODE_KEY_O, /* 79 */ RDP_SCANCODE_KEY_P, /* 80 */ RDP_SCANCODE_KEY_Q, /* 81 */ RDP_SCANCODE_KEY_R, /* 82 */ RDP_SCANCODE_KEY_S, /* 83 */ RDP_SCANCODE_KEY_T, /* 84 */ RDP_SCANCODE_KEY_U, /* 85 */ RDP_SCANCODE_KEY_V, /* 86 */ RDP_SCANCODE_KEY_W, /* 87 */ RDP_SCANCODE_KEY_X, /* 88 */ RDP_SCANCODE_KEY_Y, /* 89 */ RDP_SCANCODE_KEY_Z, /* 90 */ RDP_SCANCODE_LWIN, /* 91 */ RDP_SCANCODE_RWIN, /* 92 */ RDP_SCANCODE_APPS, /* 93 */ RDP_SCANCODE_KEY_6, /* 94 */ RDP_SCANCODE_OEM_MINUS, /* 95 */ RDP_SCANCODE_NUMPAD0, /* 96 */ RDP_SCANCODE_NUMPAD1, /* 97 */ RDP_SCANCODE_NUMPAD2, /* 98 */ RDP_SCANCODE_NUMPAD3, /* 99 */ RDP_SCANCODE_NUMPAD4, /* 100 */ RDP_SCANCODE_NUMPAD5, /* 101 */ RDP_SCANCODE_NUMPAD6, /* 102 */ RDP_SCANCODE_NUMPAD7, /* 103 */ RDP_SCANCODE_NUMPAD8, /* 104 */ RDP_SCANCODE_NUMPAD9, /* 105 */ RDP_SCANCODE_MULTIPLY, /* 106 */ RDP_SCANCODE_ADD, /* 107 */ 0, /* 108 */ RDP_SCANCODE_SUBTRACT, /* 109 */ RDP_SCANCODE_DELETE, /* 110 */ RDP_SCANCODE_DIVIDE, /* 111 */ RDP_SCANCODE_F1, /* 112 */ RDP_SCANCODE_F2, /* 113 */ RDP_SCANCODE_F3, /* 114 */ RDP_SCANCODE_F4, /* 115 */ RDP_SCANCODE_F5, /* 116 */ RDP_SCANCODE_F6, /* 117 */ RDP_SCANCODE_F7, /* 118 */ RDP_SCANCODE_F8, /* 119 */ RDP_SCANCODE_F9, /* 120 */ RDP_SCANCODE_F10, /* 121 */ RDP_SCANCODE_F11, /* 122 */ RDP_SCANCODE_F12, /* 123 */ RDP_SCANCODE_OEM_5, /* 124 */ RDP_SCANCODE_OEM_6, /* 125 */ VK_F4, /* 126 */ VK_END, /* 127 */ VK_F2, /* 128 */ VK_NEXT, /* 129 */ VK_F1, /* 130 */ VK_LEFT, /* 131 */ VK_RIGHT, /* 132 */ VK_DOWN, /* 133 */ VK_UP, /* 134 */ 0, /* 135 */ 0, /* 136 */ 0, /* 137 */ 0, /* 138 */ 0, /* 139 */ 0, /* 140 */ 0, /* 141 */ 0, /* 142 */ 0, /* 143 */ RDP_SCANCODE_NUMLOCK, /* 144 */ RDP_SCANCODE_SCROLLLOCK, /* 145 */ 0, /* 146 */ 0, /* 147 */ 0, /* 148 */ 0, /* 149 */ 0, /* 150 */ 0, /* 151 */ 0, /* 152 */ 0, /* 153 */ 0, /* 154 */ 0, /* 155 */ 0, /* 156 */ 0, /* 157 */ 0, /* 158 */ 0, /* 159 */ 0, /* 160 */ 0, /* 161 */ 0, /* 162 */ 0, /* 163 */ 0, /* 164 */ 0, /* 165 */ 0, /* 166 */ 0, /* 167 */ 0, /* 168 */ 0, /* 169 */ 0, /* 170 */ 0, /* 171 */ 0, /* 172 */ RDP_SCANCODE_OEM_MINUS, /* 173 */ 0, /* 174 */ 0, /* 175 */ 0, /* 176 */ 0, /* 177 */ 0, /* 178 */ 0, /* 179 */ 0, /* 180 */ 0, /* 181 */ 0, /* 182 */ 0, /* 183 */ 0, /* 184 */ 0, /* 185 */ RDP_SCANCODE_OEM_1, /* 186 */ RDP_SCANCODE_OEM_PLUS, /* 187 */ RDP_SCANCODE_OEM_COMMA, /* 188 */ RDP_SCANCODE_OEM_MINUS, /* 189 */ RDP_SCANCODE_OEM_PERIOD, /* 190 */ RDP_SCANCODE_OEM_2, /* 191 */ RDP_SCANCODE_OEM_3, /* 192 */ 0, /* 193 */ 0, /* 194 */ 0, /* 195 */ 0, /* 196 */ 0, /* 197 */ 0, /* 198 */ 0, /* 199 */ 0, /* 200 */ 0, /* 201 */ 0, /* 202 */ 0, /* 203 */ 0, /* 204 */ 0, /* 205 */ 0, /* 206 */ 0, /* 207 */ 0, /* 208 */ 0, /* 209 */ 0, /* 210 */ 0, /* 211 */ 0, /* 212 */ 0, /* 213 */ 0, /* 214 */ 0, /* 215 */ 0, /* 216 */ 0, /* 217 */ 0, /* 218 */ RDP_SCANCODE_OEM_4, /* 219 */ RDP_SCANCODE_OEM_5, /* 220 */ RDP_SCANCODE_OEM_6, /* 221 */ RDP_SCANCODE_OEM_7, /* 222 */ 0, /* 223 */ 0, /* 224 */ 0, /* 225 */ 0, /* 226 */ 0, /* 227 */ 0, /* 228 */ 0, /* 229 */ 0, /* 230 */ 0, /* 231 */ 0, /* 232 */ 0, /* 233 */ 0, /* 234 */ 0, /* 235 */ 0, /* 236 */ 0, /* 237 */ 0, /* 238 */ 0, /* 239 */ 0, /* 240 */ 0, /* 241 */ 0, /* 242 */ 0, /* 243 */ 0, /* 244 */ 0, /* 245 */ 0, /* 246 */ 0, /* 247 */ 0, /* 248 */ 0, /* 249 */ 0, /* 250 */ 0, /* 251 */ 0, /* 252 */ 0, /* 253 */ 0, /* 254 */ 0 /* 255 */ }; #define RGB_555_888(_r, _g, _b) \ _r = (_r << 3 & ~0x7) | (_r >> 2); \ _g = (_g << 3 & ~0x7) | (_g >> 2); \ _b = (_b << 3 & ~0x7) | (_b >> 2); #define RGB_565_888(_r, _g, _b) \ _r = (_r << 3 & ~0x7) | (_r >> 2); \ _g = (_g << 2 & ~0x3) | (_g >> 4); \ _b = (_b << 3 & ~0x7) | (_b >> 2); #define GetRGB_555(_r, _g, _b, _p) \ _r = (_p & 0x7C00) >> 10; \ _g = (_p & 0x3E0) >> 5; \ _b = (_p & 0x1F); #define GetRGB_565(_r, _g, _b, _p) \ _r = (_p & 0xF800) >> 11; \ _g = (_p & 0x7E0) >> 5; \ _b = (_p & 0x1F); #define GetRGB15(_r, _g, _b, _p) \ GetRGB_555(_r, _g, _b, _p); \ RGB_555_888(_r, _g, _b); #define GetRGB16(_r, _g, _b, _p) \ GetRGB_565(_r, _g, _b, _p); \ RGB_565_888(_r, _g, _b); #define RGB24(_r, _g, _b) ((_r << 16) | (_g << 8) | _b) #define GetRGB24(_r, _g, _b, _p) \ _r = (_p & 0xFF0000) >> 16; \ _g = (_p & 0xFF00) >> 8; \ _b = (_p & 0xFF); #define GetRGB32(_r, _g, _b, _p) \ _r = (_p & 0xFF0000) >> 16; \ _g = (_p & 0xFF00) >> 8; \ _b = (_p & 0xFF); #define ARGB32(_a, _r, _g, _b) (_a << 24) | (_r << 16) | (_g << 8) | _b #define RGB16(_r, _g, _b) \ (((_r >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) \ | ((_b >> 3) & 0x1F) #define RGB15(_r, _g, _b) \ (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) \ | ((_b >> 3) & 0x1F) #define GetARGB32(_a, _r, _g, _b, _p) \ _a = (_p & 0xFF000000) >> 24; \ _r = (_p & 0xFF0000) >> 16; \ _g = (_p & 0xFF00) >> 8; \ _b = (_p & 0xFF); static HCLRCONV freerdp_clrconv_new(UINT32 flags) { HCLRCONV clrconv; clrconv = (CLRCONV *)calloc(1, sizeof(CLRCONV)); if (!clrconv) return NULL; clrconv->alpha = (flags & CLRCONV_ALPHA) ? TRUE : FALSE; clrconv->invert = (flags & CLRCONV_INVERT) ? TRUE : FALSE; clrconv->rgb555 = (flags & CLRCONV_RGB555) ? TRUE : FALSE; clrconv->palette = (rdpPalette *)calloc(1, sizeof(rdpPalette)); if (!clrconv->palette) { free(clrconv); return NULL; } return clrconv; } static void freerdp_clrconv_free(HCLRCONV clrconv) { if (clrconv) { free(clrconv->palette); free(clrconv); } } static int freerdp_get_pixel(BYTE *data, int x, int y, int width, int height, int bpp) { int start; int shift; UINT16 *src16; UINT32 *src32; int red, green, blue; switch (bpp) { case 1: width = (width + 7) / 8; start = (y * width) + x / 8; shift = x % 8; return (data[start] & (0x80 >> shift)) != 0; case 8: return data[y * width + x]; case 15: case 16: src16 = (UINT16 *)data; return src16[y * width + x]; case 24: data += y * width * 3; data += x * 3; red = data[0]; green = data[1]; blue = data[2]; return RGB24(red, green, blue); case 32: src32 = (UINT32 *)data; return src32[y * width + x]; default: break; } return 0; } static void freerdp_set_pixel( BYTE *data, int x, int y, int width, int height, int bpp, int pixel) { int start; int shift; int *dst32; if (bpp == 1) { width = (width + 7) / 8; start = (y * width) + x / 8; shift = x % 8; if (pixel) data[start] = data[start] | (0x80 >> shift); else data[start] = data[start] & ~(0x80 >> shift); } else if (bpp == 32) { dst32 = (int *)data; dst32[y * width + x] = pixel; } } static void freerdp_color_split_rgb(UINT32 *color, int bpp, BYTE *red, BYTE *green, BYTE *blue, BYTE *alpha, HCLRCONV clrconv) { *red = *green = *blue = 0; *alpha = (clrconv->alpha) ? 0xFF : 0x00; switch (bpp) { case 32: if (clrconv->alpha) { GetARGB32(*alpha, *red, *green, *blue, *color); } else { GetRGB32(*red, *green, *blue, *color); } break; case 24: GetRGB24(*red, *green, *blue, *color); break; case 16: GetRGB16(*red, *green, *blue, *color); break; case 15: GetRGB15(*red, *green, *blue, *color); break; case 8: *color &= 0xFF; *red = clrconv->palette->entries[*color].red; *green = clrconv->palette->entries[*color].green; *blue = clrconv->palette->entries[*color].blue; break; case 1: if (*color != 0) { *red = 0xFF; *green = 0xFF; *blue = 0xFF; } break; default: break; } } static void freerdp_color_make_rgb(UINT32 *color, int bpp, BYTE *red, BYTE *green, BYTE *blue, BYTE *alpha, HCLRCONV clrconv) { switch (bpp) { case 32: *color = ARGB32(*alpha, *red, *green, *blue); break; case 24: *color = RGB24(*red, *green, *blue); break; case 16: if (clrconv->rgb555) { *color = RGB15(*red, *green, *blue); } else { *color = RGB16(*red, *green, *blue); } break; case 15: *color = RGB15(*red, *green, *blue); break; case 8: *color = RGB24(*red, *green, *blue); break; case 1: if ((*red != 0) || (*green != 0) || (*blue != 0)) *color = 1; break; default: break; } } static UINT32 freerdp_color_convert_rgb( UINT32 srcColor, int srcBpp, int dstBpp, HCLRCONV clrconv) { BYTE red = 0; BYTE green = 0; BYTE blue = 0; BYTE alpha = 0xFF; UINT32 dstColor = 0; freerdp_color_split_rgb( &srcColor, srcBpp, &red, &green, &blue, &alpha, clrconv); freerdp_color_make_rgb( &dstColor, dstBpp, &red, &green, &blue, &alpha, clrconv); return dstColor; } static void freerdp_alpha_cursor_convert(BYTE *alphaData, BYTE *xorMask, BYTE *andMask, int width, int height, int bpp, HCLRCONV clrconv) { UINT32 xorPixel; UINT32 andPixel; UINT32 x, y, jj; for (y = 0; y < height; y++) { jj = (bpp == 1) ? y : (height - 1) - y; for (x = 0; x < width; x++) { xorPixel = freerdp_get_pixel( xorMask, x, jj, width, height, bpp); xorPixel = freerdp_color_convert_rgb( xorPixel, bpp, 32, clrconv); andPixel = freerdp_get_pixel( andMask, x, jj, width, height, 1); if (andPixel) { if ((xorPixel & 0xFFFFFF) == 0xFFFFFF) { /* use pattern (not solid black) for xor * area */ xorPixel = (x & 1) == (y & 1); xorPixel = xorPixel ? 0xFFFFFF : 0; xorPixel |= 0xFF000000; } else if (xorPixel == 0xFF000000) { xorPixel = 0; } } freerdp_set_pixel( alphaData, x, y, width, height, 32, xorPixel); } } } static void freerdp_bitmap_flip(BYTE *src, BYTE *dst, int scanLineSz, int height) { int i; BYTE *bottomLine = dst + (scanLineSz * (height - 1)); BYTE *topLine = src; /* Special processing if called for flip-in-place. */ if (src == dst) { /* Allocate a scanline buffer. * (FIXME: malloc / xfree below should be replaced by "get/put * scanline buffer from a pool/Q of fixed buffers" to reuse * fixed size buffers (of max scanline size (or adaptative?) ) * -- would be much faster). */ BYTE *tmpBfr = (BYTE *)_aligned_malloc(scanLineSz, 16); int half = height / 2; /* Flip buffer in place by line permutations through the temp * scan line buffer. * Note that if height has an odd number of line, we don't need * to move the center scanline anyway. * Also note that in place flipping takes three memcpy() calls * to process two scanlines while src to distinct dest would * only requires two memcpy() calls for two scanlines. */ height--; for (i = 0; i < half; i++) { CopyMemory(tmpBfr, topLine, scanLineSz); CopyMemory(topLine, bottomLine, scanLineSz); CopyMemory(bottomLine, tmpBfr, scanLineSz); topLine += scanLineSz; bottomLine -= scanLineSz; height--; } _aligned_free(tmpBfr); } /* Flip from source buffer to destination buffer. */ else { for (i = 0; i < height; i++) { CopyMemory(bottomLine, topLine, scanLineSz); topLine += scanLineSz; bottomLine -= scanLineSz; } } } static BYTE * freerdp_image_flip(BYTE *srcData, BYTE *dstData, int width, int height, int bpp) { int scanline; scanline = width * ((bpp + 7) / 8); if (!dstData) dstData = (BYTE *)_aligned_malloc( width * height * ((bpp + 7) / 8), 16); if (!dstData) { return NULL; } freerdp_bitmap_flip(srcData, dstData, scanline, height); return dstData; } /* outgoing rdp protocol to client implementation */ static BOOL Pointer_New(rdpContext *context, rdpPointer *pointer) { my_rdp_context *c = (my_rdp_context *)context; HCLRCONV hclrconv = c->my_internals->clrconv; size_t psize = pointer->width * pointer->height * 4; my_rdp_pointer *p = (my_rdp_pointer *)pointer; p->id = c->my_internals->m_ptrId++; uint8_t *pixels = malloc(sizeof(uint8_t) * psize); memset(pixels, 0, psize); if ((pointer->andMaskData != 0) && (pointer->xorMaskData != 0)) { //XXX freerdp_alpha_cursor_convert(pixels, pointer->xorMaskData, pointer->andMaskData, pointer->width, pointer->height, pointer->xorBpp, hclrconv); } //check if the cursor is fully transparent bool transparent = TRUE; for (int y = 0; y < pointer->height; y++) { for (int x = 0; x < pointer->width; x++) { if (pixels[0 + x * 4 + y * 4 * pointer->width] != 0) { transparent = FALSE; } } } if (transparent) { pixels[3] = 1; } rdp_png_buf png_buf; memset(&png_buf, 0, sizeof(png_buf)); png_buf.buf_size = (pointer->width * pointer->height * sizeof(uint32_t)) + 8 /* allocating fullsize 32but argb pixels + png header */; png_buf.buf = malloc(png_buf.buf_size); png_generate_from_argb( pointer->width, pointer->height, pixels, &png_buf); struct { unsigned char resL; //2 bytes reserved must always be 0 unsigned char resH; unsigned char imgTypeL; //2 bytes image type. 1 = ICO, 2 = CUR unsigned char imgTypeH; unsigned char nbImgL; //2 bytes number of images unsigned char nbImgH; unsigned char width; //1 byte image width in pixels unsigned char height; //1 byte image height in pixels unsigned char nbColors; //1 bytenumber of colors. 0 if not using //a color pallete unsigned char res; //1 byte reserved, should be 0 unsigned char xPosL; //2 bytes of hot spot x (for ICO, color //planes, 0 or 1) unsigned char xPosH; unsigned char yPosL; //2 bytes of hot spot y (for ICO bits per pixel) unsigned char yPosH; unsigned char sizeLL; //4 bytes of image size unsigned char sizeLH; unsigned char sizeHL; unsigned char sizeHH; unsigned char offsetLL; //4 bytes of offset of the data unsigned char offsetLH; unsigned char offsetHL; unsigned char offsetHH; } curHeader = {0x00, 0x00, 0x02, 0x00, 0x01, 0x00, (unsigned char)pointer->width, (unsigned char)pointer->height, 0x00, 0x00, (unsigned char)pointer->xPos, (unsigned char)(pointer->xPos >> 8), (unsigned char)pointer->yPos, (unsigned char)(pointer->yPos >> 8), (unsigned char)png_buf.written, (unsigned char)(png_buf.written >> 8), (unsigned char)(png_buf.written >> 16), (unsigned char)(png_buf.written >> 24), 0x16, 0x00, 0x00, 0x00}; size_t cursor_buf_size = png_buf.written + sizeof(curHeader); uint8_t *cursor_buf = malloc(cursor_buf_size); memcpy(cursor_buf, &curHeader, sizeof(curHeader)); memcpy(cursor_buf + sizeof(curHeader), png_buf.buf, png_buf.written); free(png_buf.buf); /* rdp_cursor_add (p->id, cursor_buf, cursor_buf_size, * c->my_internals); */ free(pixels); struct { uint32_t id; uint32_t hx; uint32_t hy; } tmp = {p->id, pointer->xPos, pointer->yPos}; size_t send_buf_size = sizeof(tmp) + cursor_buf_size; uint8_t *send_buf = malloc(send_buf_size); memcpy(send_buf, &tmp, sizeof(tmp)); memcpy(send_buf + sizeof(tmp), cursor_buf, cursor_buf_size); free(cursor_buf); c->my_internals->core->send_ptr_new( send_buf, send_buf_size, c->my_internals->task_info); return TRUE; } static void Pointer_Free(rdpContext *context, rdpPointer *pointer) { my_rdp_pointer *p = (my_rdp_pointer *)pointer; my_rdp_context *c = (my_rdp_context *)context; if (p->id) { /* rdp_cursor_erase (p->id, c->my_internals); */ c->my_internals->core->send_ptr_free((uint8_t *)&(p->id), sizeof(uint32_t), c->my_internals->task_info); } } static BOOL Pointer_Set(rdpContext *context, const rdpPointer *pointer) { my_rdp_pointer *p = (my_rdp_pointer *)pointer; my_rdp_context *c = (my_rdp_context *)context; c->my_internals->core->send_ptr_set( (uint8_t *)&(p->id), sizeof(uint32_t), c->my_internals->task_info); return TRUE; } static BOOL Pointer_SetNull(rdpContext *context) { my_rdp_context *c = (my_rdp_context *)context; c->my_internals->core->send_ptr_set_null(c->my_internals->task_info); return TRUE; } static BOOL Pointer_SetDefault(rdpContext *context) { my_rdp_context *c = (my_rdp_context *)context; c->my_internals->core->send_ptr_set_default(c->my_internals->task_info); return TRUE; } void register_pointer(rdpPointer *p) { p->New = Pointer_New; p->Free = Pointer_Free; p->Set = Pointer_Set; p->SetNull = Pointer_SetNull; p->SetDefault = Pointer_SetDefault; } static BOOL rdp_context_new(freerdp *instance, rdpContext *context) { return TRUE; } static void rdp_context_free(freerdp *instance, rdpContext *context) { my_rdp_context *c = (my_rdp_context *)context; if (context->cache) { cache_free(context->cache); context->cache = NULL; } if (c->my_internals->clrconv) { freerdp_clrconv_free(c->my_internals->clrconv); c->my_internals->clrconv = NULL; } } static BOOL BeginPaint(rdpContext *context) { my_rdp_context *c = (my_rdp_context *)context; c->my_internals->core->send_begin_paint(c->my_internals->task_info); return TRUE; } static BOOL EndPaint(rdpContext *context) { my_rdp_context *c = (my_rdp_context *)context; c->my_internals->core->send_end_paint(c->my_internals->task_info); return TRUE; } static BOOL SetBounds(rdpContext *context, const rdpBounds *bounds) { my_rdp_context *c = (my_rdp_context *)context; rdpBounds lB; if (bounds) { memcpy(&lB, bounds, sizeof(rdpBounds)); lB.right++; lB.bottom++; } else { memset(&lB, 0, sizeof(rdpBounds)); } c->my_internals->core->send_set_bounds( (uint8_t *)&lB, sizeof(lB), c->my_internals->task_info); return TRUE; } static BOOL Synchronize(rdpContext *context) { return TRUE; } static BOOL DesktopResize(rdpContext *context) { my_rdp_context *c = (my_rdp_context *)context; char buf[64]; snprintf(buf, 63, "R:%dx%d", context->settings->DesktopWidth, context->settings->DesktopHeight); c->my_internals->core->send_text_msg(buf, c->my_internals->task_info); return TRUE; } static BOOL BitmapUpdate(rdpContext *context, const BITMAP_UPDATE *bitmap) { my_rdp_context *c = (my_rdp_context *)context; int i; BITMAP_DATA *bmd; for (i = 0; i < (int)bitmap->number; i++) { bmd = &bitmap->rectangles[i]; struct { uint32_t x; uint32_t y; uint32_t w; uint32_t h; uint32_t dw; uint32_t dh; uint32_t bpp; uint32_t cf; uint32_t sz; } wxbm = {bmd->destLeft, bmd->destTop, bmd->width, bmd->height, bmd->destRight - bmd->destLeft + 1, bmd->destBottom - bmd->destTop + 1, bmd->bitsPerPixel, (uint32_t)bmd->compressed, bmd->bitmapLength}; if (!bmd->compressed) { freerdp_image_flip(bmd->bitmapDataStream, bmd->bitmapDataStream, bmd->width, bmd->height, bmd->bitsPerPixel); } size_t buf_size = sizeof(wxbm) + bmd->bitmapLength; uint8_t *buf = malloc(buf_size); memcpy(buf, &wxbm, sizeof(wxbm)); memcpy(buf + sizeof(wxbm), bmd->bitmapDataStream, bmd->bitmapLength); c->my_internals->core->send_bitmap( buf, buf_size, c->my_internals->task_info); free(buf); } return TRUE; } static BOOL Palette(rdpContext *c, const PALETTE_UPDATE *p) { return TRUE; } static BOOL PlaySound(rdpContext *c, const PLAY_SOUND_UPDATE *s) { return TRUE; } static BOOL RefreshRect(rdpContext *c, UINT8 hz, const RECTANGLE_16 *r) { return TRUE; } static BOOL SuppressOutput(rdpContext *c, UINT8 hz, const RECTANGLE_16 *r) { return TRUE; } /*static BOOL SurfaceCommand(rdpContext* c, wStream* s) { return TRUE; }*/ static BOOL SurfaceBits(rdpContext *c, const SURFACE_BITS_COMMAND *sbc) { return TRUE; } /*static BOOL SurfaceFrameMarker(rdpContext* c, SURFACE_FRAME_MARKER* sfm) { return TRUE; } */ void RegisterUpdate(freerdp *rdp) { rdp->update->BeginPaint = BeginPaint; rdp->update->EndPaint = EndPaint; rdp->update->SetBounds = SetBounds; rdp->update->Synchronize = Synchronize; rdp->update->DesktopResize = DesktopResize; rdp->update->BitmapUpdate = BitmapUpdate; rdp->update->Palette = Palette; rdp->update->PlaySound = PlaySound; rdp->update->SurfaceBits = SurfaceBits; rdp->update->RefreshRect = RefreshRect; rdp->update->SuppressOutput = SuppressOutput; } static BOOL DstBlt(rdpContext *c, const DSTBLT_ORDER *_do) { return TRUE; } static BOOL PatBlt(rdpContext *ctx, PATBLT_ORDER *po) { my_rdp_context *c = (my_rdp_context *)ctx; uint32_t rop3 = gdi_rop3_code(po->bRop); if (GDI_BS_SOLID == po->brush.style) { struct { int32_t x; int32_t y; int32_t w; int32_t h; uint32_t fg; uint32_t rop; } tmp = {po->nLeftRect, po->nTopRect, po->nWidth, po->nHeight, ConvertColor(po->foreColor, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_ABGR32, NULL), //XXX rop3}; c->my_internals->core->send_pat_blt( (uint8_t *)&tmp, sizeof(tmp), c->my_internals->task_info); } return TRUE; } static BOOL ScrBlt(rdpContext *ctx, const SCRBLT_ORDER *sbo) { my_rdp_context *c = (my_rdp_context *)ctx; uint32_t rop3 = gdi_rop3_code(sbo->bRop); struct { uint32_t rop; int32_t x; int32_t y; int32_t w; int32_t h; int32_t sx; int32_t sy; } tmp = {rop3, sbo->nLeftRect, sbo->nTopRect, sbo->nWidth, sbo->nHeight, sbo->nXSrc, sbo->nYSrc}; c->my_internals->core->send_scr_blt( (uint8_t *)&tmp, sizeof(tmp), c->my_internals->task_info); return TRUE; } static BOOL OpaqueRect(rdpContext *context, const OPAQUE_RECT_ORDER *oro) { my_rdp_context *c = (my_rdp_context *)context; OPAQUE_RECT_ORDER oro2 = *oro; oro2.color = ConvertColor( oro2.color, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_ABGR32, NULL); c->my_internals->core->send_opaque_rect_order((uint8_t *)&oro2, sizeof(OPAQUE_RECT_ORDER), c->my_internals->task_info); return TRUE; } static BOOL DrawNineGrid(rdpContext *c, const DRAW_NINE_GRID_ORDER *dngo) { return TRUE; } static BOOL MultiDstBlt(rdpContext *c, const MULTI_DSTBLT_ORDER *mdo) { return TRUE; } static BOOL MultiPatBlt(rdpContext *c, const MULTI_PATBLT_ORDER *mpo) { return TRUE; } static BOOL MultiScrBlt(rdpContext *c, const MULTI_SCRBLT_ORDER *mso) { return TRUE; } static BOOL MultiOpaqueRect(rdpContext *context, const MULTI_OPAQUE_RECT_ORDER *moro) { my_rdp_context *c = (my_rdp_context *)context; uint32_t color = ConvertColor( moro->color, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_ABGR32, NULL); uint32_t nr = moro->numRectangles; size_t buf_size = (sizeof(color) + sizeof(nr)) + (sizeof(DELTA_RECT) * nr); uint8_t *buf = malloc(buf_size); memcpy(buf, (uint8_t *)&color, sizeof(color)); memcpy(buf + sizeof(color), (uint8_t *)&nr, sizeof(nr)); memcpy(buf + (sizeof(color) + sizeof(color)), (uint8_t *)&moro->rectangles[1], sizeof(DELTA_RECT) * nr); c->my_internals->core->send_multi_opaque_rect( buf, buf_size, c->my_internals->task_info); free(buf); return TRUE; } static BOOL MultiDrawNineGrid(rdpContext *c, const MULTI_DRAW_NINE_GRID_ORDER *mdngo) { return TRUE; } static BOOL LineTo(rdpContext *c, const LINE_TO_ORDER *lto) { return TRUE; } static BOOL Polyline(rdpContext *c, const POLYLINE_ORDER *po) { return TRUE; } static BOOL MemBlt(rdpContext *c, MEMBLT_ORDER *mo) { return TRUE; } static BOOL Mem3Blt(rdpContext *c, MEM3BLT_ORDER *mo) { return TRUE; } static BOOL SaveBitmap(rdpContext *c, const SAVE_BITMAP_ORDER *sbo) { return TRUE; } static BOOL GlyphIndex(rdpContext *c, GLYPH_INDEX_ORDER *gio) { return TRUE; } static BOOL FastIndex(rdpContext *c, const FAST_INDEX_ORDER *fio) { return TRUE; } static BOOL FastGlyph(rdpContext *c, const FAST_GLYPH_ORDER *fgo) { return TRUE; } static BOOL PolygonSC(rdpContext *c, const POLYGON_SC_ORDER *pso) { return TRUE; } static BOOL PolygonCB(rdpContext *c, POLYGON_CB_ORDER *pco) { return TRUE; } static BOOL EllipseSC(rdpContext *c, const ELLIPSE_SC_ORDER *eso) { return TRUE; } static BOOL EllipseCB(rdpContext *c, const ELLIPSE_CB_ORDER *eco) { return TRUE; } void RegisterPrimary(freerdp *rdp) { rdp->update->primary->DstBlt = DstBlt; rdp->update->primary->PatBlt = PatBlt; rdp->update->primary->ScrBlt = ScrBlt; rdp->update->primary->OpaqueRect = OpaqueRect; rdp->update->primary->DrawNineGrid = DrawNineGrid; rdp->update->primary->MultiDstBlt = MultiDstBlt; rdp->update->primary->MultiPatBlt = MultiPatBlt; rdp->update->primary->MultiScrBlt = MultiScrBlt; rdp->update->primary->MultiOpaqueRect = MultiOpaqueRect; rdp->update->primary->MultiDrawNineGrid = MultiDrawNineGrid; rdp->update->primary->LineTo = LineTo; rdp->update->primary->Polyline = Polyline; rdp->update->primary->MemBlt = MemBlt; rdp->update->primary->Mem3Blt = Mem3Blt; rdp->update->primary->SaveBitmap = SaveBitmap; rdp->update->primary->GlyphIndex = GlyphIndex; rdp->update->primary->FastIndex = FastIndex; rdp->update->primary->FastGlyph = FastGlyph; rdp->update->primary->PolygonSC = PolygonSC; rdp->update->primary->PolygonCB = PolygonCB; rdp->update->primary->EllipseSC = EllipseSC; rdp->update->primary->EllipseCB = EllipseCB; } /* incomming input from client handlers */ static bool rdp_backend_handle_input_mouse(ws_input_mouse input, void *internals) { rdp_internals *_i = internals; rdpInput *inp = _i->instance->input; _i->core->reset_idle(_i->task_info); inp->MouseEvent(inp, input.flags, input.x, input.y); return true; } static bool rdp_backend_handle_input_kupdown(ws_input_kupdown input, void *internals) { rdp_internals *_i = internals; rdpInput *inp = _i->instance->input; if (0 < input.code) { _i->core->reset_idle(_i->task_info); /*log::info << "257 >> tcode: " << input.code << "\n"; */ /* make byte */ input.code = RDP_SCANCODE_CODE(input.code); /* apply extended */ input.code = ASCII_TO_SCANCODE[input.code]; /* extract extended sepparatelly in tflag */ uint32_t tflag = RDP_SCANCODE_EXTENDED(input.code) ? KBD_FLAGS_EXTENDED : 0; /* now make the call */ freerdp_input_send_keyboard_event(inp, (input.down ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE) | tflag, input.code); } return true; } static bool rdp_backend_handle_input_kpress(ws_input_kpress input, void *internals) { rdp_internals *_i = internals; rdpInput *inp = _i->instance->input; _i->core->reset_idle(_i->task_info); if (0x20 < input.code) { if (input.shiftstate & 6) { //Control and or Alt: Must use scan-codes since //unicode-event can't handle these if (((64 < input.code) && (91 > input.code)) || ((96 < input.code) && (123 > input.code))) { input.code -= (input.shiftstate & 1) ? 0 : 32; input.code = GetVirtualScanCodeFromVirtualKeyCode( input.code, 4); if (0 < input.code) { freerdp_input_send_unicode_keyboard_event( inp, KBD_FLAGS_DOWN, ASCII_TO_SCANCODE[input.code]); freerdp_input_send_unicode_keyboard_event( inp, KBD_FLAGS_RELEASE, ASCII_TO_SCANCODE[input.code]); } } } else { if (0 < input.code) { if (input.code == 96) { freerdp_input_send_keyboard_event(inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LCONTROL); freerdp_input_send_keyboard_event(inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU); freerdp_input_send_keyboard_event(inp, KBD_FLAGS_DOWN, RDP_SCANCODE_DELETE); freerdp_input_send_keyboard_event(inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LCONTROL); freerdp_input_send_keyboard_event(inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LMENU); freerdp_input_send_keyboard_event(inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_DELETE); } freerdp_input_send_keyboard_event(inp, KBD_FLAGS_DOWN, ASCII_TO_SCANCODE[input.code]); freerdp_input_send_keyboard_event(inp, KBD_FLAGS_RELEASE, ASCII_TO_SCANCODE[input.code]); } } } else { if (0 < input.code) { input.code = RDP_SCANCODE_CODE(input.code); freerdp_input_send_keyboard_event( inp, KBD_FLAGS_DOWN, ASCII_TO_SCANCODE[input.code]); freerdp_input_send_keyboard_event(inp, KBD_FLAGS_RELEASE, ASCII_TO_SCANCODE[input.code]); } } return true; } static bool rdp_backend_handle_input_kcomb(ws_input_keycomb input, void *internals) { rdp_internals *_i = internals; rdpInput *inp = _i->instance->input; _i->core->reset_idle(_i->task_info); switch (input) { case ws_keycomb_ctrlaltdel_press: { freerdp_input_send_keyboard_event( inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LCONTROL); freerdp_input_send_keyboard_event( inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU); freerdp_input_send_keyboard_event( inp, KBD_FLAGS_DOWN, RDP_SCANCODE_DELETE); freerdp_input_send_keyboard_event( inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LCONTROL); freerdp_input_send_keyboard_event( inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LMENU); freerdp_input_send_keyboard_event( inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_DELETE); } break; case ws_keycomb_alttab_press: { freerdp_input_send_keyboard_event( inp, KBD_FLAGS_DOWN, RDP_SCANCODE_LMENU); freerdp_input_send_keyboard_event( inp, KBD_FLAGS_DOWN, RDP_SCANCODE_TAB); freerdp_input_send_keyboard_event( inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_TAB); } break; case ws_keycomb_alttab_release: { freerdp_input_send_keyboard_event( inp, KBD_FLAGS_RELEASE, RDP_SCANCODE_LMENU); } break; default: break; } return true; } static bool rdp_backend_handle_input_unicode(ws_input_unicode input, void *internals) { rdp_internals *_i = internals; rdpInput *inp = _i->instance->input; int i; _i->core->reset_idle(_i->task_info); for (i = 0; i < input.length; ++i) { freerdp_input_send_unicode_keyboard_event( inp, KBD_FLAGS_DOWN, (UINT16)input.input[i]); freerdp_input_send_unicode_keyboard_event( inp, KBD_FLAGS_RELEASE, (UINT16)input.input[i]); } return true; } void register_input(wrdp_backend_module *backend) { backend->backend_handle_input_kcomb = rdp_backend_handle_input_kcomb; backend->backend_handle_input_kupdown = rdp_backend_handle_input_kupdown; backend->backend_handle_input_kpress = rdp_backend_handle_input_kpress; backend->backend_handle_input_mouse = rdp_backend_handle_input_mouse; backend->backend_handle_input_unicode = rdp_backend_handle_input_unicode; } static BOOL rdp_pre_connect(freerdp *instance) { rdpSettings *settings = instance->settings; my_rdp_context *c = (my_rdp_context *)instance->context; RegisterUpdate(instance); RegisterPrimary(instance); /* looks like this settings reducing artifacts level */ settings->OrderSupport[NEG_PATBLT_INDEX] = FALSE; settings->OrderSupport[NEG_SCRBLT_INDEX] = FALSE; /* causing random disconnects */ settings->OrderSupport[NEG_ATEXTOUT_INDEX] = FALSE; settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE; settings->NoBitmapCompressionHeader = TRUE; settings->BitmapCompressionDisabled = TRUE; settings->FastPathOutput = FALSE; settings->BitmapCacheEnabled = FALSE; settings->BrushSupportLevel = 0; /* causing connection failure on recent versions of freerdp */ settings->OffscreenSupportLevel = 0; settings->OffscreenCacheSize = 0; /* following required at least on windows 7 */ settings->OrderSupport[NEG_MEMBLT_INDEX] = FALSE; settings->OrderSupport[NEG_MEM3BLT_INDEX] = FALSE; instance->context->cache = cache_new(settings); c->my_internals->clrconv = freerdp_clrconv_new(CLRCONV_ALPHA | CLRCONV_INVERT); if (!instance->context->cache) { return FALSE; } return TRUE; } static BOOL rdp_post_connect(freerdp *instance) { my_rdp_context *c = (my_rdp_context *)instance->context; c->my_internals->conn_state = rdp_conn_state_connected; rdpPointer p; memset(&p, 0, sizeof(p)); p.size = sizeof(my_rdp_pointer); register_pointer(&p); graphics_register_pointer(instance->context->graphics, &p); pointer_cache_register_callbacks(instance->update); c->my_internals->core->send_text_msg( "C:RDP session connection started.", c->my_internals->task_info); instance->update->DesktopResize(instance->context); return TRUE; } static DWORD rdp_verify_certificate(freerdp *instance, const char *common_name, const char *subject, const char *issuer, const char *fingerprint, BOOL host_mismatch) { WLog_INFO(TAG, "Certificate details:"); WLog_INFO(TAG, "\tSubject: %s", subject); WLog_INFO(TAG, "\tIssuer: %s", issuer); WLog_INFO(TAG, "\tThumbprint: %s", fingerprint); WLog_INFO(TAG, "The above X.509 certificate could not be verified, possibly " "because you do not have " "the CA certificate in your certificate store, or the " "certificate has expired. " "Please look at the OpenSSL documentation on how to add a " "private CA to the store."); return TRUE; /* ?? */ } /*static int rdp_receive_channel_data (freerdp* instance, UINT16 channelId, BYTE* data, int size, int flags, int total_size) { return freerdp_channels_data ( instance, channelId, data, size, flags, total_size); }*/ void rdp_register_base(freerdp *r) { r->PreConnect = rdp_pre_connect; r->PostConnect = rdp_post_connect; r->VerifyCertificate = rdp_verify_certificate; // r->ReceiveChannelData = rdp_receive_channel_data; r->ContextNew = rdp_context_new; r->ContextFree = rdp_context_free; }