Browse Source

Multi byte mouse report format for rxvt (Unix)

Margers 10 months ago
parent
commit
9073615dea
2 changed files with 101 additions and 17 deletions
  1. 91 14
      packages/rtl-console/src/unix/keyboard.pp
  2. 10 3
      packages/rtl-console/src/unix/mouse.pp

+ 91 - 14
packages/rtl-console/src/unix/keyboard.pp

@@ -511,46 +511,121 @@ const
   end;
   end;
 
 
   procedure GenMouseEvent;
   procedure GenMouseEvent;
+  { format: CSI M char1 charX charY
+       char1 - button nr and state
+       charX - mouse X (if multi byte format then 1 or 2 chars)
+       charY - mouse Y (if multi byte format then 1 or 2 chars)
+  }
   var MouseEvent: TMouseEvent;
   var MouseEvent: TMouseEvent;
       ch : AnsiChar;
       ch : AnsiChar;
       fdsin : tfdSet;
       fdsin : tfdSet;
       buttonval:byte;
       buttonval:byte;
+      x,y,x1 : word;
+      notMultiByte : boolean;
+      NeedMouseRelease:boolean;
+      addButtMove : byte;
   begin
   begin
     fpFD_ZERO(fdsin);
     fpFD_ZERO(fdsin);
     fpFD_SET(StdInputHandle,fdsin);
     fpFD_SET(StdInputHandle,fdsin);
 {    Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);}
 {    Fillchar(MouseEvent,SizeOf(TMouseEvent),#0);}
-    MouseEvent.action:=0;
+    MouseEvent.buttons:=0;
     if inhead=intail then
     if inhead=intail then
       fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
       fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
     ch:=ttyRecvChar;
     ch:=ttyRecvChar;
+    buttonval:=byte(ch);
+    if ch in [#$c2,#$c3] then
+    begin
+      {xterm multibyte}
+      addButtMove:=(byte(ch) and 1) shl 6;
+      if inhead=intail then
+        fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
+      ch:=ttyRecvChar;
+      buttonval:=byte(ch) or addButtMove;
+    end;
+    NeedMouseRelease:=false;
     { Other bits are used for Shift, Meta and Ctrl modifiers PM }
     { Other bits are used for Shift, Meta and Ctrl modifiers PM }
-    buttonval:=byte(ch)-byte(' ');
+    buttonval:=buttonval and %11100111;
     {bits 0..1: button status
     {bits 0..1: button status
      bit  5   : mouse movement while button down.
      bit  5   : mouse movement while button down.
      bit  6   : interpret button 1 as button 4
      bit  6   : interpret button 1 as button 4
                 interpret button 2 as button 5}
                 interpret button 2 as button 5}
-    case buttonval and 67 of
-      0 : {left button press}
+    case buttonval of
+      %00100000,%01000000 : {left button pressed,moved}
         MouseEvent.buttons:=1;
         MouseEvent.buttons:=1;
-      1 : {middle button pressed }
+      %00100001,%01000001 : {middle button pressed,moved }
         MouseEvent.buttons:=2;
         MouseEvent.buttons:=2;
-      2 : { right button pressed }
+      %00100010,%01000010 : { right button pressed,moved }
         MouseEvent.buttons:=4;
         MouseEvent.buttons:=4;
-      3 : { no button pressed }
+      %00100011,%01000011 : { no button pressed,moved }
         MouseEvent.buttons:=0;
         MouseEvent.buttons:=0;
-      64: { button 4 pressed }
-          MouseEvent.buttons:=8;
-      65: { button 5 pressed }
-          MouseEvent.buttons:=16;
+      %01100000: { button 4 pressed }
+          MouseEvent.buttons:=MouseButton4;
+      %10000000: { rxvt - button 4 move }
+          MouseEvent.buttons:=0;  {rxvt does not release button keeps moving it, fake as no button press move}
+      %01100001: { button 5 pressed }
+          MouseEvent.buttons:=MouseButton5;
+      %10000001: { rxvt - button 5 move }
+          MouseEvent.buttons:=0;
+      %10100000,%11000000 : { xterm - button 6 pressed,moved }
+          MouseEvent.buttons:=MouseXButton1;
+      %01100100 : { rxvt - button 6 pressed, have to add fake release }
+          begin MouseEvent.buttons:=MouseXButton1; NeedMouseRelease:=true; end;
+      %10000100 : { rxvt - button 6 move }
+          MouseEvent.buttons:=0;
+      %10100001,%11000001 : { xterm - button 7 pressed,moved }
+          MouseEvent.buttons:=MouseXButton2;
+      %01100101 : { rxvt - button 7 pressed, have to add fake release }
+          begin MouseEvent.buttons:=MouseXButton2; NeedMouseRelease:=true; end;
+      %10000101: { rxvt - button 7 move }
+          MouseEvent.buttons:=0;
     end;
     end;
+     notMultiByte:=false;
+     {mouse X}
      if inhead=intail then
      if inhead=intail then
        fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
        fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
      ch:=ttyRecvChar;
      ch:=ttyRecvChar;
-     MouseEvent.x:=Ord(ch)-ord(' ')-1;
+     x:=byte(ch);
+     x1:=x;
+     {mouse Y}
      if inhead=intail then
      if inhead=intail then
-      fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
+       fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
      ch:=ttyRecvChar;
      ch:=ttyRecvChar;
-     MouseEvent.y:=Ord(ch)-ord(' ')-1;
+     y:=byte(ch);
+     {decide if this is a single byte or a multi byte mouse report format}
+     if (x in [127..193]) or (x=0) then
+       notMultiByte:=true
+     else
+     if x >= 194 then
+     begin
+       if ch in [#$80..#$bf] then  {probably multibyte}
+         x1:=128+(byte(ch)-128)+(x-194)*($bf-$80+1)
+       else notMultiByte:=true;
+     end;
+     if y < 128 then
+       notMultiByte:=true;
+     {probability is high for multi byte format and we have extra character in line to read}
+     if not notMultiByte and sysKeyPressed then
+     begin
+       if inhead=intail then
+         fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
+       ch:=ttyRecvChar;
+       if ch > ' ' then
+       begin
+         {we are sure, it is a multi byte mouse report format}
+         x:=x1; {new mouse X}
+         y:=byte(ch); {new mouse Y}
+         if (y <> 0 ) and sysKeyPressed and (y >= 194) then
+         begin
+           if inhead=intail then
+             fpSelect(StdInputHandle+1,@fdsin,nil,nil,10);
+           ch:=ttyRecvChar;
+           y:=128+(byte(ch)-128)+(y-194)*($bf-$80+1); {multibyte mouse Y}
+         end;
+       end else PutBackIntoInBuf(ch);
+     end;
+     if (x=0) or (y=0) then exit; {single byte format hit its limts, no mouse event}
+     MouseEvent.x:=x-32-1;
+     MouseEvent.y:=y-32-1;
      mouseevent.action:=MouseActionMove;
      mouseevent.action:=MouseActionMove;
      if (lastmouseevent.buttons=0) and (mouseevent.buttons<>0) then
      if (lastmouseevent.buttons=0) and (mouseevent.buttons<>0) then
        MouseEvent.action:=MouseActionDown;
        MouseEvent.action:=MouseActionDown;
@@ -577,6 +652,8 @@ const
      PutMouseEvent(MouseEvent);
      PutMouseEvent(MouseEvent);
      if (MouseEvent.buttons and (8+16)) <> 0 then // 'M' escape sequence cannot map button 4&5 release, so fake one.
      if (MouseEvent.buttons and (8+16)) <> 0 then // 'M' escape sequence cannot map button 4&5 release, so fake one.
        GenFakeReleaseEvent(MouseEvent);
        GenFakeReleaseEvent(MouseEvent);
+     if NeedMouseRelease then
+       GenFakeReleaseEvent(MouseEvent);
 {$ifdef DebugMouse}
 {$ifdef DebugMouse}
      if MouseEvent.Action=MouseActionDown then
      if MouseEvent.Action=MouseActionDown then
        Write(system.stderr,'Button down : ')
        Write(system.stderr,'Button down : ')

+ 10 - 3
packages/rtl-console/src/unix/mouse.pp

@@ -221,7 +221,10 @@ begin
         {Use the xterm mouse, report button events only.}
         {Use the xterm mouse, report button events only.}
         gpm_fs:=-1000;
         gpm_fs:=-1000;
         {write(#27'[?1001s');} { save old hilit tracking }
         {write(#27'[?1001s');} { save old hilit tracking }
-        write(#27'[?1000h'); { enable mouse tracking }
+        write(#27'[?1000h'); { try to enable mouse down+up tracking }
+        write(#27'[?1002h'); { try to enable mouse down+up and drag tracking }
+        write(#27'[?1003h'); { try to enable mouse all motion tracking }
+        write(#27'[?1005h'); { try to enable mouse report format multibyte }
         if not DisableSGRExtModeMouse then
         if not DisableSGRExtModeMouse then
           write(#27'[?1006h'); { try to enable Extended/SGH 1006 mouse tracking }
           write(#27'[?1006h'); { try to enable Extended/SGH 1006 mouse tracking }
       end;
       end;
@@ -265,10 +268,14 @@ begin
     -1000:
     -1000:
       begin
       begin
         {xterm mouse}
         {xterm mouse}
-        write(#27'[?1000l'); { disable mouse tracking }
-        {write(#27'[?1001r');} { Restore old hilit tracking }
         if not DisableSGRExtModeMouse then
         if not DisableSGRExtModeMouse then
           write(#27'[?1006l'); { disable Extended/SGH 1006 mouse tracking }
           write(#27'[?1006l'); { disable Extended/SGH 1006 mouse tracking }
+        write(#27'[?1005l'); { disable mouse report format multibyte }
+        write(#27'[?1003l'); { disable mouse all motion tracking }
+        write(#27'[?1002l'); { disable mouse down+up and drag tracking }
+        write(#27'[?1000l'); { disable mouse down+up tracking }
+        {write(#27'[?1001r');} { Restore old hilit tracking }
+
       end;
       end;
     -1003:
     -1003:
       begin
       begin