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 |
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); |
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 |
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 |
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); |