21
21
#include < config.h>
22
22
#endif
23
23
24
+ #include < algorithm>
25
+
24
26
#include < assert.h>
25
27
#include < stdio.h>
26
28
#include < string.h>
@@ -113,7 +115,7 @@ static const WORD SCAN_FAKE = 0xaa;
113
115
114
116
Viewport::Viewport (int w, int h, const rfb::PixelFormat& serverPF, CConn* cc_)
115
117
: Fl_Widget(0 , 0 , w, h), cc(cc_), frameBuffer(NULL ),
116
- lastPointerPos(0 , 0 ), lastButtonMask(0 ),
118
+ lastPointerPos(0 , 0 ), lastButtonMask(0 ), hotKeyWedged( false ),
117
119
#ifdef WIN32
118
120
altGrArmed (false ),
119
121
#endif
@@ -823,59 +825,27 @@ void Viewport::handlePointerTimeout(void *data)
823
825
824
826
void Viewport::handleKeyPress (int keyCode, rdr::U32 keySym)
825
827
{
826
- std::set<HotKey> hotkeys;
827
-
828
- hotkeys = parseHotKeyCombo (hotKeyCombo);
829
-
830
- if ((hotkeys.count (hotkeyCtrl) > 0 ) &&
831
- ((keySym == XK_Control_L) || (keySym == XK_Control_R)))
832
- downHotkeys.insert (hotkeyCtrl);
833
- else if ((hotkeys.count (hotkeyShift) > 0 ) &&
834
- ((keySym == XK_Shift_L) || (keySym == XK_Shift_R)))
835
- downHotkeys.insert (hotkeyShift);
836
- else if ((hotkeys.count (hotkeyAlt) > 0 ) &&
837
- ((keySym == XK_Alt_L) || (keySym == XK_Alt_R)))
838
- downHotkeys.insert (hotkeyAlt);
839
- else if ((hotkeys.count (hotkeySuper) > 0 ) &&
840
- ((keySym == XK_Super_L) || (keySym == XK_Super_R)))
841
- downHotkeys.insert (hotkeySuper);
842
-
843
- if (viewOnly)
844
- return ;
845
-
846
828
if (keyCode == 0 ) {
847
829
vlog.error (_ (" No key code specified on key press" ));
848
830
return ;
849
831
}
850
832
851
- #ifdef __APPLE__
852
- // Alt on OS X behaves more like AltGr on other systems, and to get
853
- // sane behaviour we should translate things in that manner for the
854
- // remote VNC server. However that means we lose the ability to use
855
- // Alt as a shortcut modifier. Do what RealVNC does and hijack the
856
- // left command key as an Alt replacement.
857
- switch (keySym) {
858
- case XK_Super_L:
859
- keySym = XK_Alt_L;
860
- break ;
861
- case XK_Super_R:
862
- keySym = XK_Super_L;
863
- break ;
864
- case XK_Alt_L:
865
- keySym = XK_Mode_switch;
866
- break ;
867
- case XK_Alt_R:
868
- keySym = XK_ISO_Level3_Shift;
869
- break ;
870
- }
871
- #endif
833
+ // Possible hot key combo?
834
+ if (handleHotKeyPress (keyCode, keySym))
835
+ return ;
872
836
873
837
// Because of the way keyboards work, we cannot expect to have the same
874
838
// symbol on release as when pressed. This breaks the VNC protocol however,
875
839
// so we need to keep track of what keysym a key _code_ generated on press
876
840
// and send the same on release.
877
841
downKeySym[keyCode] = keySym;
878
842
843
+ if (viewOnly)
844
+ return ;
845
+
846
+ // Platform specific adjustments
847
+ keySym = adjustKeySym (keyCode, keySym);
848
+
879
849
#if defined(WIN32) || defined(__APPLE__)
880
850
vlog.debug (" Key pressed: 0x%04x => 0x%04x" , keyCode, keySym);
881
851
#else
@@ -900,9 +870,7 @@ void Viewport::handleKeyPress(int keyCode, rdr::U32 keySym)
900
870
void Viewport::handleKeyRelease (int keyCode)
901
871
{
902
872
DownMap::iterator iter;
903
-
904
- if (viewOnly)
905
- return ;
873
+ rdr::U32 keySym;
906
874
907
875
iter = downKeySym.find (keyCode);
908
876
if (iter == downKeySym.end ()) {
@@ -912,25 +880,178 @@ void Viewport::handleKeyRelease(int keyCode)
912
880
return ;
913
881
}
914
882
883
+ keySym = iter->second ;
884
+ downKeySym.erase (iter);
885
+
886
+ if (downKeySym.empty ())
887
+ hotKeyWedged = false ;
888
+
889
+ if (viewOnly)
890
+ return ;
891
+
892
+ // Platform specific adjustments
893
+ keySym = adjustKeySym (keyCode, keySym);
894
+
915
895
#if defined(WIN32) || defined(__APPLE__)
916
- vlog.debug (" Key released: 0x%04x => 0x%04x" , keyCode, iter-> second );
896
+ vlog.debug (" Key released: 0x%04x => 0x%04x" , keyCode, keySym );
917
897
#else
918
898
vlog.debug (" Key released: 0x%04x => XK_%s (0x%04x)" ,
919
- keyCode, XKeysymToString (iter-> second ), iter-> second );
899
+ keyCode, XKeysymToString (keySym ), keySym );
920
900
#endif
921
901
922
902
try {
923
903
if (keyCode > 0xff )
924
- cc->writer ()->writeKeyEvent (iter-> second , 0 , false );
904
+ cc->writer ()->writeKeyEvent (keySym , 0 , false );
925
905
else
926
- cc->writer ()->writeKeyEvent (iter-> second , keyCode, false );
906
+ cc->writer ()->writeKeyEvent (keySym , keyCode, false );
927
907
} catch (rdr::Exception& e) {
928
908
vlog.error (" %s" , e.str ());
929
909
exit_vncviewer (_ (" An unexpected error occurred when communicating "
930
910
" with the server:\n\n %s" ), e.str ());
931
911
}
912
+ }
932
913
933
- downKeySym.erase (iter);
914
+ rdr::U32 Viewport::adjustKeySym (int keyCode, rdr::U32 keySym)
915
+ {
916
+ #ifdef __APPLE__
917
+ // Alt on OS X behaves more like AltGr on other systems, and to get
918
+ // sane behaviour we should translate things in that manner for the
919
+ // remote VNC server. However that means we lose the ability to use
920
+ // Alt as a shortcut modifier. Do what RealVNC does and hijack the
921
+ // left command key as an Alt replacement.
922
+ switch (keySym) {
923
+ case XK_Super_L:
924
+ keySym = XK_Alt_L;
925
+ break ;
926
+ case XK_Super_R:
927
+ keySym = XK_Super_L;
928
+ break ;
929
+ case XK_Alt_L:
930
+ keySym = XK_Mode_switch;
931
+ break ;
932
+ case XK_Alt_R:
933
+ keySym = XK_ISO_Level3_Shift;
934
+ break ;
935
+ }
936
+ #endif
937
+
938
+ return keySym;
939
+ }
940
+
941
+ bool Viewport::handleHotKeyPress (int keyCode, rdr::U32 keySym)
942
+ {
943
+ // Already determined this isn't a hot key combo?
944
+ if (hotKeyWedged)
945
+ return false ;
946
+
947
+ // Are we still collecting modifiers?
948
+ if (!hotKeyReady) {
949
+ std::set<HotKey> hotkeys;
950
+ std::set<HotKey> downHotkeys;
951
+ DownMap::iterator iter;
952
+
953
+ hotkeys = parseHotKeyCombo (hotKeyCombo);
954
+
955
+ // No hot key combo configured?
956
+ if (hotkeys.empty ()) {
957
+ hotKeyWedged = true ;
958
+ return false ;
959
+ }
960
+
961
+ // Which modifiers are pressed?
962
+ for (iter = downKeySym.begin (); iter != downKeySym.end (); ++iter) {
963
+ switch (iter->second ) {
964
+ case XK_Super_L:
965
+ case XK_Super_R:
966
+ downHotkeys.insert (hotkeySuper);
967
+ break ;
968
+ case XK_Alt_L:
969
+ case XK_Alt_R:
970
+ downHotkeys.insert (hotkeyAlt);
971
+ break ;
972
+ case XK_Shift_L:
973
+ case XK_Shift_R:
974
+ downHotkeys.insert (hotkeyShift);
975
+ break ;
976
+ case XK_Control_L:
977
+ case XK_Control_R:
978
+ downHotkeys.insert (hotkeyCtrl);
979
+ break ;
980
+ default :
981
+ // Something else snuck in
982
+ hotKeyWedged = true ;
983
+ return false ;
984
+ }
985
+ }
986
+
987
+ // Not enough?
988
+ if (hotkeys != downHotkeys) {
989
+ // Extra modifiers?
990
+ if (!std::includes (hotkeys.begin (), hotkeys.end (),
991
+ downHotkeys.begin (), downHotkeys.end ())) {
992
+ // Yes, so this is likely some other key combo we should ignore
993
+ hotKeyWedged = true ;
994
+ }
995
+
996
+ return false ;
997
+ }
998
+
999
+ // Is this new key also a modifier?
1000
+ switch (keySym) {
1001
+ case XK_Super_L:
1002
+ case XK_Super_R:
1003
+ case XK_Alt_L:
1004
+ case XK_Alt_R:
1005
+ case XK_Shift_L:
1006
+ case XK_Shift_R:
1007
+ case XK_Control_L:
1008
+ case XK_Control_R:
1009
+ // Yes, so this is likely some other key combo we should ignore
1010
+ hotKeyWedged = true ;
1011
+ return false ;
1012
+ }
1013
+
1014
+ if (keySym == XK_space) {
1015
+ vlog.debug (" Detected hot key escape sequence" );
1016
+ // We're not really wedged, but we want the same effect,
1017
+ // i.e. that all following keys are passed through
1018
+ hotKeyWedged = true ;
1019
+ // This space is consumed though
1020
+ return true ;
1021
+ }
1022
+
1023
+ vlog.debug (" Detected hot key 0x%04x" , keySym);
1024
+
1025
+ // The remote session won't see any more keys, so release the ones
1026
+ // currently down
1027
+ while (!downKeySym.empty ())
1028
+ handleKeyRelease (downKeySym.begin ()->first );
1029
+
1030
+ hotKeyReady = true ;
1031
+ }
1032
+
1033
+ assert (hotKeyReady);
1034
+
1035
+ switch (keySym) {
1036
+ case XK_m:
1037
+ popupContextMenu ();
1038
+ break ;
1039
+ case XK_KP_Enter:
1040
+ case XK_Return:
1041
+ if (window ()->fullscreen_active ())
1042
+ window ()->fullscreen_off ();
1043
+ else
1044
+ ((DesktopWindow*)window ())->fullscreen_on ();
1045
+ break ;
1046
+ default :
1047
+ // Unknown/Unused hot key combo
1048
+ break ;
1049
+ }
1050
+
1051
+ // FIXME: Should be able to press multiple hot keys
1052
+ hotKeyReady = false ;
1053
+
1054
+ return true ;
934
1055
}
935
1056
936
1057
0 commit comments