hedgewars/uChat.pas
changeset 11383 d3b603323b2b
parent 11372 208bc571f949
child 11476 c4e1d39acc56
equal deleted inserted replaced
11381:437a60995fe1 11383:d3b603323b2b
    19 {$INCLUDE "options.inc"}
    19 {$INCLUDE "options.inc"}
    20 
    20 
    21 unit uChat;
    21 unit uChat;
    22 
    22 
    23 interface
    23 interface
       
    24 uses SDLh;
    24 
    25 
    25 procedure initModule;
    26 procedure initModule;
    26 procedure freeModule;
    27 procedure freeModule;
    27 procedure ReloadLines;
    28 procedure ReloadLines;
    28 procedure CleanupInput;
    29 procedure CleanupInput;
    29 procedure AddChatString(s: shortstring);
    30 procedure AddChatString(s: shortstring);
    30 procedure DrawChat;
    31 procedure DrawChat;
    31 procedure KeyPressChat(Key, Sym: Longword; Modifier: Word);
    32 procedure KeyPressChat(keysym: TSDL_Keysym);
    32 procedure SendHogSpeech(s: shortstring);
    33 procedure SendHogSpeech(s: shortstring);
    33 procedure CopyToClipboard(var newContent: shortstring);
    34 procedure CopyToClipboard(var newContent: shortstring);
       
    35 procedure TextInput(var event: TSDL_TextInputEvent);
    34 
    36 
    35 implementation
    37 implementation
    36 uses SDLh, uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO, uScript, uRenderUtils;
    38 uses uInputHandler, uTypes, uVariables, uCommands, uUtils, uTextures, uRender, uIO, uScript, uRenderUtils;
    37 
    39 
    38 const MaxStrIndex = 27;
    40 const MaxStrIndex = 27;
    39       MaxInputStrLen = 200;
    41       MaxInputStrLen = 200;
    40 
    42 
    41 type TChatLine = record
    43 type TChatLine = record
   265 SetLine(Strs[lastStr], s, false);
   267 SetLine(Strs[lastStr], s, false);
   266 
   268 
   267 inc(visibleCount)
   269 inc(visibleCount)
   268 end;
   270 end;
   269 
   271 
   270 procedure CheckPasteBuffer(); forward;
       
   271 
       
   272 procedure UpdateInputLinePrefix();
   272 procedure UpdateInputLinePrefix();
   273 begin
   273 begin
   274 if liveLua then
   274 if liveLua then
   275     begin
   275     begin
   276     InputLinePrefix.color:= colors[#1];
   276     InputLinePrefix.color:= colors[#1];
   300 top := 10 + visibleCount * ClHeight; // we start with input line (if any)
   300 top := 10 + visibleCount * ClHeight; // we start with input line (if any)
   301 
   301 
   302 // draw chat input line first and under all other lines
   302 // draw chat input line first and under all other lines
   303 if (GameState = gsChat) and (InputStr.Tex <> nil) then
   303 if (GameState = gsChat) and (InputStr.Tex <> nil) then
   304     begin
   304     begin
   305     CheckPasteBuffer();
       
   306 
   305 
   307     if InputLinePrefix.Tex = nil then
   306     if InputLinePrefix.Tex = nil then
   308         RenderChatLineTex(InputLinePrefix, InputLinePrefix.s);
   307         RenderChatLineTex(InputLinePrefix, InputLinePrefix.s);
   309 
   308 
   310     DrawTexture(left, top, InputLinePrefix.Tex);
   309     DrawTexture(left, top, InputLinePrefix.Tex);
   569 
   568 
   570 procedure CleanupInput;
   569 procedure CleanupInput;
   571 begin
   570 begin
   572     FreezeEnterKey;
   571     FreezeEnterKey;
   573     history:= 0;
   572     history:= 0;
   574 {$IFNDEF SDL2}
   573     SDL_StopTextInput();
   575     SDL_EnableKeyRepeat(0,0);
   574     //SDL_EnableKeyRepeat(0,0);
   576 {$ENDIF}
       
   577     GameState:= gsGame;
   575     GameState:= gsGame;
   578     ResetKbd;
   576     ResetKbd;
   579 end;
   577 end;
   580 
   578 
   581 procedure DelBytesFromInputStrBack(endIdx: integer; count: byte);
   579 procedure DelBytesFromInputStrBack(endIdx: integer; count: byte);
   726     end;
   724     end;
   727 end;
   725 end;
   728 
   726 
   729 procedure CopyToClipboard(var newContent: shortstring);
   727 procedure CopyToClipboard(var newContent: shortstring);
   730 begin
   728 begin
   731     SendIPC(_S'y' + copy(newContent, 1, 253) + #0);
   729     // SDL2 clipboard
       
   730     SDL_SetClipboardText(Str2PChar(newContent));
   732 end;
   731 end;
   733 
   732 
   734 procedure CopySelectionToClipboard();
   733 procedure CopySelectionToClipboard();
   735 var selection: shortstring;
   734 var selection: shortstring;
   736 begin
   735 begin
   780         UpdateCursorCoords();
   779         UpdateCursorCoords();
   781         end;
   780         end;
   782 end;
   781 end;
   783 
   782 
   784 procedure PasteFromClipboard();
   783 procedure PasteFromClipboard();
   785 begin
   784 var clip: PChar;
   786     SendIPC(_S'Y');
   785 begin
   787 end;
   786     // use SDL2 clipboard functions
   788 
   787     if SDL_HasClipboardText() then
   789 procedure CheckPasteBuffer();
   788         begin
   790 begin
   789         clip:= SDL_GetClipboardText();
   791     if Length(ChatPasteBuffer) > 0 then
   790         // returns NULL if not enough memory for a copy of clipboard content 
   792         begin
   791         if clip <> nil then
   793         InsertIntoInputStr(ChatPasteBuffer);
   792             begin
   794         ChatPasteBuffer:= '';
   793             InsertIntoInputStr(shortstring(clip));
   795         end;
   794             SDL_free(Pointer(clip));
   796 end;
   795             end;
   797 
   796         end;
   798 procedure KeyPressChat(Key, Sym: Longword; Modifier: Word);
   797 end;
   799 const firstByteMark: array[0..3] of byte = (0, $C0, $E0, $F0);
   798 
   800       nonStateMask = (not (KMOD_NUM or KMOD_CAPS));
   799 procedure KeyPressChat(keysym: TSDL_Keysym);
   801 var i, btw, index: integer;
   800 const nonStateMask = (not (KMOD_NUM or KMOD_CAPS));
   802     utf8: shortstring;
   801 var i, index: integer;
   803     action, selMode, ctrl, ctrlonly: boolean;
   802     selMode, ctrl, ctrlonly: boolean;
   804     skip: TCharSkip;
   803     skip: TCharSkip;
   805 begin
   804     Scancode: TSDL_Scancode;
       
   805     Modifier: Word;
       
   806 begin
       
   807     Scancode:= keysym.scancode;
       
   808     Modifier:= keysym.modifier;
       
   809 
   806     LastKeyPressTick:= RealTicks;
   810     LastKeyPressTick:= RealTicks;
   807     action:= true;
       
   808 
       
   809     CheckPasteBuffer();
       
   810 
   811 
   811     selMode:= (modifier and (KMOD_LSHIFT or KMOD_RSHIFT)) <> 0;
   812     selMode:= (modifier and (KMOD_LSHIFT or KMOD_RSHIFT)) <> 0;
   812     ctrl:= (modifier and (KMOD_LCTRL or KMOD_RCTRL)) <> 0;
   813     ctrl:= (modifier and (KMOD_LCTRL or KMOD_RCTRL)) <> 0;
   813     ctrlonly:= ctrl and ((modifier and nonStateMask and (not (KMOD_LCTRL or KMOD_RCTRL))) = 0);
   814     ctrlonly:= ctrl and ((modifier and nonStateMask and (not (KMOD_LCTRL or KMOD_RCTRL))) = 0);
   814     skip:= none;
   815     skip:= none;
   815 
   816 
   816     case Sym of
   817     case Scancode of
   817         SDLK_BACKSPACE:
   818         SDL_SCANCODE_BACKSPACE:
   818             begin
   819             begin
   819             if selectedPos < 0 then
   820             if selectedPos < 0 then
   820                 begin
   821                 begin
   821                 HandleSelection(true);
   822                 HandleSelection(true);
   822 
   823 
   829                 end;
   830                 end;
   830 
   831 
   831             DeleteSelected();
   832             DeleteSelected();
   832             UpdateCursorCoords();
   833             UpdateCursorCoords();
   833             end;
   834             end;
   834         SDLK_DELETE:
   835         SDL_SCANCODE_DELETE:
   835             begin
   836             begin
   836             if selectedPos < 0 then
   837             if selectedPos < 0 then
   837                 begin
   838                 begin
   838                 HandleSelection(true);
   839                 HandleSelection(true);
   839 
   840 
   846                 end;
   847                 end;
   847 
   848 
   848             DeleteSelected();
   849             DeleteSelected();
   849             UpdateCursorCoords();
   850             UpdateCursorCoords();
   850             end;
   851             end;
   851         SDLK_ESCAPE:
   852         SDL_SCANCODE_ESCAPE:
   852             begin
   853             begin
   853             if Length(InputStr.s) > 0 then
   854             if Length(InputStr.s) > 0 then
   854                 begin
   855                 begin
   855                 SetLine(InputStr, '', true);
   856                 SetLine(InputStr, '', true);
   856                 ResetCursor();
   857                 ResetCursor();
   857                 end
   858                 end
   858             else CleanupInput
   859             else CleanupInput
   859             end;
   860             end;
   860         SDLK_RETURN, SDLK_KP_ENTER:
   861         SDL_SCANCODE_RETURN, SDL_SCANCODE_KP_ENTER:
   861             begin
   862             begin
   862             if Length(InputStr.s) > 0 then
   863             if Length(InputStr.s) > 0 then
   863                 begin
   864                 begin
   864                 AcceptChatString(InputStr.s);
   865                 AcceptChatString(InputStr.s);
   865                 SetLine(InputStr, '', false);
   866                 SetLine(InputStr, '', false);
   866                 ResetCursor();
   867                 ResetCursor();
   867                 end;
   868                 end;
   868             CleanupInput
   869             CleanupInput
   869             end;
   870             end;
   870         SDLK_UP, SDLK_DOWN:
   871         SDL_SCANCODE_UP, SDL_SCANCODE_DOWN:
   871             begin
   872             begin
   872             if (Sym = SDLK_UP) and (history < localLastStr) then inc(history);
   873             if (Scancode = SDL_SCANCODE_UP) and (history < localLastStr) then inc(history);
   873             if (Sym = SDLK_DOWN) and (history > 0) then dec(history);
   874             if (Scancode = SDL_SCANCODE_DOWN) and (history > 0) then dec(history);
   874             index:= localLastStr - history + 1;
   875             index:= localLastStr - history + 1;
   875             if (index > localLastStr) then
   876             if (index > localLastStr) then
   876                 begin
   877                 begin
   877                 SetLine(InputStr, '', true);
   878                 SetLine(InputStr, '', true);
   878                 end
   879                 end
   882                 end;
   883                 end;
   883             cursorPos:= Length(InputStr.s);
   884             cursorPos:= Length(InputStr.s);
   884             ResetSelection();
   885             ResetSelection();
   885             UpdateCursorCoords();
   886             UpdateCursorCoords();
   886             end;
   887             end;
   887         SDLK_HOME:
   888         SDL_SCANCODE_HOME:
   888             begin
   889             begin
   889             if cursorPos > 0 then
   890             if cursorPos > 0 then
   890                 begin
   891                 begin
   891                 HandleSelection(selMode);
   892                 HandleSelection(selMode);
   892                 cursorPos:= 0;
   893                 cursorPos:= 0;
   894             else if (not selMode) then
   895             else if (not selMode) then
   895                 ResetSelection();
   896                 ResetSelection();
   896 
   897 
   897             UpdateCursorCoords();
   898             UpdateCursorCoords();
   898             end;
   899             end;
   899         SDLK_END:
   900         SDL_SCANCODE_END:
   900             begin
   901             begin
   901             i:= Length(InputStr.s);
   902             i:= Length(InputStr.s);
   902             if cursorPos < i then
   903             if cursorPos < i then
   903                 begin
   904                 begin
   904                 HandleSelection(selMode);
   905                 HandleSelection(selMode);
   907             else if (not selMode) then
   908             else if (not selMode) then
   908                 ResetSelection();
   909                 ResetSelection();
   909 
   910 
   910             UpdateCursorCoords();
   911             UpdateCursorCoords();
   911             end;
   912             end;
   912         SDLK_LEFT:
   913         SDL_SCANCODE_LEFT:
   913             begin
   914             begin
   914             if cursorPos > 0 then
   915             if cursorPos > 0 then
   915                 begin
   916                 begin
   916 
   917 
   917                 if ctrl then
   918                 if ctrl then
   936             else if (not selMode) then
   937             else if (not selMode) then
   937                 ResetSelection();
   938                 ResetSelection();
   938 
   939 
   939             UpdateCursorCoords();
   940             UpdateCursorCoords();
   940             end;
   941             end;
   941         SDLK_RIGHT:
   942         SDL_SCANCODE_RIGHT:
   942             begin
   943             begin
   943             if cursorPos < Length(InputStr.s) then
   944             if cursorPos < Length(InputStr.s) then
   944                 begin
   945                 begin
   945 
   946 
   946                 if selMode or (selectedPos < 0) then
   947                 if selMode or (selectedPos < 0) then
   961             else if (not selMode) then
   962             else if (not selMode) then
   962                 ResetSelection();
   963                 ResetSelection();
   963 
   964 
   964             UpdateCursorCoords();
   965             UpdateCursorCoords();
   965             end;
   966             end;
   966         SDLK_PAGEUP, SDLK_PAGEDOWN:
   967         SDL_SCANCODE_PAGEUP, SDL_SCANCODE_PAGEDOWN:
   967             begin
   968             begin
   968             // ignore me!!!
   969             // ignore me!!!
   969             end;
   970             end;
   970         SDLK_a:
   971         // TODO: figure out how to determine those keys better
       
   972         SDL_SCANCODE_a:
   971             begin
   973             begin
   972             // select all
   974             // select all
   973             if ctrlonly then
   975             if ctrlonly then
   974                 begin
   976                 begin
   975                 ResetSelection();
   977                 ResetSelection();
   976                 cursorPos:= 0;
   978                 cursorPos:= 0;
   977                 HandleSelection(true);
   979                 HandleSelection(true);
   978                 cursorPos:= Length(InputStr.s);
   980                 cursorPos:= Length(InputStr.s);
   979                 UpdateCursorCoords();
   981                 UpdateCursorCoords();
   980                 end
   982                 end
   981             else
   983             end;
   982                 action:= false;
   984         SDL_SCANCODE_c:
   983             end;
       
   984         SDLK_c:
       
   985             begin
   985             begin
   986             // copy
   986             // copy
   987             if ctrlonly then
   987             if ctrlonly then
   988                 CopySelectionToClipboard()
   988                 CopySelectionToClipboard()
   989             else
   989             end;
   990                 action:= false;
   990         SDL_SCANCODE_v:
   991             end;
       
   992         SDLK_v:
       
   993             begin
   991             begin
   994             // paste
   992             // paste
   995             if ctrlonly then
   993             if ctrlonly then
   996                 begin
   994                 begin
   997                 DeleteSelected();
   995                 DeleteSelected();
   998                 PasteFromClipboard();
   996                 PasteFromClipboard();
   999                 end
   997                 end
  1000             else
   998             end;
  1001                 action:= false;
   999         SDL_SCANCODE_x:
  1002             end;
       
  1003         SDLK_x:
       
  1004             begin
  1000             begin
  1005             // cut
  1001             // cut
  1006             if ctrlonly then
  1002             if ctrlonly then
  1007                 begin
  1003                 begin
  1008                 CopySelectionToClipboard();
  1004                 CopySelectionToClipboard();
  1009                 DeleteSelected();
  1005                 DeleteSelected();
  1010                 end
  1006                 end
  1011             else
  1007             end;
  1012                 action:= false;
  1008         end;
  1013             end;
  1009 end;
  1014         else
  1010 
  1015             action:= false;
  1011 procedure TextInput(var event: TSDL_TextInputEvent);
  1016         end;
  1012 var s: shortstring;
  1017     if not action and (Key <> 0) then
  1013     l: byte;
  1018         begin
  1014 begin
  1019         DeleteSelected();
  1015     DeleteSelected();
  1020 
  1016 
  1021         if (Key < $80) then
  1017     l:= 0;
  1022             btw:= 1
  1018     while event.text[l] <> #0 do
  1023         else if (Key < $800) then
  1019         begin
  1024             btw:= 2
  1020         s[l + 1]:= event.text[l];
  1025         else if (Key < $10000) then
  1021         inc(l)
  1026             btw:= 3
  1022         end;
  1027         else
  1023 
  1028             btw:= 4;
  1024     if l > 0 then
  1029 
  1025         begin
  1030         utf8:= '';
  1026         if byte(InputStr.s[0]) + l > 240 then exit;
  1031 
  1027         s[0]:= char(l);
  1032         for i:= btw downto 2 do
  1028         InsertIntoInputStr(s);
  1033             begin
       
  1034             utf8:= char((Key or $80) and $BF) + utf8;
       
  1035             Key:= Key shr 6
       
  1036             end;
       
  1037 
       
  1038         utf8:= char(Key or firstByteMark[Pred(btw)]) + utf8;
       
  1039 
       
  1040         if Length(InputStr.s) + btw > MaxInputStrLen then
       
  1041             exit;
       
  1042 
       
  1043         // if speech bubble quotes are used as first input, add the closing quote and place cursor inbetween
       
  1044         if (Length(InputStr.s) = 0) and (Length(utf8) = 1) and (charIsForHogSpeech(utf8[1])) then
       
  1045             begin
       
  1046             InsertIntoInputStr(utf8);
       
  1047             InsertIntoInputStr(utf8);
       
  1048             cursorPos:= 1;
       
  1049             UpdateCursorCoords();
       
  1050             end
       
  1051         else
       
  1052             InsertIntoInputStr(utf8);
       
  1053         end
  1029         end
  1054 end;
  1030 end;
       
  1031 
  1055 
  1032 
  1056 procedure chChatMessage(var s: shortstring);
  1033 procedure chChatMessage(var s: shortstring);
  1057 begin
  1034 begin
  1058     AddChatString(s)
  1035     AddChatString(s)
  1059 end;
  1036 end;
  1096 
  1073 
  1097 procedure chChat(var s: shortstring);
  1074 procedure chChat(var s: shortstring);
  1098 begin
  1075 begin
  1099     s:= s; // avoid compiler hint
  1076     s:= s; // avoid compiler hint
  1100     GameState:= gsChat;
  1077     GameState:= gsChat;
  1101 {$IFNDEF SDL2}
  1078     SDL_StopTextInput();
  1102     SDL_EnableKeyRepeat(200,45);
  1079     SDL_StartTextInput();
  1103 {$ENDIF}
  1080     //SDL_EnableKeyRepeat(200,45);
  1104     if length(s) = 0 then
  1081     if length(s) = 0 then
  1105         SetLine(InputStr, '', true)
  1082         SetLine(InputStr, '', true)
  1106     else
  1083     else
  1107         begin
  1084         begin
  1108         SetLine(InputStr, '/team ', true);
  1085         SetLine(InputStr, '/team ', true);
  1138     for i:= 0 to MaxStrIndex do
  1115     for i:= 0 to MaxStrIndex do
  1139         Strs[i].Tex := nil;
  1116         Strs[i].Tex := nil;
  1140 
  1117 
  1141     LastKeyPressTick:= 0;
  1118     LastKeyPressTick:= 0;
  1142     ResetCursor();
  1119     ResetCursor();
       
  1120     SDL_StopTextInput();
  1143 end;
  1121 end;
  1144 
  1122 
  1145 procedure freeModule;
  1123 procedure freeModule;
  1146 var i: ShortInt;
  1124 var i: ShortInt;
  1147 begin
  1125 begin