GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/videosources_screen.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 0 234 0.0%
Functions: 0 21 0.0%
Branches: 0 92 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/io/videosources.h"
29 #include "gate/platforms.h"
30 #include "gate/results.h"
31
32 #if defined(GATE_SYS_WIN)
33 # if defined(GATE_SYS_WINSTORE) || defined(GATE_SYS_WIN16)
34 # define GATE_IO_VIDEO_NO_IMPL
35 # else
36 # define GATE_IO_VIDEO_WINAPI
37 # define GATE_IO_VIDEO_SCREEN_INTERFACE
38 # endif
39 #elif defined(GATE_SYS_ANDROID)
40 # define GATE_IO_VIDEO_ANDROID
41 #elif defined(GATE_SYS_LINUX)
42 # define GATE_IO_VIDEO_X11
43 # define GATE_IO_VIDEO_SCREEN_INTERFACE
44 #else
45 # define GATE_IO_VIDEO_NO_IMPL
46 #endif
47
48
49
50 #if defined(GATE_IO_VIDEO_SCREEN_INTERFACE)
51
52 static char const* screenctrl_get_interface_name(void* thisptr);
53 static void screenctrl_release(void* thisptr);
54 static int screenctrl_retain(void* thisptr);
55
56 static char const* screenctrl_get_id(void* thisptr);
57 static char const* screenctrl_get_name(void* thisptr);
58 static gate_intptr_t screenctrl_get_handle(void* thisptr);
59 static gate_size_t screenctrl_get_supported_formats(void* thisptr, gate_video_format_t* format_buffer, gate_size_t format_buffer_count);
60
61 static gate_result_t screenctrl_open(void* thisptr, gate_video_format_t const* format);
62 static gate_result_t screenctrl_close(void* thisptr);
63
64 static gate_result_t screenctrl_read(void* thisptr, gate_video_frame_t* frame);
65
66 static gate_result_t screenctrl_get_cursor_pos(void* thisptr, gate_int32_t* ptr_x, gate_int32_t* ptr_y);
67 static gate_result_t screenctrl_move_cursor(void* thisptr, gate_int32_t x, gate_int32_t y);
68 static gate_result_t screenctrl_change_cursor_button_state(void* thisptr, gate_int32_t x, gate_int32_t y, gate_enumint_t button_id, gate_enumint_t button_state);
69 static gate_result_t screenctrl_change_key_state(void* thisptr, gate_input_keycode_t key_code, gate_enumint_t key_state);
70
71 static GATE_INTERFACE_VTBL(gate_video_screencontrol) const* init_video_screencontrol_vtbl()
72 {
73 static GATE_INTERFACE_VTBL(gate_video_screencontrol) global_vtbl;
74 if (global_vtbl.get_interface_name == NULL)
75 {
76 GATE_INTERFACE_VTBL(gate_video_screencontrol) const local_vtbl =
77 {
78 &screenctrl_get_interface_name,
79 &screenctrl_release,
80 &screenctrl_retain,
81
82 &screenctrl_read,
83
84 &screenctrl_get_id,
85 &screenctrl_get_name,
86 &screenctrl_get_handle,
87 &screenctrl_get_supported_formats,
88
89 &screenctrl_open,
90 &screenctrl_close,
91
92 &screenctrl_get_cursor_pos,
93 &screenctrl_move_cursor,
94 &screenctrl_change_cursor_button_state,
95 &screenctrl_change_key_state
96 };
97 global_vtbl = local_vtbl;
98 }
99
100 return &global_vtbl;
101 }
102
103 #endif
104
105
106 #if defined(GATE_IO_VIDEO_WINAPI)
107
108 #include "gate/debugging.h"
109 #include "gate/graphics/platform/win32_gdi.h"
110
111 #if !defined(GATE_SYS_WINCE)
112 #define GATE_USE_NT_DESKTOP_API 1
113 #endif
114
115 typedef struct win32screen_class
116 {
117 GATE_INTERFACE_VTBL(gate_video_screencontrol) const* vtbl;
118
119 gate_atomic_int_t ref_counter;
120
121 unsigned x;
122 unsigned y;
123 unsigned width;
124 unsigned height;
125 unsigned bits_per_pixel;
126 unsigned line_len;
127
128 void* hdesk;
129 TCHAR deskname[128];
130 gate_size_t deskname_length;
131
132 HDC hscreen;
133 HDC hdc;
134 HGDIOBJ hbmp_backup;
135 HBITMAP hbmp;
136 void* bitmap_bits;
137 gate_size_t bitmap_bits_length;
138
139 } win32screen_t;
140
141 typedef struct
142 {
143 BITMAPINFO info;
144 RGBQUAD colors[256];
145 } BITMAPINFO_PAL;
146
147 static unsigned init_bmp_pal(RGBQUAD* pal)
148 {
149 gate_color_rgb_t gate_pal[256];
150 unsigned pal_len = (unsigned)gate_color_palette_rgb8_create(gate_pal);
151 unsigned ndx = 0;
152 for (; ndx != pal_len; ++ndx)
153 {
154 pal[ndx].rgbRed = gate_pal[ndx].r;
155 pal[ndx].rgbGreen = gate_pal[ndx].g;
156 pal[ndx].rgbBlue = gate_pal[ndx].b;
157 pal[ndx].rgbReserved = 0;
158 }
159 return pal_len;
160 }
161
162 static gate_bool_t win32_open_screen(win32screen_t* self)
163 {
164 gate_win32_userapi_t* const user32 = gate_win32_userapi();
165 gate_result_t succeeded = false;
166 HDC screen = NULL;
167 HDC mem = NULL;
168 HBITMAP bmp = NULL;
169 void* bits = NULL;
170 BITMAPINFO_PAL bmpinfo_pal;
171 BITMAPINFOHEADER* hdr = &bmpinfo_pal.info.bmiHeader;
172 RGBQUAD* ptr_rgb;
173
174 do
175 {
176 if (!user32) break;
177
178 screen = user32->UserGetDC(NULL);
179 if (!screen) break;
180
181 mem = gdi.GdiCreateCompatibleDC(screen);
182 if (!mem) break;
183
184 gate_mem_clear(&bmpinfo_pal, sizeof(bmpinfo_pal));
185 hdr->biSize = sizeof(BITMAPINFOHEADER);
186 hdr->biWidth = (LONG)self->width;
187 hdr->biHeight = (LONG)self->height;
188 hdr->biPlanes = 1;
189 hdr->biBitCount = self->bits_per_pixel;
190 hdr->biCompression = BI_RGB;
191 hdr->biSizeImage = 0;
192 hdr->biXPelsPerMeter = 0;
193 hdr->biYPelsPerMeter = 0;
194 hdr->biClrImportant = 0;
195 hdr->biClrUsed = 0;
196
197 if (self->bits_per_pixel == 1)
198 {
199 hdr->biClrUsed = 2;
200 ptr_rgb = &bmpinfo_pal.info.bmiColors[0];
201 ptr_rgb->rgbBlue = ptr_rgb->rgbGreen = ptr_rgb->rgbRed = ptr_rgb->rgbReserved = 0;
202 ptr_rgb = &bmpinfo_pal.info.bmiColors[1];
203 ptr_rgb->rgbBlue = ptr_rgb->rgbGreen = ptr_rgb->rgbRed = 255;
204 ptr_rgb->rgbReserved = 0;
205 }
206 else if (self->bits_per_pixel == 8)
207 {
208 hdr->biClrUsed = init_bmp_pal(&bmpinfo_pal.info.bmiColors[0]);
209 }
210 bmp = gdi.GdiCreateDIBSection(screen, &bmpinfo_pal.info, DIB_RGB_COLORS, &bits, NULL, 0);
211 if (NULL == bmp) break;
212
213 /* success-case: */
214 self->hscreen = screen;
215 self->hbmp_backup = gdi.GdiSelectObject(mem, (HGDIOBJ)bmp);
216 self->hdc = mem;
217 self->hbmp = bmp;
218 self->bitmap_bits = bits;
219 succeeded = true;
220 } while (0);
221
222 if (!succeeded)
223 {
224 if (mem) gdi.GdiDeleteDC(mem);
225 if (screen) user32->UserReleaseDC(NULL, screen);
226 }
227 return succeeded;
228 }
229
230 static void win32_close_screen(win32screen_t* self)
231 {
232 if (self->hdc)
233 {
234 gdi.GdiSelectObject(self->hdc, self->hbmp_backup);
235 gdi.GdiDeleteObject((HGDIOBJ)self->hbmp);
236 gdi.GdiDeleteDC(self->hdc);
237 gdi.GdiDeleteDC(self->hscreen);
238 self->hbmp_backup = NULL;
239 self->hbmp = NULL;
240 self->hdc = NULL;
241 }
242
243 if (self->hscreen)
244 {
245 self->hscreen = NULL;
246 }
247 }
248
249 #if defined(GATE_USE_NT_DESKTOP_API)
250
251 static gate_size_t win32_get_desktop_name(void* hdesk, TCHAR* desktop_name_buffer, gate_size_t desktop_name_buffer_capacity)
252 {
253 gate_win32_userapi_t* const user32 = gate_win32_userapi();
254 DWORD bytes_needed;
255
256 if (!user32 || !user32->UserGetUserObjectInformation ||
257 !user32->UserGetUserObjectInformation(hdesk, UOI_NAME, desktop_name_buffer, (DWORD)desktop_name_buffer_capacity * sizeof(TCHAR), &bytes_needed))
258 {
259 /* api not available, or failed */
260 return 0;
261 }
262 return bytes_needed / sizeof(TCHAR);
263 }
264
265 static gate_bool_t win32_open_input_desktop(void** ptr_hdesk, TCHAR* ptr_deskname, gate_size_t* ptr_deskname_length)
266 {
267 gate_win32_userapi_t* const user32 = gate_win32_userapi();
268 void* hdesk;
269
270 if (!user32 || !user32->UserOpenInputDesktop)
271 {
272 return false;
273 }
274
275 hdesk = user32->UserOpenInputDesktop(0, FALSE, GENERIC_ALL);
276 if (hdesk == NULL)
277 {
278 return false;
279 }
280 *ptr_deskname_length = win32_get_desktop_name(hdesk, ptr_deskname, *ptr_deskname_length);
281 *ptr_hdesk = hdesk;
282 return true;
283 }
284
285 static void win32_close_desktop(void** hdesk)
286 {
287 if (*hdesk)
288 {
289 gate_win32_userapi_t* const user32 = gate_win32_userapi();
290 user32->UserCloseDesktop((HDESK)*hdesk);
291 *hdesk = NULL;
292 }
293 }
294
295 static gate_bool_t win32_are_desktops_equal(void* desk1, TCHAR const* desk1name, gate_size_t desk1name_len, void* desk2, TCHAR const* desk2name, gate_size_t desk2name_len)
296 {
297 if (desk1 == desk2)
298 {
299 return true;
300 }
301 if (desk1name_len != desk2name_len)
302 {
303 return false;
304 }
305 else
306 {
307 return 0 == gate_win32_winstr_comp_range(desk1name, desk2name, desk1name_len);
308 }
309 }
310
311 static gate_bool_t win32_change_thread_desktop(void* target_desktop)
312 {
313 gate_win32_userapi_t* const user32 = gate_win32_userapi();
314 if (!user32 || !user32->UserSetThreadDesktop
315 || !user32->UserSetThreadDesktop((HDESK)target_desktop))
316 {
317 GATE_DEBUG_TRACE("SetThreadDesktop() failed");
318 return false;
319 }
320 return true;
321 }
322
323 static gate_bool_t screenctrl_update_desktop(win32screen_t* self)
324 {
325 void* input_hdesk = NULL;
326 TCHAR input_deskname[128];
327 gate_size_t input_deskname_len = sizeof(input_deskname) / sizeof(input_deskname[0]);
328 gate_bool_t result = win32_open_input_desktop(&input_hdesk, input_deskname, &input_deskname_len);
329 if (!result)
330 {
331 GATE_DEBUG_TRACE("Failed to open input desktop");
332 return false;
333 }
334 result = win32_are_desktops_equal(self->hdesk, self->deskname, self->deskname_length, input_hdesk, input_deskname, input_deskname_len);
335 if (result)
336 {
337 /* desktops are equal, no change required */
338 win32_close_desktop(&input_hdesk);
339 return true;
340 }
341 /* switch to new desktop */
342 result = win32_change_thread_desktop(input_hdesk);
343 if (!result)
344 {
345 GATE_DEBUG_TRACE("Failed to switch thread-desktop");
346 win32_close_desktop(&input_hdesk);
347 return false;
348 }
349 /* close old desktop handle and screen objects */
350 win32_close_screen(self);
351 win32_close_desktop(&self->hdesk);
352 /* install new desktop handle */
353 self->hdesk = input_hdesk;
354 gate_mem_copy(&self->deskname[0], input_deskname, input_deskname_len * sizeof(TCHAR));
355 self->deskname_length = input_deskname_len;
356 self->deskname[self->deskname_length] = 0;
357 return true;
358 }
359
360 #endif /* GATE_USE_NT_DESKTOP_API */
361
362
363 static gate_bool_t screenctrl_is_screen_opened(win32screen_t* self)
364 {
365 return (self->hscreen != NULL) && (self->hdc != NULL) && (self->hbmp != NULL);
366 }
367
368
369 static void screenctrl_destroy(win32screen_t* self)
370 {
371 win32_close_screen(self);
372 #if defined(GATE_USE_NT_DESKTOP_API)
373 win32_close_desktop(&self->hdesk);
374 #endif
375 }
376
377 static char const* screenctrl_get_interface_name(void* thisptr)
378 {
379 return GATE_INTERFACE_NAME_VIDEO_SOURCE_SCREENCONTROL;
380 }
381
382 static void screenctrl_release(void* thisptr)
383 {
384 win32screen_t* const self = (win32screen_t*)thisptr;
385 if (gate_atomic_int_dec(&self->ref_counter) == 0)
386 {
387 screenctrl_destroy(self);
388 }
389 }
390 static int screenctrl_retain(void* thisptr)
391 {
392 win32screen_t* const self = (win32screen_t*)thisptr;
393 return gate_atomic_int_inc(&self->ref_counter);
394 }
395
396 static char const* screenctrl_get_id(void* thisptr)
397 {
398 return "screen";
399 }
400 static char const* screenctrl_get_name(void* thisptr)
401 {
402 return "screen";
403 }
404 static gate_intptr_t screenctrl_get_handle(void* thisptr)
405 {
406 win32screen_t* const self = (win32screen_t*)thisptr;
407 return (gate_intptr_t)self->hscreen;
408 }
409
410 #ifndef SM_CXVIRTUALSCREEN
411 #define SM_CXVIRTUALSCREEN 78
412 #endif
413
414 #ifndef SM_CYVIRTUALSCREEN
415 #define SM_CYVIRTUALSCREEN 79
416 #endif
417
418 static gate_size_t screenctrl_get_supported_formats(void* thisptr, gate_video_format_t* format_buffer, gate_size_t format_buffer_count)
419 {
420 gate_win32_userapi_t* const user32 = gate_win32_userapi();
421 int sx, sy;
422
423 GATE_UNUSED_ARG(thisptr);
424
425 if ((format_buffer_count == 0) || (format_buffer == NULL))
426 {
427 return 0;
428 }
429
430 sx = user32->UserGetSystemMetrics(SM_CXVIRTUALSCREEN);
431 sy = user32->UserGetSystemMetrics(SM_CYVIRTUALSCREEN);
432 if (sx == 0) sx = user32->UserGetSystemMetrics(SM_CXSCREEN);
433 if (sy == 0) sy = user32->UserGetSystemMetrics(SM_CYSCREEN);
434
435 format_buffer->encoding_id = 0;
436 format_buffer->compression = 0;
437 format_buffer->frames_per_second = 5.0f;
438 format_buffer->width = sx;
439 format_buffer->height = sy;
440 format_buffer->bits_per_pixel = 24;
441
442 return 1;
443 }
444
445 static gate_bool_t screenctrl_is_opened(win32screen_t* self)
446 {
447 if ((self->width == 0) || (self->height == 0) || (self->bits_per_pixel == 0))
448 {
449 return false;
450 }
451 return true;
452 }
453
454 static gate_result_t screenctrl_open(void* thisptr, gate_video_format_t const* format)
455 {
456 win32screen_t* const self = (win32screen_t*)thisptr;
457
458 if (screenctrl_is_opened(self))
459 {
460 return GATE_RESULT_INVALIDSTATE;
461 }
462
463 if ((NULL == format) || (format->width == 0) || (format->height == 0))
464 {
465 return GATE_RESULT_INVALIDARG;
466 }
467
468 switch (format->bits_per_pixel)
469 {
470 case 1:
471 case 8:
472 case 16:
473 case 24:
474 self->bits_per_pixel = format->bits_per_pixel;
475 break;
476 default:
477 self->bits_per_pixel = 24;
478 break;
479 }
480
481 self->x = 0;
482 self->y = 0;
483 self->width = format->width;
484 self->height = format->height;
485 self->line_len = ((self->bits_per_pixel * self->width) / 8 + 3) & 0xfffffffc;
486
487 #if defined(GATE_USE_NT_DESKTOP_API)
488 screenctrl_update_desktop(self);
489 #endif
490
491 return GATE_RESULT_OK;
492 }
493
494 static gate_result_t screenctrl_close(void* thisptr)
495 {
496 win32screen_t* const self = (win32screen_t*)thisptr;
497
498 win32_close_screen(self);
499 #if defined(GATE_USE_NT_DESKTOP_API)
500 win32_close_desktop(&self->hdesk);
501 #endif
502
503 self->width = 0;
504 self->height = 0;
505 self->bits_per_pixel;
506 self->bitmap_bits = NULL;
507 self->bitmap_bits_length = 0;
508
509 return GATE_RESULT_OK;
510 }
511
512 static gate_result_t screenctrl_read(void* thisptr, gate_video_frame_t* frame)
513 {
514 win32screen_t* const self = (win32screen_t*)thisptr;
515 gate_bool_t update_succeeded;
516 gate_rasterimage_t raster = GATE_INIT_EMPTY;
517 unsigned y, x;
518 unsigned char const* ptr_src;
519 unsigned char* ptr_dst;
520
521 if ((self->width == 0) || (self->height == 0))
522 {
523 return GATE_RESULT_INVALIDSTATE;
524 }
525
526 #if defined(GATE_USE_NT_DESKTOP_API)
527 update_succeeded = screenctrl_update_desktop(self);
528 if (!update_succeeded)
529 {
530 GATE_DEBUG_TRACE("Failed to update desktop object");
531 }
532 #endif
533
534 if (!screenctrl_is_screen_opened(self))
535 {
536 if (!win32_open_screen(self))
537 {
538 GATE_DEBUG_TRACE("Failed to open screen");
539 return GATE_RESULT_FAILED;
540 }
541 }
542
543 update_succeeded = gdi.GdiBitBlt(self->hdc, 0, 0, self->width, self->height, self->hscreen, self->x, self->y, SRCCOPY);
544 if (!update_succeeded)
545 {
546 GATE_DEBUG_TRACE("Failed to copy screen into memory buffer");
547 return GATE_RESULT_FAILED;
548 }
549
550 switch (self->bits_per_pixel)
551 {
552 case 1:
553 {
554 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_PAL8, self->width, self->height, NULL))
555 {
556 return GATE_RESULT_OUTOFMEMORY;
557 }
558 for (y = 0; y != self->height; ++y)
559 {
560 ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len;
561 ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y);
562 for (x = 0; x != self->width; ++x)
563 {
564 gate_uint8_t b = ptr_src[x / 8];
565 gate_uint8_t bit = x % 8;
566 *ptr_dst = ((b & (1 << (7 - bit))) == 0) ? 0 : 15;
567 ++ptr_dst;
568 }
569 }
570 break;
571 }
572 case 8:
573 {
574 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_PAL8, self->width, self->height, NULL))
575 {
576 return GATE_RESULT_OUTOFMEMORY;
577 }
578 for (y = 0; y != self->height; ++y)
579 {
580 ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len;
581 ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y);
582 gate_mem_copy(ptr_dst, ptr_src, self->width);
583 }
584 break;
585 }
586 case 15:
587 case 16:
588 {
589 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_RGB555, self->width, self->height, NULL))
590 {
591 return GATE_RESULT_OUTOFMEMORY;
592 }
593 for (y = 0; y != self->height; ++y)
594 {
595 ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len;
596 ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y);
597 for (x = 0; x != self->width; ++x)
598 {
599 gate_uint8_t const b = (ptr_src[0] & 0x1f) << 3;
600 gate_uint8_t const g = ((ptr_src[0] >> 5) | ((ptr_src[1] & 0x03) << 3)) << 3;
601 gate_uint8_t const r = (ptr_src[1] & 0x7c) << 1;
602
603 unsigned const num = ((unsigned)(r >> 3)) << 10
604 | ((unsigned)(g >> 3)) << 5
605 | ((unsigned)(b >> 3));
606 ptr_dst[0] = (gate_uint8_t)(num & 0xff);
607 ptr_dst[1] = (gate_uint8_t)(num >> 8);
608
609 ptr_src += 2;
610 ptr_dst += 2;
611 }
612 }
613 break;
614 }
615 case 24:
616 {
617 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_RGB24, self->width, self->height, NULL))
618 {
619 return GATE_RESULT_OUTOFMEMORY;
620 }
621 for (y = 0; y != self->height; ++y)
622 {
623 ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len;
624 ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y);
625 for (x = 0; x != self->width; ++x)
626 {
627 /* BGR to RGB */
628 ptr_dst[0] = ptr_src[2];
629 ptr_dst[1] = ptr_src[1];
630 ptr_dst[2] = ptr_src[0];
631 ptr_src += 3;
632 ptr_dst += 3;
633 }
634 }
635 break;
636 }
637 default:
638 {
639 return GATE_RESULT_NOTSUPPORTED;
640 }
641 }
642
643 frame->format.encoding_id = 0;
644 frame->format.compression = 0;
645 frame->format.frames_per_second = 5.0f;
646 frame->format.width = self->width;
647 frame->format.height = self->height;
648 frame->format.bits_per_pixel = self->bits_per_pixel;
649
650 frame->record_time = 0;
651 gate_mem_copy(&frame->image, &raster, sizeof(raster));
652 return GATE_RESULT_OK;
653 }
654
655 static gate_result_t win32_send_input(INPUT* inp)
656 {
657 gate_win32_userapi_t* const user32 = gate_win32_userapi();
658 UINT result;
659
660 if (!user32)
661 {
662 return GATE_RESULT_NOTAVAILABLE;
663 }
664
665 if (user32->UserSendInput)
666 {
667 result = user32->UserSendInput(1, inp, sizeof(INPUT));
668 if (result != 1)
669 {
670 return GATE_RESULT_FAILED;
671 }
672 return GATE_RESULT_OK;
673 }
674
675 /* win95 NT 3.1 do not support SendInput: */
676 if ((inp->type == INPUT_MOUSE) && (user32->UserMouse_event))
677 {
678 user32->UserMouse_event(inp->mi.dwFlags, inp->mi.dx, inp->mi.dy, inp->mi.mouseData, inp->mi.dwExtraInfo);
679 return GATE_RESULT_OK;
680 }
681
682 if ((inp->type == INPUT_KEYBOARD) && (user32->UserKeybd_event))
683 {
684 user32->UserKeybd_event((BYTE)inp->ki.wVk, (BYTE)inp->ki.wScan, inp->ki.dwFlags, inp->ki.dwExtraInfo);
685 return GATE_RESULT_OK;
686 }
687
688 return GATE_RESULT_NOTSUPPORTED;
689 }
690
691 #ifndef MOUSEEVENTF_VIRTUALDESK
692 #define MOUSEEVENTF_VIRTUALDESK 0x4000
693 #endif
694
695 static void win32_prepare_mouse_input(INPUT* inp, gate_int32_t x, gate_int32_t y)
696 {
697 gate_win32_userapi_t* const user32 = gate_win32_userapi();
698
699 int screen_width;
700 int screen_height;
701
702 if (user32)
703 {
704 screen_width = user32->UserGetSystemMetrics(SM_CXVIRTUALSCREEN);
705 screen_height = user32->UserGetSystemMetrics(SM_CYVIRTUALSCREEN);
706 if (screen_width == 0) screen_width = user32->UserGetSystemMetrics(SM_CXSCREEN);
707 if (screen_height == 0) screen_height = user32->UserGetSystemMetrics(SM_CYSCREEN);
708 inp->mi.dwExtraInfo = user32->UserGetMessageExtraInfo();
709 }
710 else
711 {
712 screen_width = 640;
713 screen_height = 480;
714 inp->mi.dwExtraInfo = 0;
715 }
716
717 inp->type = INPUT_MOUSE;
718 inp->mi.dx = (screen_width > 0) ? (x * 65536 / screen_width) : 0;
719 inp->mi.dy = (screen_height > 0) ? (y * 65536 / screen_height) : 0;
720 inp->mi.mouseData = 0;
721 inp->mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK;
722 inp->mi.time = 0;
723 }
724
725 static gate_result_t screenctrl_get_cursor_pos(void* thisptr, gate_int32_t* ptr_x, gate_int32_t* ptr_y)
726 {
727 gate_win32_userapi_t* const user32 = gate_win32_userapi();
728 POINT pnt;
729 if (!user32)
730 {
731 return GATE_RESULT_FAILED;
732 }
733 if (!user32->UserGetCursorPos(&pnt))
734 {
735 return GATE_RESULT_FAILED;
736 }
737 if (ptr_x) *ptr_x = pnt.x;
738 if (ptr_y) *ptr_y = pnt.y;
739 return GATE_RESULT_OK;
740 }
741 static gate_result_t screenctrl_move_cursor(void* thisptr, gate_int32_t x, gate_int32_t y)
742 {
743 INPUT inp;
744 win32_prepare_mouse_input(&inp, x, y);
745 return win32_send_input(&inp);
746 }
747 static gate_result_t screenctrl_change_cursor_button_state(void* thisptr, gate_int32_t x, gate_int32_t y, gate_enumint_t button_id, gate_enumint_t button_state)
748 {
749 INPUT inp;
750 win32_prepare_mouse_input(&inp, x, y);
751 if (GATE_FLAG_ENABLED(button_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN))
752 {
753 /* mouse down */
754 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT) inp.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
755 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE) inp.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
756 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT) inp.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
757 }
758 else if (GATE_FLAG_ENABLED(button_state, GATE_VIDEO_SCREENCONTROL_STATE_UP))
759 {
760 /* mouse up */
761 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT) inp.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
762 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE) inp.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
763 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT) inp.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
764 }
765 return win32_send_input(&inp);
766 }
767
768 static gate_input_keystates_t extract_state_keys_from_key_state_flags(gate_enumint_t key_state)
769 {
770 gate_input_keystates_t value = 0;
771 if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_CTRL)) value |= GATE_KBD_KEYSTATE_CTRL;
772 if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_MENU)) value |= GATE_KBD_KEYSTATE_MENU;
773 if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_SHIFT)) value |= GATE_KBD_KEYSTATE_SHIFT;
774 return value;
775 }
776
777 static void win32_prepare_key_input(INPUT* inp, gate_input_keycode_t keycode, gate_input_keystates_t keystates, gate_bool_t down)
778 {
779 gate_win32_userapi_t* const user32 = gate_win32_userapi();
780 gate_input_nativekeycode_t vk = 0;
781
782 if (user32 && user32->UserGetMessageExtraInfo)
783 {
784 inp->ki.dwExtraInfo = user32->UserGetMessageExtraInfo();
785 }
786 else
787 {
788 inp->ki.dwExtraInfo = 0;
789 }
790
791 inp->type = INPUT_KEYBOARD;
792 gate_keyboard_build_native_key(keycode, keystates, &vk);
793 inp->ki.wVk = (WORD)vk;
794 inp->ki.wScan = 0;
795 inp->ki.dwFlags = down ? 0 : KEYEVENTF_KEYUP;
796 inp->ki.time = 0;
797 }
798
799 static gate_result_t screenctrl_change_key_state(void* thisptr, gate_input_keycode_t key_code, gate_enumint_t key_state)
800 {
801 INPUT inp;
802 gate_input_keystates_t state_keys = extract_state_keys_from_key_state_flags(key_state);
803 win32_prepare_key_input(&inp, key_code, state_keys, GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN));
804 return win32_send_input(&inp);
805 }
806
807
808 gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source)
809 {
810 gate_result_t ret = GATE_RESULT_FAILED;
811 win32screen_t* impl = NULL;
812
813 do
814 {
815 ret = gate_win32_gdi_init();
816 GATE_BREAK_IF_FAILED(ret);
817
818 impl = (win32screen_t*)gate_mem_alloc(sizeof(win32screen_t));
819 if (impl == NULL)
820 {
821 ret = GATE_RESULT_OUTOFMEMORY;
822 break;
823 }
824 gate_mem_clear(impl, sizeof(win32screen_t));
825 impl->vtbl = init_video_screencontrol_vtbl();
826 gate_atomic_int_init(&impl->ref_counter, 1);
827
828 if (ptr_source)
829 {
830 *ptr_source = (gate_video_screencontrol_t*)impl;
831 impl = NULL;
832 }
833 ret = GATE_RESULT_OK;
834 } while (0);
835
836 if (impl != NULL)
837 {
838 screenctrl_release(impl);
839 }
840
841 return ret;
842 }
843
844
845 #endif
846
847
848 #if defined(GATE_IO_VIDEO_X11)
849
850 #include "gate/platform/posix/xlib.h"
851 #include "gate/debugging.h"
852
853 typedef struct x11screen_class
854 {
855 GATE_INTERFACE_VTBL(gate_video_screencontrol) const* vtbl;
856
857 gate_atomic_int_t ref_counter;
858 Display* x11_display;
859 Window x11_root;
860 gate_video_format_t format;
861 GC x11_gc;
862 int x11_screen;
863 Colormap x11_colmap;
864 } x11screen_t;
865
866
867 static gate_result_t x11screen_init(x11screen_t* self)
868 {
869 gate_result_t result;
870
871 do
872 {
873 result = gate_xlib_load_functions();
874 GATE_BREAK_IF_FAILED(result);
875
876 self->x11_display = xlib.XOpenDisplay(NULL);
877 if (self->x11_display == NULL)
878 {
879 self->x11_display = xlib.XOpenDisplay(":0");
880 }
881 if (self->x11_display == NULL)
882 {
883 GATE_DEBUG_TRACE("Failed to open X11 display");
884 result = GATE_RESULT_FAILED;
885 break;
886 }
887 self->x11_root = xlib.XDefaultRootWindow(self->x11_display);
888
889 } while (0);
890
891 return result;
892 }
893
894 static void x11screen_destroy(x11screen_t* self)
895 {
896
897 if (self->x11_display)
898 {
899 xlib.XCloseDisplay(self->x11_display);
900 self->x11_display = NULL;
901 }
902 }
903
904
905 static char const* screenctrl_get_interface_name(void* thisptr)
906 {
907 return GATE_INTERFACE_NAME_VIDEO_SOURCE_SCREENCONTROL;
908 }
909
910
911 static void screenctrl_release(void* thisptr)
912 {
913 x11screen_t* const self = (x11screen_t*)thisptr;
914 if (gate_atomic_int_dec(&self->ref_counter) == 0)
915 {
916 x11screen_destroy(self);
917 gate_mem_dealloc(self);
918 }
919 }
920 static int screenctrl_retain(void* thisptr)
921 {
922 x11screen_t* const self = (x11screen_t*)thisptr;
923 return gate_atomic_int_inc(&self->ref_counter);
924 }
925 static char const* screenctrl_get_id(void* thisptr)
926 {
927 return "screen";
928 }
929 static char const* screenctrl_get_name(void* thisptr)
930 {
931 return "screen";
932 }
933 static gate_intptr_t screenctrl_get_handle(void* thisptr)
934 {
935 x11screen_t* const self = (x11screen_t*)thisptr;
936 return (gate_intptr_t)self->x11_display;
937 }
938 static gate_size_t screenctrl_get_supported_formats(void* thisptr, gate_video_format_t* format_buffer, gate_size_t format_buffer_count)
939 {
940 x11screen_t* const self = (x11screen_t*)thisptr;
941 XWindowAttributes attrs = GATE_INIT_EMPTY;
942
943 if ((format_buffer == NULL) || (format_buffer_count < 1))
944 {
945 GATE_DEBUG_TRACE("Not enough space in output buffer");
946 return 0;
947 }
948
949 /* get screen dimensions */
950 xlib.XGetWindowAttributes(self->x11_display, self->x11_root, &attrs);
951
952 format_buffer->encoding_id = 0;
953 format_buffer->compression = 0;
954 format_buffer->frames_per_second = 5;
955 format_buffer->width = (gate_uint32_t)attrs.width;
956 format_buffer->height = (gate_uint32_t)attrs.height;
957 format_buffer->bits_per_pixel = 32;
958
959 return 1; /* one entry was used */
960 }
961
962 static gate_result_t screenctrl_open(void* thisptr, gate_video_format_t const* format)
963 {
964 x11screen_t* const self = (x11screen_t*)thisptr;
965
966 if (self->x11_gc != NULL)
967 {
968 GATE_DEBUG_TRACE("Error: X11 GC is already initialized");
969 return GATE_RESULT_INVALIDSTATE;
970 }
971
972 gate_mem_copy(&self->format, format, sizeof(gate_video_format_t));
973
974 self->x11_gc = xlib.XCreateGC(self->x11_display, self->x11_root, 0, NULL);
975 if (!self->x11_gc)
976 {
977 GATE_DEBUG_TRACE("Error: Failed to create GC on current display");
978 return GATE_RESULT_FAILED;
979 }
980 self->x11_screen = xlib.XDefaultScreen(self->x11_display);
981 self->x11_colmap = xlib.XDefaultColormap(self->x11_display, self->x11_screen);
982 return GATE_RESULT_OK;
983 }
984 static gate_result_t screenctrl_close(void* thisptr)
985 {
986 x11screen_t* const self = (x11screen_t*)thisptr;
987
988 if (!self->x11_gc)
989 {
990 xlib.XFreeGC(self->x11_display, self->x11_gc);
991 self->x11_gc = NULL;
992 self->x11_screen = 0;
993 self->x11_colmap = 0;
994 }
995 return GATE_RESULT_OK;
996 }
997
998 static gate_result_t ximage32_to_raster(XImage* ptr_ximage, gate_rasterimage_t* ptr_raster)
999 {
1000 unsigned char const* ptr_src_pixel;
1001 unsigned int y;
1002
1003 if (NULL == gate_rasterimage_create(ptr_raster, GATE_IMAGE_PIXELFORMAT_RGB24,
1004 (unsigned)ptr_ximage->width, (unsigned)ptr_ximage->height, NULL))
1005 {
1006 return GATE_RESULT_OUTOFMEMORY;
1007 }
1008
1009 ptr_src_pixel = (unsigned char const*)ptr_ximage->data;
1010 for (y = 0; y != ptr_raster->height; ++y)
1011 {
1012 gate_color_rgb_t* ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y);
1013 unsigned int x;
1014 for (x = 0; x != ptr_raster->width; ++x)
1015 {
1016 ptr_dst_pixel->b = *(ptr_src_pixel++);
1017 ptr_dst_pixel->g = *(ptr_src_pixel++);
1018 ptr_dst_pixel->r = *(ptr_src_pixel++);
1019 ++ptr_src_pixel; /* skip A value */
1020 ++ptr_dst_pixel;
1021 }
1022 }
1023 return GATE_RESULT_OK;
1024 }
1025
1026 static gate_result_t ximage16_to_raster(XImage* ptr_ximage, gate_rasterimage_t* ptr_raster)
1027 {
1028 unsigned char const* ptr_src_pixel;
1029 unsigned int y;
1030
1031 if (NULL == gate_rasterimage_create(ptr_raster, GATE_IMAGE_PIXELFORMAT_RGB24,
1032 (unsigned)ptr_ximage->width, (unsigned)ptr_ximage->height, NULL))
1033 {
1034 return GATE_RESULT_OUTOFMEMORY;
1035 }
1036
1037 ptr_src_pixel = (unsigned char const*)ptr_ximage->data;;
1038 for (y = 0; y != ptr_raster->height; ++y)
1039 {
1040 gate_color_rgb_t* ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y);
1041 unsigned int x;
1042 for (x = 0; x != ptr_raster->width; ++x)
1043 {
1044 const gate_uint16_t col = (gate_uint16_t)(ptr_src_pixel[0]) | (((gate_uint16_t)ptr_src_pixel[1]) << 8);
1045 ptr_dst_pixel->b = (gate_uint8_t)((col & 0x001F) << 3);
1046 ptr_dst_pixel->g = (gate_uint8_t)((col & 0x07e0) >> 3);
1047 ptr_dst_pixel->r = (gate_uint8_t)((col & 0xF800) >> 8);
1048 ptr_src_pixel += 2;
1049 ++ptr_dst_pixel;
1050 }
1051 }
1052 return GATE_RESULT_OK;
1053 }
1054
1055 static gate_result_t ximage_to_raster(Display* display, Colormap colmap, XImage* ptr_ximage, gate_rasterimage_t* ptr_raster)
1056 {
1057 unsigned int y;
1058
1059 if (NULL == gate_rasterimage_create(ptr_raster, GATE_IMAGE_PIXELFORMAT_RGB24,
1060 (unsigned)ptr_ximage->width, (unsigned)ptr_ximage->height, NULL))
1061 {
1062 return GATE_RESULT_OUTOFMEMORY;
1063 }
1064
1065 for (y = 0; y != ptr_raster->height; ++y)
1066 {
1067 gate_color_rgb_t* ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y);
1068 unsigned int x;
1069 for (x = 0; x != ptr_raster->width; ++x)
1070 {
1071 XColor xcol;
1072 xcol.pixel = xlib.XGetPixel(ptr_ximage, (int)x, (int)y);
1073 xlib.XQueryColor(display, colmap, &xcol);
1074
1075 ptr_dst_pixel->r = (gate_uint8_t)(xcol.red >> 8);
1076 ptr_dst_pixel->g = (gate_uint8_t)(xcol.green >> 8);
1077 ptr_dst_pixel->b = (gate_uint8_t)(xcol.blue >> 8);
1078 ++ptr_dst_pixel;
1079 }
1080 }
1081 return GATE_RESULT_OK;
1082 }
1083
1084 static gate_result_t screenctrl_read(void* thisptr, gate_video_frame_t* frame)
1085 {
1086 gate_result_t ret = GATE_RESULT_FAILED;
1087 x11screen_t* const self = (x11screen_t*)thisptr;
1088 XImage* ptr_ximage = NULL;
1089 gate_rasterimage_t raster = GATE_INIT_EMPTY;
1090
1091 do
1092 {
1093 ptr_ximage = xlib.XGetImage(self->x11_display, self->x11_root,
1094 0, 0, self->format.width, self->format.height, AllPlanes, ZPixmap);
1095 if (ptr_ximage == NULL)
1096 {
1097 ret = GATE_RESULT_FAILED;
1098 break;
1099 }
1100
1101 if ((ptr_ximage->bits_per_pixel == 32) && (ptr_ximage->depth == 24))
1102 {
1103 ret = ximage32_to_raster(ptr_ximage, &raster);
1104 }
1105 else if ((ptr_ximage->bits_per_pixel == 16) && (ptr_ximage->depth == 16))
1106 {
1107 ret = ximage16_to_raster(ptr_ximage, &raster);
1108 }
1109 else
1110 {
1111 ret = ximage_to_raster(self->x11_display, self->x11_colmap, ptr_ximage, &raster);
1112 }
1113
1114 GATE_BREAK_IF_FAILED(ret);
1115
1116 frame->format.bits_per_pixel = raster.bits_per_pixel;
1117 frame->format.compression = 0;
1118 frame->format.encoding_id = 0;
1119 frame->format.frames_per_second = self->format.frames_per_second;
1120 frame->format.width = raster.width;
1121 frame->format.height = raster.height;
1122 gate_rasterimage_duplicate(&frame->image, &raster);
1123 frame->record_time = 0;
1124
1125 ret = GATE_RESULT_OK;
1126 } while (0);
1127
1128 gate_rasterimage_release(&raster);
1129
1130 if (ptr_ximage != NULL)
1131 {
1132 xlib.XDestroyImage(ptr_ximage);
1133 }
1134
1135 return ret;
1136 }
1137
1138 static gate_result_t screenctrl_get_cursor_pos(void* thisptr, gate_int32_t* ptr_x, gate_int32_t* ptr_y)
1139 {
1140 gate_result_t ret = GATE_RESULT_FAILED;
1141 x11screen_t* const self = (x11screen_t*)thisptr;
1142 Window win, subwin;
1143 int gx, gy, wx, wy;
1144 unsigned int state;
1145
1146 if (xlib.XQueryPointer(self->x11_display, self->x11_root, &win, &subwin, &gx, &gy, &wx, &wy, &state))
1147 {
1148 if (ptr_x) *ptr_x = gx;
1149 if (ptr_y) *ptr_y = gy;
1150 return GATE_RESULT_OK;
1151 }
1152 return GATE_RESULT_FAILED;
1153 }
1154
1155 static gate_result_t screenctrl_move_cursor(void* thisptr, gate_int32_t x, gate_int32_t y)
1156 {
1157 gate_result_t ret = GATE_RESULT_FAILED;
1158 x11screen_t* const self = (x11screen_t*)thisptr;
1159 xlib.XWarpPointer(self->x11_display, None, self->x11_root, 0, 0, 0, 0, (int)x, (int)y);
1160 return GATE_RESULT_OK;
1161 }
1162
1163 static gate_result_t screenctrl_change_cursor_button_state(void* thisptr, gate_int32_t x, gate_int32_t y, gate_enumint_t button_id, gate_enumint_t button_state)
1164 {
1165 /* http://www.linuxquestions.org/questions/programming-9/simulating-a-mouse-click-594576/ */
1166
1167 gate_result_t ret = GATE_RESULT_FAILED;
1168 x11screen_t* const self = (x11screen_t*)thisptr;
1169 XEvent xevt = GATE_INIT_EMPTY;
1170 XButtonEvent* evt = &xevt.xbutton;
1171
1172 xlib.XWarpPointer(self->x11_display, None, self->x11_root, 0, 0, 0, 0, (int)x, (int)y);
1173
1174 /* find inner sub-window */
1175 evt->type = (button_state == GATE_VIDEO_SCREENCONTROL_STATE_DOWN) ? ButtonPress : ButtonRelease;
1176 evt->display = self->x11_display;
1177 evt->same_screen = True;
1178 evt->time = CurrentTime;
1179
1180 evt->subwindow = self->x11_root;
1181 do
1182 {
1183 evt->window = evt->subwindow;
1184 xlib.XQueryPointer(self->x11_display, evt->window, &evt->root, &evt->subwindow, &evt->x_root, &evt->y_root, &evt->x, &evt->y, &evt->state);
1185 } while (evt->subwindow != 0);
1186
1187
1188
1189 evt->state = 0;
1190 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT)
1191 {
1192 evt->button = Button1;
1193 evt->state |= Button1Mask;
1194 }
1195 else if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE)
1196 {
1197 evt->button = Button2;
1198 evt->state |= Button2Mask;
1199 }
1200 else if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT)
1201 {
1202 evt->button = Button3;
1203 evt->state |= Button3Mask;
1204 }
1205
1206 xlib.XSendEvent(self->x11_display, PointerWindow, True, 0xfff, &xevt);
1207 xlib.XFlush(self->x11_display);
1208
1209 return GATE_RESULT_OK;
1210 }
1211
1212 static gate_result_t screenctrl_change_key_state(void* thisptr, gate_input_keycode_t key_code, gate_enumint_t key_state)
1213 {
1214 gate_result_t ret = GATE_RESULT_FAILED;
1215 x11screen_t* const self = (x11screen_t*)thisptr;
1216 XKeyEvent evt;
1217 int focus_state;
1218 Window focus_win = self->x11_root;
1219 KeySym x11_key_sym = key_code;
1220 gate_bool_t key_down = GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN);
1221 unsigned int x11_state = 0;
1222
1223 if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_CTRL))
1224 {
1225 x11_state |= ControlMask;
1226 }
1227 if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_MENU))
1228 {
1229 x11_state |= Mod1Mask;
1230 }
1231 if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_SHIFT))
1232 {
1233 x11_state |= ShiftMask;
1234 }
1235
1236 xlib.XGetInputFocus(self->x11_display, &focus_win, &focus_state);
1237
1238 evt.display = self->x11_display;
1239 evt.window = focus_win;
1240 evt.root = self->x11_root;
1241 evt.subwindow = None;
1242 evt.time = CurrentTime;
1243 evt.x = 1;
1244 evt.y = 1;
1245 evt.x_root = 1;
1246 evt.y_root = 1;
1247 evt.same_screen = True;
1248 evt.send_event = True;
1249 evt.keycode = xlib.XKeysymToKeycode(self->x11_display, x11_key_sym);
1250 evt.state = x11_state;
1251 evt.type = key_down ? KeyPress : KeyRelease;
1252 xlib.XSendEvent(evt.display, evt.window, True, KeyPressMask, (XEvent*)&evt);
1253
1254 return GATE_RESULT_OK;
1255 }
1256
1257
1258
1259 gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source)
1260 {
1261 gate_result_t ret = GATE_RESULT_FAILED;
1262 x11screen_t* impl = NULL;
1263
1264 do
1265 {
1266 impl = (x11screen_t*)gate_mem_alloc(sizeof(x11screen_t));
1267 if (impl == NULL)
1268 {
1269 ret = GATE_RESULT_OUTOFMEMORY;
1270 break;
1271 }
1272 gate_mem_clear(impl, sizeof(x11screen_t));
1273 impl->vtbl = init_video_screencontrol_vtbl();
1274 gate_atomic_int_init(&impl->ref_counter, 1);
1275
1276 ret = x11screen_init(impl);
1277 GATE_BREAK_IF_FAILED(ret);
1278
1279 if (ptr_source)
1280 {
1281 *ptr_source = (gate_video_screencontrol_t*)impl;
1282 impl = NULL;
1283 }
1284 ret = GATE_RESULT_OK;
1285 } while (0);
1286
1287 if (impl != NULL)
1288 {
1289 screenctrl_release(impl);
1290 }
1291
1292 return ret;
1293 }
1294
1295 #endif
1296
1297 #if defined(GATE_IO_VIDEO_ANDROID)
1298
1299 gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source)
1300 {
1301 GATE_UNUSED_ARG(ptr_source);
1302 /* TODO */
1303 return GATE_RESULT_NOTSUPPORTED;
1304 }
1305
1306 #endif
1307
1308
1309 #if defined(GATE_IO_VIDEO_NO_IMPL)
1310
1311 gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source)
1312 {
1313 GATE_UNUSED_ARG(ptr_source);
1314 return GATE_RESULT_NOTSUPPORTED;
1315 }
1316
1317 #endif
1318