24 |
|
* Ctrl-Tab = suspend DGA mode |
25 |
|
* Ctrl-Esc = emergency quit |
26 |
|
* Ctrl-F1 = mount floppy |
27 |
+ |
* Ctrl-F5 = grab mouse (in windowed mode) |
28 |
|
*/ |
29 |
|
|
30 |
|
#include "sysdeps.h" |
74 |
|
// Constants |
75 |
|
const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes"; |
76 |
|
|
77 |
< |
static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask | StructureNotifyMask; |
77 |
> |
static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask; |
78 |
|
static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask; |
79 |
|
|
80 |
|
|
323 |
|
virtual void update_palette(void); |
324 |
|
virtual void suspend(void) {} |
325 |
|
virtual void resume(void) {} |
326 |
+ |
virtual void toggle_mouse_grab(void) {} |
327 |
+ |
virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); } |
328 |
+ |
|
329 |
+ |
virtual void grab_mouse(void) {} |
330 |
+ |
virtual void ungrab_mouse(void) {} |
331 |
|
|
332 |
|
public: |
333 |
|
bool init_ok; // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer) |
348 |
|
driver_window(const video_mode &mode); |
349 |
|
~driver_window(); |
350 |
|
|
351 |
+ |
void toggle_mouse_grab(void); |
352 |
+ |
void mouse_moved(int x, int y); |
353 |
+ |
|
354 |
+ |
void grab_mouse(void); |
355 |
+ |
void ungrab_mouse(void); |
356 |
+ |
|
357 |
|
private: |
358 |
|
GC gc; |
359 |
|
XImage *img; |
360 |
< |
bool have_shm; // Flag: SHM extensions available |
360 |
> |
bool have_shm; // Flag: SHM extensions available |
361 |
|
XShmSegmentInfo shminfo; |
362 |
|
Cursor mac_cursor; |
363 |
+ |
bool mouse_grabbed; // Flag: mouse pointer grabbed, using relative mouse mode |
364 |
+ |
int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode) |
365 |
|
}; |
366 |
|
|
367 |
|
static driver_base *drv = NULL; // Pointer to currently used driver object |
379 |
|
|
380 |
|
driver_base::~driver_base() |
381 |
|
{ |
382 |
+ |
ungrab_mouse(); |
383 |
+ |
|
384 |
|
if (w) { |
385 |
|
XUnmapWindow(x_display, w); |
386 |
|
wait_unmapped(w); |
437 |
|
|
438 |
|
// Open display |
439 |
|
driver_window::driver_window(const video_mode &mode) |
440 |
< |
: gc(0), img(NULL), have_shm(false), mac_cursor(0) |
440 |
> |
: gc(0), img(NULL), have_shm(false), mouse_grabbed(false), mac_cursor(0) |
441 |
|
{ |
442 |
|
int width = mode.x, height = mode.y; |
443 |
|
int aligned_width = (width + 15) & ~15; |
444 |
|
int aligned_height = (height + 15) & ~15; |
445 |
|
|
446 |
|
// Set absolute mouse mode |
447 |
< |
ADBSetRelMouseMode(false); |
447 |
> |
ADBSetRelMouseMode(mouse_grabbed); |
448 |
|
|
449 |
|
// Create window |
450 |
|
XSetWindowAttributes wattr; |
577 |
|
XFreeGC(x_display, gc); |
578 |
|
} |
579 |
|
|
580 |
+ |
// Toggle mouse grab |
581 |
+ |
void driver_window::toggle_mouse_grab(void) |
582 |
+ |
{ |
583 |
+ |
if (mouse_grabbed) |
584 |
+ |
ungrab_mouse(); |
585 |
+ |
else |
586 |
+ |
grab_mouse(); |
587 |
+ |
} |
588 |
+ |
|
589 |
+ |
// Grab mouse, switch to relative mouse mode |
590 |
+ |
void driver_window::grab_mouse(void) |
591 |
+ |
{ |
592 |
+ |
int result; |
593 |
+ |
for (int i=0; i<10; i++) { |
594 |
+ |
result = XGrabPointer(x_display, w, True, 0, |
595 |
+ |
GrabModeAsync, GrabModeAsync, w, None, CurrentTime); |
596 |
+ |
if (result != AlreadyGrabbed) |
597 |
+ |
break; |
598 |
+ |
Delay_usec(100000); |
599 |
+ |
} |
600 |
+ |
if (result == GrabSuccess) { |
601 |
+ |
ADBSetRelMouseMode(mouse_grabbed = true); |
602 |
+ |
XStoreName(x_display, w, GetString(STR_WINDOW_TITLE_GRABBED)); |
603 |
+ |
XSync(x_display, false); |
604 |
+ |
} |
605 |
+ |
} |
606 |
+ |
|
607 |
+ |
// Ungrab mouse, switch to absolute mouse mode |
608 |
+ |
void driver_window::ungrab_mouse(void) |
609 |
+ |
{ |
610 |
+ |
if (mouse_grabbed) { |
611 |
+ |
XUngrabPointer(x_display, CurrentTime); |
612 |
+ |
XStoreName(x_display, w, GetString(STR_WINDOW_TITLE)); |
613 |
+ |
ADBSetRelMouseMode(mouse_grabbed = false); |
614 |
+ |
} |
615 |
+ |
} |
616 |
+ |
|
617 |
+ |
// Mouse moved |
618 |
+ |
void driver_window::mouse_moved(int x, int y) |
619 |
+ |
{ |
620 |
+ |
if (!mouse_grabbed) { |
621 |
+ |
mouse_last_x = x; mouse_last_y = y; |
622 |
+ |
ADBMouseMoved(x, y); |
623 |
+ |
return; |
624 |
+ |
} |
625 |
+ |
|
626 |
+ |
// Warped mouse motion (this code is taken from SDL) |
627 |
+ |
|
628 |
+ |
// Post first mouse event |
629 |
+ |
int width = VideoMonitor.mode.x, height = VideoMonitor.mode.y; |
630 |
+ |
int delta_x = x - mouse_last_x, delta_y = y - mouse_last_y; |
631 |
+ |
mouse_last_x = x; mouse_last_y = y; |
632 |
+ |
ADBMouseMoved(delta_x, delta_y); |
633 |
+ |
|
634 |
+ |
// Only warp the pointer when it has reached the edge |
635 |
+ |
const int MOUSE_FUDGE_FACTOR = 8; |
636 |
+ |
if (x < MOUSE_FUDGE_FACTOR || x > (width - MOUSE_FUDGE_FACTOR) |
637 |
+ |
|| y < MOUSE_FUDGE_FACTOR || y > (height - MOUSE_FUDGE_FACTOR)) { |
638 |
+ |
XEvent event; |
639 |
+ |
while (XCheckTypedEvent(x_display, MotionNotify, &event)) { |
640 |
+ |
delta_x = x - mouse_last_x; delta_y = y - mouse_last_y; |
641 |
+ |
mouse_last_x = x; mouse_last_y = y; |
642 |
+ |
ADBMouseMoved(delta_x, delta_y); |
643 |
+ |
} |
644 |
+ |
mouse_last_x = width/2; |
645 |
+ |
mouse_last_y = height/2; |
646 |
+ |
XWarpPointer(x_display, None, w, 0, 0, 0, 0, mouse_last_x, mouse_last_y); |
647 |
+ |
for (int i=0; i<10; i++) { |
648 |
+ |
XMaskEvent(x_display, PointerMotionMask, &event); |
649 |
+ |
if (event.xmotion.x > (mouse_last_x - MOUSE_FUDGE_FACTOR) |
650 |
+ |
&& event.xmotion.x < (mouse_last_x + MOUSE_FUDGE_FACTOR) |
651 |
+ |
&& event.xmotion.y > (mouse_last_y - MOUSE_FUDGE_FACTOR) |
652 |
+ |
&& event.xmotion.y < (mouse_last_y + MOUSE_FUDGE_FACTOR)) |
653 |
+ |
break; |
654 |
+ |
} |
655 |
+ |
} |
656 |
+ |
} |
657 |
+ |
|
658 |
|
|
659 |
|
#if defined(ENABLE_XF86_DGA) || defined(ENABLE_FBDEV_DGA) |
660 |
|
/* |
733 |
|
XMapRaised(x_display, w); |
734 |
|
wait_mapped(w); |
735 |
|
XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0); |
736 |
< |
XGrabKeyboard(x_display, rootwin, 1, GrabModeAsync, GrabModeAsync, CurrentTime); |
737 |
< |
XGrabPointer(x_display, rootwin, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); |
736 |
> |
XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime); |
737 |
> |
XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); |
738 |
|
#ifdef ENABLE_XF86_DGA |
739 |
|
XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse); |
740 |
|
XF86DGASetViewPort(x_display, screen, 0, 0); |
1559 |
|
// Recalculate pixel color expansion map |
1560 |
|
if (!IsDirectMode(VideoMonitor.mode) && (vis->c_class == TrueColor || vis->c_class == DirectColor)) { |
1561 |
|
for (int i=0; i<256; i++) { |
1562 |
< |
int c = i % num_in; // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier) |
1562 |
> |
int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier) |
1563 |
|
ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]); |
1564 |
|
} |
1565 |
|
|
1596 |
|
|
1597 |
|
|
1598 |
|
/* |
1599 |
< |
* Translate key event to Mac keycode |
1599 |
> |
* Translate key event to Mac keycode, returns -1 if no keycode was found |
1600 |
> |
* and -2 if the key was recognized as a hotkey |
1601 |
|
*/ |
1602 |
|
|
1603 |
< |
static int kc_decode(KeySym ks) |
1603 |
> |
static int kc_decode(KeySym ks, bool key_down) |
1604 |
|
{ |
1605 |
|
switch (ks) { |
1606 |
|
case XK_A: case XK_a: return 0x00; |
1653 |
|
case XK_period: case XK_greater: return 0x2f; |
1654 |
|
case XK_slash: case XK_question: return 0x2c; |
1655 |
|
|
1656 |
< |
#if defined(ENABLE_XF86_DGA) || defined(ENABLE_FBDEV_DGA) |
1562 |
< |
case XK_Tab: if (ctrl_down) {drv->suspend(); return -1;} else return 0x30; |
1563 |
< |
#else |
1564 |
< |
case XK_Tab: return 0x30; |
1565 |
< |
#endif |
1656 |
> |
case XK_Tab: if (ctrl_down) {if (key_down) drv->suspend(); return -2;} else return 0x30; |
1657 |
|
case XK_Return: return 0x24; |
1658 |
|
case XK_space: return 0x31; |
1659 |
|
case XK_BackSpace: return 0x33; |
1687 |
|
case XK_Left: return 0x3b; |
1688 |
|
case XK_Right: return 0x3c; |
1689 |
|
|
1690 |
< |
case XK_Escape: if (ctrl_down) {quit_full_screen = true; emerg_quit = true; return -1;} else return 0x35; |
1690 |
> |
case XK_Escape: if (ctrl_down) {if (key_down) { quit_full_screen = true; emerg_quit = true; } return -2;} else return 0x35; |
1691 |
|
|
1692 |
< |
case XK_F1: if (ctrl_down) {SysMountFirstFloppy(); return -1;} else return 0x7a; |
1692 |
> |
case XK_F1: if (ctrl_down) {if (key_down) SysMountFirstFloppy(); return -2;} else return 0x7a; |
1693 |
|
case XK_F2: return 0x78; |
1694 |
|
case XK_F3: return 0x63; |
1695 |
|
case XK_F4: return 0x76; |
1696 |
< |
case XK_F5: return 0x60; |
1696 |
> |
case XK_F5: if (ctrl_down) {if (key_down) drv->toggle_mouse_grab(); return -2;} else return 0x60; |
1697 |
|
case XK_F6: return 0x61; |
1698 |
|
case XK_F7: return 0x62; |
1699 |
|
case XK_F8: return 0x64; |
1741 |
|
return -1; |
1742 |
|
} |
1743 |
|
|
1744 |
< |
static int event2keycode(XKeyEvent &ev) |
1744 |
> |
static int event2keycode(XKeyEvent &ev, bool key_down) |
1745 |
|
{ |
1746 |
|
KeySym ks; |
1656 |
– |
int as; |
1747 |
|
int i = 0; |
1748 |
|
|
1749 |
|
do { |
1750 |
|
ks = XLookupKeysym(&ev, i++); |
1751 |
< |
as = kc_decode(ks); |
1752 |
< |
if (as != -1) |
1751 |
> |
int as = kc_decode(ks, key_down); |
1752 |
> |
if (as >= 0) |
1753 |
> |
return as; |
1754 |
> |
if (as == -2) |
1755 |
|
return as; |
1756 |
|
} while (ks != NoSymbol); |
1757 |
|
|
1798 |
|
} |
1799 |
|
|
1800 |
|
// Mouse moved |
1709 |
– |
case EnterNotify: |
1801 |
|
case MotionNotify: |
1802 |
< |
ADBMouseMoved(event.xmotion.x, event.xmotion.y); |
1802 |
> |
drv->mouse_moved(event.xmotion.x, event.xmotion.y); |
1803 |
|
break; |
1804 |
|
|
1805 |
|
// Keyboard |
1806 |
|
case KeyPress: { |
1807 |
< |
int code; |
1807 |
> |
int code = -1; |
1808 |
|
if (use_keycodes) { |
1809 |
< |
event2keycode(event.xkey); // This is called to process the hotkeys |
1810 |
< |
code = keycode_table[event.xkey.keycode & 0xff]; |
1809 |
> |
if (event2keycode(event.xkey, true) != -2) // This is called to process the hotkeys |
1810 |
> |
code = keycode_table[event.xkey.keycode & 0xff]; |
1811 |
|
} else |
1812 |
< |
code = event2keycode(event.xkey); |
1813 |
< |
if (code != -1) { |
1812 |
> |
code = event2keycode(event.xkey, true); |
1813 |
> |
if (code >= 0) { |
1814 |
|
if (!emul_suspended) { |
1815 |
|
if (code == 0x39) { // Caps Lock pressed |
1816 |
|
if (caps_on) { |
1832 |
|
break; |
1833 |
|
} |
1834 |
|
case KeyRelease: { |
1835 |
< |
int code; |
1835 |
> |
int code = -1; |
1836 |
|
if (use_keycodes) { |
1837 |
< |
event2keycode(event.xkey); // This is called to process the hotkeys |
1838 |
< |
code = keycode_table[event.xkey.keycode & 0xff]; |
1837 |
> |
if (event2keycode(event.xkey, false) != -2) // This is called to process the hotkeys |
1838 |
> |
code = keycode_table[event.xkey.keycode & 0xff]; |
1839 |
|
} else |
1840 |
< |
code = event2keycode(event.xkey); |
1841 |
< |
if (code != -1 && code != 0x39) { // Don't propagate Caps Lock releases |
1840 |
> |
code = event2keycode(event.xkey, false); |
1841 |
> |
if (code >= 0 && code != 0x39) { // Don't propagate Caps Lock releases |
1842 |
|
ADBKeyUp(code); |
1843 |
|
if (code == 0x36) |
1844 |
|
ctrl_down = false; |
2102 |
|
|
2103 |
|
static inline void possibly_quit_dga_mode() |
2104 |
|
{ |
2105 |
< |
// Quit DGA mode if requested |
2105 |
> |
// Quit DGA mode if requested (something terrible has happened and we |
2106 |
> |
// want to give control back to the user) |
2107 |
|
if (quit_full_screen) { |
2108 |
|
quit_full_screen = false; |
2109 |
|
delete drv; |
2111 |
|
} |
2112 |
|
} |
2113 |
|
|
2114 |
+ |
static inline void possibly_ungrab_mouse() |
2115 |
+ |
{ |
2116 |
+ |
// Ungrab mouse if requested (something terrible has happened and we |
2117 |
+ |
// want to give control back to the user) |
2118 |
+ |
if (quit_full_screen) { |
2119 |
+ |
quit_full_screen = false; |
2120 |
+ |
if (drv) |
2121 |
+ |
drv->ungrab_mouse(); |
2122 |
+ |
} |
2123 |
+ |
} |
2124 |
+ |
|
2125 |
|
static inline void handle_palette_changes(void) |
2126 |
|
{ |
2127 |
|
LOCK_PALETTE; |
2174 |
|
|
2175 |
|
static void video_refresh_window_vosf(void) |
2176 |
|
{ |
2177 |
< |
// Quit DGA mode if requested |
2178 |
< |
possibly_quit_dga_mode(); |
2177 |
> |
// Ungrab mouse if requested |
2178 |
> |
possibly_ungrab_mouse(); |
2179 |
|
|
2180 |
|
// Handle X events |
2181 |
|
handle_events(); |
2199 |
|
|
2200 |
|
static void video_refresh_window_static(void) |
2201 |
|
{ |
2202 |
+ |
// Ungrab mouse if requested |
2203 |
+ |
possibly_ungrab_mouse(); |
2204 |
+ |
|
2205 |
|
// Handle X events |
2206 |
|
handle_events(); |
2207 |
|
|
2218 |
|
|
2219 |
|
static void video_refresh_window_dynamic(void) |
2220 |
|
{ |
2221 |
+ |
// Ungrab mouse if requested |
2222 |
+ |
possibly_ungrab_mouse(); |
2223 |
+ |
|
2224 |
|
// Handle X events |
2225 |
|
handle_events(); |
2226 |
|
|