GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/videosources_screen.c
Date: 2025-09-14 13:10:38
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 win32screen_t* const self = (win32screen_t*)thisptr;
422 int sx, sy;
423
424 if ((format_buffer_count == 0) || (format_buffer == NULL))
425 {
426 return 0;
427 }
428
429 sx = user32->UserGetSystemMetrics(SM_CXVIRTUALSCREEN);
430 sy = user32->UserGetSystemMetrics(SM_CYVIRTUALSCREEN);
431 if (sx == 0) sx = user32->UserGetSystemMetrics(SM_CXSCREEN);
432 if (sy == 0) sy = user32->UserGetSystemMetrics(SM_CYSCREEN);
433
434 format_buffer->encoding_id = 0;
435 format_buffer->compression = 0;
436 format_buffer->frames_per_second = 5.0f;
437 format_buffer->width = sx;
438 format_buffer->height = sy;
439 format_buffer->bits_per_pixel = 24;
440
441 return 1;
442 }
443
444 static gate_bool_t screenctrl_is_opened(win32screen_t* self)
445 {
446 if ((self->width == 0) || (self->height == 0) || (self->bits_per_pixel == 0))
447 {
448 return false;
449 }
450 return true;
451 }
452
453 static gate_result_t screenctrl_open(void* thisptr, gate_video_format_t const* format)
454 {
455 win32screen_t* const self = (win32screen_t*)thisptr;
456
457 if (screenctrl_is_opened(self))
458 {
459 return GATE_RESULT_INVALIDSTATE;
460 }
461
462 if ((NULL == format) || (format->width == 0) || (format->height == 0))
463 {
464 return GATE_RESULT_INVALIDARG;
465 }
466
467 switch (format->bits_per_pixel)
468 {
469 case 1:
470 case 8:
471 case 16:
472 case 24:
473 self->bits_per_pixel = format->bits_per_pixel;
474 break;
475 default:
476 self->bits_per_pixel = 24;
477 break;
478 }
479
480 self->x = 0;
481 self->y = 0;
482 self->width = format->width;
483 self->height = format->height;
484 self->line_len = ((self->bits_per_pixel * self->width) / 8 + 3) & 0xfffffffc;
485
486 #if defined(GATE_USE_NT_DESKTOP_API)
487 screenctrl_update_desktop(self);
488 #endif
489
490 return GATE_RESULT_OK;
491 }
492
493 static gate_result_t screenctrl_close(void* thisptr)
494 {
495 win32screen_t* const self = (win32screen_t*)thisptr;
496
497 win32_close_screen(self);
498 #if defined(GATE_USE_NT_DESKTOP_API)
499 win32_close_desktop(&self->hdesk);
500 #endif
501
502 self->width = 0;
503 self->height = 0;
504 self->bits_per_pixel;
505 self->bitmap_bits = NULL;
506 self->bitmap_bits_length = 0;
507
508 return GATE_RESULT_OK;
509 }
510
511 static gate_result_t screenctrl_read(void* thisptr, gate_video_frame_t* frame)
512 {
513 win32screen_t* const self = (win32screen_t*)thisptr;
514 gate_bool_t update_succeeded;
515 gate_rasterimage_t raster = GATE_INIT_EMPTY;
516 unsigned y, x;
517 unsigned char const* ptr_src;
518 unsigned char* ptr_dst;
519
520 if ((self->width == 0) || (self->height == 0))
521 {
522 return GATE_RESULT_INVALIDSTATE;
523 }
524
525 #if defined(GATE_USE_NT_DESKTOP_API)
526 update_succeeded = screenctrl_update_desktop(self);
527 if (!update_succeeded)
528 {
529 GATE_DEBUG_TRACE("Failed to update desktop object");
530 }
531 #endif
532
533 if (!screenctrl_is_screen_opened(self))
534 {
535 if (!win32_open_screen(self))
536 {
537 GATE_DEBUG_TRACE("Failed to open screen");
538 return GATE_RESULT_FAILED;
539 }
540 }
541
542 update_succeeded = gdi.GdiBitBlt(self->hdc, 0, 0, self->width, self->height, self->hscreen, self->x, self->y, SRCCOPY);
543 if (!update_succeeded)
544 {
545 GATE_DEBUG_TRACE("Failed to copy screen into memory buffer");
546 return GATE_RESULT_FAILED;
547 }
548
549 switch (self->bits_per_pixel)
550 {
551 case 1:
552 {
553 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_PAL8, self->width, self->height, NULL))
554 {
555 return GATE_RESULT_OUTOFMEMORY;
556 }
557 for (y = 0; y != self->height; ++y)
558 {
559 ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len;
560 ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y);
561 for (x = 0; x != self->width; ++x)
562 {
563 gate_uint8_t b = ptr_src[x / 8];
564 gate_uint8_t bit = x % 8;
565 *ptr_dst = ((b & (1 << (7 - bit))) == 0) ? 0 : 15;
566 ++ptr_dst;
567 }
568 }
569 break;
570 }
571 case 8:
572 {
573 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_PAL8, self->width, self->height, NULL))
574 {
575 return GATE_RESULT_OUTOFMEMORY;
576 }
577 for (y = 0; y != self->height; ++y)
578 {
579 ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len;
580 ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y);
581 gate_mem_copy(ptr_dst, ptr_src, self->width);
582 }
583 break;
584 }
585 case 15:
586 case 16:
587 {
588 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_RGB555, self->width, self->height, NULL))
589 {
590 return GATE_RESULT_OUTOFMEMORY;
591 }
592 for (y = 0; y != self->height; ++y)
593 {
594 ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len;
595 ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y);
596 for (x = 0; x != self->width; ++x)
597 {
598 gate_uint8_t const b = (ptr_src[0] & 0x1f) << 3;
599 gate_uint8_t const g = ((ptr_src[0] >> 5) | ((ptr_src[1] & 0x03) << 3)) << 3;
600 gate_uint8_t const r = (ptr_src[1] & 0x7c) << 1;
601
602 unsigned const num = ((unsigned)(r >> 3)) << 10
603 | ((unsigned)(g >> 3)) << 5
604 | ((unsigned)(b >> 3));
605 ptr_dst[0] = (gate_uint8_t)(num & 0xff);
606 ptr_dst[1] = (gate_uint8_t)(num >> 8);
607
608 ptr_src += 2;
609 ptr_dst += 2;
610 }
611 }
612 break;
613 }
614 case 24:
615 {
616 if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_RGB24, self->width, self->height, NULL))
617 {
618 return GATE_RESULT_OUTOFMEMORY;
619 }
620 for (y = 0; y != self->height; ++y)
621 {
622 ptr_src = (unsigned char const*)self->bitmap_bits + (self->height - 1 - y) * self->line_len;
623 ptr_dst = (unsigned char*)gate_rasterimage_get_line_ptr(&raster, y);
624 for (x = 0; x != self->width; ++x)
625 {
626 /* BGR to RGB */
627 ptr_dst[0] = ptr_src[2];
628 ptr_dst[1] = ptr_src[1];
629 ptr_dst[2] = ptr_src[0];
630 ptr_src += 3;
631 ptr_dst += 3;
632 }
633 }
634 break;
635 }
636 default:
637 {
638 return GATE_RESULT_NOTSUPPORTED;
639 }
640 }
641
642 frame->format.encoding_id = 0;
643 frame->format.compression = 0;
644 frame->format.frames_per_second = 5.0f;
645 frame->format.width = self->width;
646 frame->format.height = self->height;
647 frame->format.bits_per_pixel = self->bits_per_pixel;
648
649 frame->record_time = 0;
650 gate_mem_copy(&frame->image, &raster, sizeof(raster));
651 return GATE_RESULT_OK;
652 }
653
654 static gate_result_t win32_send_input(INPUT* inp)
655 {
656 gate_win32_userapi_t* const user32 = gate_win32_userapi();
657 UINT result;
658
659 if (!user32)
660 {
661 return GATE_RESULT_NOTAVAILABLE;
662 }
663
664 if (user32->UserSendInput)
665 {
666 result = user32->UserSendInput(1, inp, sizeof(INPUT));
667 if (result != 1)
668 {
669 return GATE_RESULT_FAILED;
670 }
671 return GATE_RESULT_OK;
672 }
673
674 /* win95 NT 3.1 do not support SendInput: */
675 if ((inp->type == INPUT_MOUSE) && (user32->UserMouse_event))
676 {
677 user32->UserMouse_event(inp->mi.dwFlags, inp->mi.dx, inp->mi.dy, inp->mi.mouseData, inp->mi.dwExtraInfo);
678 return GATE_RESULT_OK;
679 }
680
681 if ((inp->type == INPUT_KEYBOARD) && (user32->UserKeybd_event))
682 {
683 user32->UserKeybd_event((BYTE)inp->ki.wVk, (BYTE)inp->ki.wScan, inp->ki.dwFlags, inp->ki.dwExtraInfo);
684 return GATE_RESULT_OK;
685 }
686
687 return GATE_RESULT_NOTSUPPORTED;
688 }
689
690 #ifndef MOUSEEVENTF_VIRTUALDESK
691 #define MOUSEEVENTF_VIRTUALDESK 0x4000
692 #endif
693
694 static void win32_prepare_mouse_input(INPUT* inp, gate_int32_t x, gate_int32_t y)
695 {
696 gate_win32_userapi_t* const user32 = gate_win32_userapi();
697
698 int screen_width;
699 int screen_height;
700
701 if (user32)
702 {
703 screen_width = user32->UserGetSystemMetrics(SM_CXVIRTUALSCREEN);
704 screen_height = user32->UserGetSystemMetrics(SM_CYVIRTUALSCREEN);
705 if (screen_width == 0) screen_width = user32->UserGetSystemMetrics(SM_CXSCREEN);
706 if (screen_height == 0) screen_height = user32->UserGetSystemMetrics(SM_CYSCREEN);
707 inp->mi.dwExtraInfo = user32->UserGetMessageExtraInfo();
708 }
709 else
710 {
711 screen_width = 640;
712 screen_height = 480;
713 inp->mi.dwExtraInfo = 0;
714 }
715
716 inp->type = INPUT_MOUSE;
717 inp->mi.dx = (screen_width > 0) ? (x * 65536 / screen_width) : 0;
718 inp->mi.dy = (screen_height > 0) ? (y * 65536 / screen_height) : 0;
719 inp->mi.mouseData = 0;
720 inp->mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK;
721 inp->mi.time = 0;
722 }
723
724 static gate_result_t screenctrl_get_cursor_pos(void* thisptr, gate_int32_t* ptr_x, gate_int32_t* ptr_y)
725 {
726 gate_win32_userapi_t* const user32 = gate_win32_userapi();
727 POINT pnt;
728 if (!user32)
729 {
730 return GATE_RESULT_FAILED;
731 }
732 if (!user32->UserGetCursorPos(&pnt))
733 {
734 return GATE_RESULT_FAILED;
735 }
736 if (ptr_x) *ptr_x = pnt.x;
737 if (ptr_y) *ptr_y = pnt.y;
738 return GATE_RESULT_OK;
739 }
740 static gate_result_t screenctrl_move_cursor(void* thisptr, gate_int32_t x, gate_int32_t y)
741 {
742 INPUT inp;
743 win32_prepare_mouse_input(&inp, x, y);
744 return win32_send_input(&inp);
745 }
746 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)
747 {
748 INPUT inp;
749 win32_prepare_mouse_input(&inp, x, y);
750 if (GATE_FLAG_ENABLED(button_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN))
751 {
752 /* mouse down */
753 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT) inp.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
754 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE) inp.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
755 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT) inp.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
756 }
757 else if (GATE_FLAG_ENABLED(button_state, GATE_VIDEO_SCREENCONTROL_STATE_UP))
758 {
759 /* mouse up */
760 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT) inp.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
761 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE) inp.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
762 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT) inp.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
763 }
764 return win32_send_input(&inp);
765 }
766
767 static gate_input_keystates_t extract_state_keys_from_key_state_flags(gate_enumint_t key_state)
768 {
769 gate_input_keystates_t value = 0;
770 if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_CTRL)) value |= GATE_KBD_KEYSTATE_CTRL;
771 if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_MENU)) value |= GATE_KBD_KEYSTATE_MENU;
772 if (GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_SHIFT)) value |= GATE_KBD_KEYSTATE_SHIFT;
773 return value;
774 }
775
776 static void win32_prepare_key_input(INPUT* inp, gate_input_keycode_t keycode, gate_input_keystates_t keystates, gate_bool_t down)
777 {
778 gate_win32_userapi_t* const user32 = gate_win32_userapi();
779 gate_input_nativekeycode_t vk = 0;
780
781 if (user32 && user32->UserGetMessageExtraInfo)
782 {
783 inp->ki.dwExtraInfo = user32->UserGetMessageExtraInfo();
784 }
785 else
786 {
787 inp->ki.dwExtraInfo = 0;
788 }
789
790 inp->type = INPUT_KEYBOARD;
791 gate_keyboard_build_native_key(keycode, keystates, &vk);
792 inp->ki.wVk = (WORD)vk;
793 inp->ki.wScan = 0;
794 inp->ki.dwFlags = down ? 0 : KEYEVENTF_KEYUP;
795 inp->ki.time = 0;
796 }
797
798 static gate_result_t screenctrl_change_key_state(void* thisptr, gate_input_keycode_t key_code, gate_enumint_t key_state)
799 {
800 INPUT inp;
801 gate_input_keystates_t state_keys = extract_state_keys_from_key_state_flags(key_state);
802 win32_prepare_key_input(&inp, key_code, state_keys, GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN));
803 return win32_send_input(&inp);
804 }
805
806
807 gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source)
808 {
809 gate_result_t ret = GATE_RESULT_FAILED;
810 win32screen_t* impl = NULL;
811
812 do
813 {
814 ret = gate_win32_gdi_init();
815 GATE_BREAK_IF_FAILED(ret);
816
817 impl = (win32screen_t*)gate_mem_alloc(sizeof(win32screen_t));
818 if (impl == NULL)
819 {
820 ret = GATE_RESULT_OUTOFMEMORY;
821 break;
822 }
823 gate_mem_clear(impl, sizeof(win32screen_t));
824 impl->vtbl = init_video_screencontrol_vtbl();
825 gate_atomic_int_init(&impl->ref_counter, 1);
826
827 if (ptr_source)
828 {
829 *ptr_source = (gate_video_screencontrol_t*)impl;
830 impl = NULL;
831 }
832 ret = GATE_RESULT_OK;
833 } while (0);
834
835 if (impl != NULL)
836 {
837 screenctrl_release(impl);
838 }
839
840 return ret;
841 }
842
843
844 #endif
845
846
847 #if defined(GATE_IO_VIDEO_X11)
848
849 #include "gate/platform/posix/xlib.h"
850 #include "gate/debugging.h"
851
852 typedef struct x11screen_class
853 {
854 GATE_INTERFACE_VTBL(gate_video_screencontrol) const* vtbl;
855
856 gate_atomic_int_t ref_counter;
857 Display* x11_display;
858 Window x11_root;
859 gate_video_format_t format;
860 GC x11_gc;
861 int x11_screen;
862 Colormap x11_colmap;
863 } x11screen_t;
864
865
866 static gate_result_t x11screen_init(x11screen_t* self)
867 {
868 gate_result_t result;
869
870 do
871 {
872 result = gate_xlib_load_functions();
873 GATE_BREAK_IF_FAILED(result);
874
875 self->x11_display = xlib.XOpenDisplay(NULL);
876 if (self->x11_display == NULL)
877 {
878 self->x11_display = xlib.XOpenDisplay(":0");
879 }
880 if (self->x11_display == NULL)
881 {
882 GATE_DEBUG_TRACE("Failed to open X11 display");
883 result = GATE_RESULT_FAILED;
884 break;
885 }
886 self->x11_root = xlib.XDefaultRootWindow(self->x11_display);
887
888 } while (0);
889
890 return result;
891 }
892
893 static void x11screen_destroy(x11screen_t* self)
894 {
895
896 if (self->x11_display)
897 {
898 xlib.XCloseDisplay(self->x11_display);
899 self->x11_display = NULL;
900 }
901 }
902
903
904 static char const* screenctrl_get_interface_name(void* thisptr)
905 {
906 return GATE_INTERFACE_NAME_VIDEO_SOURCE_SCREENCONTROL;
907 }
908
909
910 static void screenctrl_release(void* thisptr)
911 {
912 x11screen_t* const self = (x11screen_t*)thisptr;
913 if (gate_atomic_int_dec(&self->ref_counter) == 0)
914 {
915 x11screen_destroy(self);
916 gate_mem_dealloc(self);
917 }
918 }
919 static int screenctrl_retain(void* thisptr)
920 {
921 x11screen_t* const self = (x11screen_t*)thisptr;
922 return gate_atomic_int_inc(&self->ref_counter);
923 }
924 static char const* screenctrl_get_id(void* thisptr)
925 {
926 return "screen";
927 }
928 static char const* screenctrl_get_name(void* thisptr)
929 {
930 return "screen";
931 }
932 static gate_intptr_t screenctrl_get_handle(void* thisptr)
933 {
934 x11screen_t* const self = (x11screen_t*)thisptr;
935 return (gate_intptr_t)self->x11_display;
936 }
937 static gate_size_t screenctrl_get_supported_formats(void* thisptr, gate_video_format_t* format_buffer, gate_size_t format_buffer_count)
938 {
939 x11screen_t* const self = (x11screen_t*)thisptr;
940 XWindowAttributes attrs = GATE_INIT_EMPTY;
941
942 if ((format_buffer == NULL) || (format_buffer_count < 1))
943 {
944 GATE_DEBUG_TRACE("Not enough space in output buffer");
945 return 0;
946 }
947
948 /* get screen dimensions */
949 xlib.XGetWindowAttributes(self->x11_display, self->x11_root, &attrs);
950
951 format_buffer->encoding_id = 0;
952 format_buffer->compression = 0;
953 format_buffer->frames_per_second = 5;
954 format_buffer->width = (gate_uint32_t)attrs.width;
955 format_buffer->height = (gate_uint32_t)attrs.height;
956 format_buffer->bits_per_pixel = 32;
957
958 return 1; /* one entry was used */
959 }
960
961 static gate_result_t screenctrl_open(void* thisptr, gate_video_format_t const* format)
962 {
963 x11screen_t* const self = (x11screen_t*)thisptr;
964
965 if (self->x11_gc != NULL)
966 {
967 GATE_DEBUG_TRACE("Error: X11 GC is already initialized");
968 return GATE_RESULT_INVALIDSTATE;
969 }
970
971 gate_mem_copy(&self->format, format, sizeof(gate_video_format_t));
972
973 self->x11_gc = xlib.XCreateGC(self->x11_display, self->x11_root, 0, NULL);
974 if (!self->x11_gc)
975 {
976 GATE_DEBUG_TRACE("Error: Failed to create GC on current display");
977 return GATE_RESULT_FAILED;
978 }
979 self->x11_screen = xlib.XDefaultScreen(self->x11_display);
980 self->x11_colmap = xlib.XDefaultColormap(self->x11_display, self->x11_screen);
981 return GATE_RESULT_OK;
982 }
983 static gate_result_t screenctrl_close(void* thisptr)
984 {
985 x11screen_t* const self = (x11screen_t*)thisptr;
986
987 if (!self->x11_gc)
988 {
989 xlib.XFreeGC(self->x11_display, self->x11_gc);
990 self->x11_gc = NULL;
991 self->x11_screen = 0;
992 self->x11_colmap = 0;
993 }
994 return GATE_RESULT_OK;
995 }
996
997 static gate_result_t ximage32_to_raster(XImage* ptr_ximage, gate_rasterimage_t* ptr_raster)
998 {
999 unsigned char const* ptr_src_pixel = (unsigned char const*)ptr_ximage->data;
1000 gate_color_rgb_t* ptr_dst_pixel;
1001 unsigned int y, x;
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 for (y = 0; y != ptr_raster->height; ++y)
1010 {
1011 ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y);
1012 for (x = 0; x != ptr_raster->width; ++x)
1013 {
1014 ptr_dst_pixel->b = *(ptr_src_pixel++);
1015 ptr_dst_pixel->g = *(ptr_src_pixel++);
1016 ptr_dst_pixel->r = *(ptr_src_pixel++);
1017 ++ptr_src_pixel; /* skip A value */
1018 ++ptr_dst_pixel;
1019 }
1020 }
1021 return GATE_RESULT_OK;
1022 }
1023
1024 static gate_result_t ximage16_to_raster(XImage* ptr_ximage, gate_rasterimage_t* ptr_raster)
1025 {
1026 unsigned char const* ptr_src_pixel = (unsigned char const*)ptr_ximage->data;
1027 gate_color_rgb_t* ptr_dst_pixel;
1028 unsigned int y, x;
1029
1030 if (NULL == gate_rasterimage_create(ptr_raster, GATE_IMAGE_PIXELFORMAT_RGB24,
1031 (unsigned)ptr_ximage->width, (unsigned)ptr_ximage->height, NULL))
1032 {
1033 return GATE_RESULT_OUTOFMEMORY;
1034 }
1035
1036 for (y = 0; y != ptr_raster->height; ++y)
1037 {
1038 ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y);
1039 for (x = 0; x != ptr_raster->width; ++x)
1040 {
1041 const gate_uint16_t col = (gate_uint16_t)(ptr_src_pixel[0]) | (((gate_uint16_t)ptr_src_pixel[1]) << 8);
1042 ptr_dst_pixel->b = (gate_uint8_t)((col & 0x001F) << 3);
1043 ptr_dst_pixel->g = (gate_uint8_t)((col & 0x07e0) >> 3);
1044 ptr_dst_pixel->r = (gate_uint8_t)((col & 0xF800) >> 8);
1045 ptr_src_pixel += 2;
1046 ++ptr_dst_pixel;
1047 }
1048 }
1049 return GATE_RESULT_OK;
1050 }
1051
1052 static gate_result_t ximage_to_raster(Display* display, Colormap colmap, XImage* ptr_ximage, gate_rasterimage_t* ptr_raster)
1053 {
1054 gate_color_rgb_t* ptr_dst_pixel;
1055 unsigned int y, x;
1056 XColor xcol;
1057
1058 if (NULL == gate_rasterimage_create(ptr_raster, GATE_IMAGE_PIXELFORMAT_RGB24,
1059 (unsigned)ptr_ximage->width, (unsigned)ptr_ximage->height, NULL))
1060 {
1061 return GATE_RESULT_OUTOFMEMORY;
1062 }
1063
1064 for (y = 0; y != ptr_raster->height; ++y)
1065 {
1066 ptr_dst_pixel = (gate_color_rgb_t*)gate_rasterimage_get_line_ptr(ptr_raster, y);
1067 for (x = 0; x != ptr_raster->width; ++x)
1068 {
1069 xcol.pixel = xlib.XGetPixel(ptr_ximage, (int)x, (int)y);
1070 xlib.XQueryColor(display, colmap, &xcol);
1071
1072 ptr_dst_pixel->r = (gate_uint8_t)(xcol.red >> 8);
1073 ptr_dst_pixel->g = (gate_uint8_t)(xcol.green >> 8);
1074 ptr_dst_pixel->b = (gate_uint8_t)(xcol.blue >> 8);
1075 ++ptr_dst_pixel;
1076 }
1077 }
1078 return GATE_RESULT_OK;
1079 }
1080
1081 static gate_result_t screenctrl_read(void* thisptr, gate_video_frame_t* frame)
1082 {
1083 gate_result_t ret = GATE_RESULT_FAILED;
1084 x11screen_t* const self = (x11screen_t*)thisptr;
1085 XImage* ptr_ximage = NULL;
1086 gate_rasterimage_t raster = GATE_INIT_EMPTY;
1087
1088 do
1089 {
1090 ptr_ximage = xlib.XGetImage(self->x11_display, self->x11_root,
1091 0, 0, self->format.width, self->format.height, AllPlanes, ZPixmap);
1092 if (ptr_ximage == NULL)
1093 {
1094 ret = GATE_RESULT_FAILED;
1095 break;
1096 }
1097
1098 if ((ptr_ximage->bits_per_pixel == 32) && (ptr_ximage->depth == 24))
1099 {
1100 ret = ximage32_to_raster(ptr_ximage, &raster);
1101 }
1102 else if ((ptr_ximage->bits_per_pixel == 16) && (ptr_ximage->depth == 16))
1103 {
1104 ret = ximage16_to_raster(ptr_ximage, &raster);
1105 }
1106 else
1107 {
1108 ret = ximage_to_raster(self->x11_display, self->x11_colmap, ptr_ximage, &raster);
1109 }
1110
1111 GATE_BREAK_IF_FAILED(ret);
1112
1113 frame->format.bits_per_pixel = raster.bits_per_pixel;
1114 frame->format.compression = 0;
1115 frame->format.encoding_id = 0;
1116 frame->format.frames_per_second = self->format.frames_per_second;
1117 frame->format.width = raster.width;
1118 frame->format.height = raster.height;
1119 gate_rasterimage_duplicate(&frame->image, &raster);
1120 frame->record_time = 0;
1121
1122 ret = GATE_RESULT_OK;
1123 } while (0);
1124
1125 gate_rasterimage_release(&raster);
1126
1127 if (ptr_ximage != NULL)
1128 {
1129 xlib.XDestroyImage(ptr_ximage);
1130 }
1131
1132 return ret;
1133 }
1134
1135 static gate_result_t screenctrl_get_cursor_pos(void* thisptr, gate_int32_t* ptr_x, gate_int32_t* ptr_y)
1136 {
1137 gate_result_t ret = GATE_RESULT_FAILED;
1138 x11screen_t* const self = (x11screen_t*)thisptr;
1139 Window win, subwin;
1140 int gx, gy, wx, wy;
1141 unsigned int state;
1142
1143 if (xlib.XQueryPointer(self->x11_display, self->x11_root, &win, &subwin, &gx, &gy, &wx, &wy, &state))
1144 {
1145 if (ptr_x) *ptr_x = gx;
1146 if (ptr_y) *ptr_y = gy;
1147 return GATE_RESULT_OK;
1148 }
1149 return GATE_RESULT_FAILED;
1150 }
1151
1152 static gate_result_t screenctrl_move_cursor(void* thisptr, gate_int32_t x, gate_int32_t y)
1153 {
1154 gate_result_t ret = GATE_RESULT_FAILED;
1155 x11screen_t* const self = (x11screen_t*)thisptr;
1156 xlib.XWarpPointer(self->x11_display, None, self->x11_root, 0, 0, 0, 0, (int)x, (int)y);
1157 return GATE_RESULT_OK;
1158 }
1159
1160 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)
1161 {
1162 /* http://www.linuxquestions.org/questions/programming-9/simulating-a-mouse-click-594576/ */
1163
1164 gate_result_t ret = GATE_RESULT_FAILED;
1165 x11screen_t* const self = (x11screen_t*)thisptr;
1166 XEvent xevt = GATE_INIT_EMPTY;
1167 XButtonEvent* evt = &xevt.xbutton;
1168
1169 xlib.XWarpPointer(self->x11_display, None, self->x11_root, 0, 0, 0, 0, (int)x, (int)y);
1170
1171 /* find inner sub-window */
1172 evt->type = (button_state == GATE_VIDEO_SCREENCONTROL_STATE_DOWN) ? ButtonPress : ButtonRelease;
1173 evt->display = self->x11_display;
1174 evt->same_screen = True;
1175 evt->time = CurrentTime;
1176
1177 evt->subwindow = self->x11_root;
1178 do
1179 {
1180 evt->window = evt->subwindow;
1181 xlib.XQueryPointer(self->x11_display, evt->window, &evt->root, &evt->subwindow, &evt->x_root, &evt->y_root, &evt->x, &evt->y, &evt->state);
1182 } while (evt->subwindow != 0);
1183
1184
1185
1186 evt->state = 0;
1187 if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_LEFT)
1188 {
1189 evt->button = Button1;
1190 evt->state |= Button1Mask;
1191 }
1192 else if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_MIDDLE)
1193 {
1194 evt->button = Button2;
1195 evt->state |= Button2Mask;
1196 }
1197 else if (button_id == GATE_VIDEO_SCREENCONTROL_BUTTON_RIGHT)
1198 {
1199 evt->button = Button3;
1200 evt->state |= Button3Mask;
1201 }
1202
1203 xlib.XSendEvent(self->x11_display, PointerWindow, True, 0xfff, &xevt);
1204 xlib.XFlush(self->x11_display);
1205
1206 return GATE_RESULT_OK;
1207 }
1208
1209 static gate_result_t screenctrl_change_key_state(void* thisptr, gate_input_keycode_t key_code, gate_enumint_t key_state)
1210 {
1211 gate_result_t ret = GATE_RESULT_FAILED;
1212 x11screen_t* const self = (x11screen_t*)thisptr;
1213 XKeyEvent evt;
1214 int focus_state;
1215 Window focus_win = self->x11_root;
1216 KeySym x11_key_sym = key_code;
1217 gate_bool_t key_down = GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_DOWN);
1218 unsigned int x11_state = 0;
1219
1220 if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_CTRL))
1221 {
1222 x11_state |= ControlMask;
1223 }
1224 if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_MENU))
1225 {
1226 x11_state |= Mod1Mask;
1227 }
1228 if (key_down && GATE_FLAG_ENABLED(key_state, GATE_VIDEO_SCREENCONTROL_STATE_SHIFT))
1229 {
1230 x11_state |= ShiftMask;
1231 }
1232
1233 xlib.XGetInputFocus(self->x11_display, &focus_win, &focus_state);
1234
1235 evt.display = self->x11_display;
1236 evt.window = focus_win;
1237 evt.root = self->x11_root;
1238 evt.subwindow = None;
1239 evt.time = CurrentTime;
1240 evt.x = 1;
1241 evt.y = 1;
1242 evt.x_root = 1;
1243 evt.y_root = 1;
1244 evt.same_screen = True;
1245 evt.send_event = True;
1246 evt.keycode = xlib.XKeysymToKeycode(self->x11_display, x11_key_sym);
1247 evt.state = x11_state;
1248 evt.type = key_down ? KeyPress : KeyRelease;
1249 xlib.XSendEvent(evt.display, evt.window, True, KeyPressMask, (XEvent*)&evt);
1250
1251 return GATE_RESULT_OK;
1252 }
1253
1254
1255
1256 gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source)
1257 {
1258 gate_result_t ret = GATE_RESULT_FAILED;
1259 x11screen_t* impl = NULL;
1260
1261 do
1262 {
1263 impl = (x11screen_t*)gate_mem_alloc(sizeof(x11screen_t));
1264 if (impl == NULL)
1265 {
1266 ret = GATE_RESULT_OUTOFMEMORY;
1267 break;
1268 }
1269 gate_mem_clear(impl, sizeof(x11screen_t));
1270 impl->vtbl = init_video_screencontrol_vtbl();
1271 gate_atomic_int_init(&impl->ref_counter, 1);
1272
1273 ret = x11screen_init(impl);
1274 GATE_BREAK_IF_FAILED(ret);
1275
1276 if (ptr_source)
1277 {
1278 *ptr_source = (gate_video_screencontrol_t*)impl;
1279 impl = NULL;
1280 }
1281 ret = GATE_RESULT_OK;
1282 } while (0);
1283
1284 if (impl != NULL)
1285 {
1286 screenctrl_release(impl);
1287 }
1288
1289 return ret;
1290 }
1291
1292 #endif
1293
1294 #if defined(GATE_IO_VIDEO_ANDROID)
1295
1296 gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source)
1297 {
1298 GATE_UNUSED_ARG(ptr_source);
1299 /* TODO */
1300 return GATE_RESULT_NOTSUPPORTED;
1301 }
1302
1303 #endif
1304
1305
1306 #if defined(GATE_IO_VIDEO_NO_IMPL)
1307
1308 gate_result_t gate_video_screencontrol_create(gate_video_screencontrol_t** ptr_source)
1309 {
1310 GATE_UNUSED_ARG(ptr_source);
1311 return GATE_RESULT_NOTSUPPORTED;
1312 }
1313
1314 #endif
1315