Subversion Repositories Kolibri OS

Rev

Rev 619 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
616 bw 1
{}
2
 
3
procedure OpenStdout(var f: TextRec); forward;
4
procedure WriteStdout(var f: TextRec); forward;
5
procedure CloseStdout(var f: TextRec); forward;
6
 
7
procedure OpenStdin(var f: TextRec); forward;
8
procedure ReadStdin(var f: TextRec); forward;
9
procedure CloseStdin(var f: TextRec); forward;
10
 
11
 
12
 
13
procedure AssignStdout(var f: Text);
14
begin
15
  Assign(f, '');
16
  TextRec(f).OpenFunc := @OpenStdout;
17
  Rewrite(f);
18
end;
19
 
20
procedure OpenStdout(var f: TextRec);
21
begin
22
  TextRec(f).InOutFunc := @WriteStdout;
23
  TextRec(f).FlushFunc := @WriteStdout;
24
  TextRec(f).CloseFunc := @CloseStdout;
25
end;
26
 
27
procedure WriteStdout(var f: TextRec);
28
var
29
  msg: String;
30
begin
31
  msg := StrPas(PChar(f.bufptr));
32
  SetLength(msg, f.bufpos);
33
  f.bufpos := 0;
34
  Konsole.Write(msg);
35
end;
36
 
37
procedure CloseStdout(var f: TextRec);
38
begin
39
end;
40
 
41
 
42
 
43
procedure AssignStdin(var f: Text);
44
begin
45
  Assign(f, '');
46
  TextRec(f).OpenFunc := @OpenStdin;
47
  Reset(f);
48
end;
49
 
50
procedure OpenStdin(var f: TextRec);
51
begin
52
  TextRec(f).InOutFunc := @ReadStdin;
53
  TextRec(f).FlushFunc := nil;
54
  TextRec(f).CloseFunc := @CloseStdin;
55
end;
56
 
57
procedure ReadStdin(var f: TextRec);
58
var
59
  max, curpos: Longint;
60
  c: Longint;
61
begin
62
  max := f.bufsize - Length(LineEnding);
63
  curpos := 0;
64
  repeat
65
    c := 13{l4_getc()};
66
    case c of
67
      13:
68
      begin
69
        {f.bufptr^[curpos] := LineEnding;}
70
        Inc(curpos);
71
        f.bufpos := 0;
72
        f.bufend := curpos;
73
        {l4_putc(Longint(LineEnding));}
74
        break;
75
      end;
76
      32..126: if curpos < max then
77
      begin
78
        f.bufptr^[curpos] := Char(c);
79
        Inc(curpos);
80
        {l4_putc(c);}
81
      end;
82
    end;
83
  until False;
84
end;
85
 
86
procedure CloseStdin(var f: TextRec);
87
begin
88
end;
89
 
90
 
91
{ TKonsole }
92
 
93
procedure KonsoleThreadMain(Console: PKonsole);
94
{Рабочий цикл консоли}
95
var
96
  ThreadInfo: TKosThreadInfo;
97
  Message: ShortString;
98
  Event: DWord;
99
begin
100
  kos_maskevents(ME_PAINT or ME_KEYBOARD or ME_IPC);
101
  kos_threadinfo(@ThreadInfo);
102
  Console^.FThreadSlot := kos_getthreadslot(ThreadInfo.ThreadID);
103
 
104
  kos_initipc(Console^.FIPCBuffer, Console^.FIPCBufferSize);
105
 
106
  {сразу отобразить и активировать окно}
107
  Console^.Paint();
108
  {$ifndef EMULATOR}
109
  kos_setactivewindow(Console^.FThreadSlot);
110
  {$endif}
111
 
112
  {готов к обработке событий}
113
  Console^.FOpened := True;
114
  while not Console^.FTerminate do
115
  begin
116
    Event := kos_getevent();
117
    if Console^.FTerminate then
118
      {Console^.ProcessMessage('[CONSOLE] Terminate...'#13#10)} else
119
    case Event of
120
      SE_PAINT: Console^.Paint();
121
      SE_KEYBOARD: Console^.ProcessKeyboard(kos_getkey());
122
      SE_IPC: while Console^.ReceiveMessage(Message) do Console^.ProcessMessage(Message);
123
    end;
124
  end;
125
  Console^.FOpened := False;
126
end;
127
 
128
constructor TKonsole.Init(ACaption: String);
129
const
130
  IPC_SIZE = 4096;
131
var
132
  ThreadInfo: TKosThreadInfo;
133
begin
134
  if ACaption <> '' then
135
    FCaption := ACaption else
136
  begin
137
    kos_threadinfo(@ThreadInfo);
138
    FCaption := StrPas(ThreadInfo.AppName);
139
  end;
140
  SetLength(FLines, 1);
141
  FLines[0] := ' ';
142
  FCursor.X := 1;
143
  FCursor.Y := 0;
144
  FMaxLines := 150;
145
  FTerminate := False;
146
  FOpened := False;
147
  FIPCBufferSize := SizeOf(TKosIPC) + IPC_SIZE;
148
  FIPCBuffer := GetMem(FIPCBufferSize);
149
  {FIPCBufferSize := SizeOf(KonsoleIPCBuffer);
150
  FIPCBuffer := @KonsoleIPCBuffer;}
151
  FIPCBuffer^.Lock := False;
152
  FIPCBuffer^.Size := 0;
153
  FThreadSlot := -1;
154
  FThreadID := BeginThread(TThreadFunc(@KonsoleThreadMain), @Self);
155
  if FThreadID <> 0 then
156
    while not FOpened do kos_delay(1);
157
end;
158
 
159
destructor TKonsole.Done();
160
begin
161
  FTerminate := True;
162
  Self.Write(#0);
163
  if FOpened then kos_delay(1);
164
  if FOpened then kos_delay(10);
165
  if FOpened then kos_delay(20);
166
  if FOpened then
167
  begin
168
    FOpened := False;
169
    KillThread(FThreadID);
170
  end;
171
  FreeMem(FIPCBuffer);
172
  SetLength(FLines, 0);
173
end;
174
 
175
function TKonsole.ReceiveMessage(var Message: ShortString): Boolean;
176
{Извлечь первое сообщение из буфера}
177
var
178
  PMsg: PKosMessage;
179
  Size: Longword;
180
begin
181
  if FIPCBuffer^.Size > 0 then
182
  begin
183
    FIPCBuffer^.Lock := True;
184
    PMsg := Pointer(Longword(FIPCBuffer) + SizeOf(TKosIPC));
185
    {TODO: проверка PMsg^.SenderID}
186
    {Size := PMsg^.Size;
187
    Dec(FIPCBuffer^.Size, Size + SizeOf(TKosMessage));
188
    if Size > 255 then Size := 255;
189
    SetLength(Message, Size);
190
    Move(Pointer(Longword(PMsg) + SizeOf(TKosMessage))^, Message[1], Size);
191
    if FIPCBuffer^.Size > 0 then
192
      Move(Pointer(Longword(PMsg) + SizeOf(TKosMessage) + PMsg^.Size)^, PMsg^, FIPCBuffer^.Size);}
193
 
194
    {XXX}
195
    Size := FIPCBuffer^.Size;
196
    Dec(FIPCBuffer^.Size, Size);
197
    if Size > 255 then Size := 255;
198
    SetLength(Message, Size);
199
    Move(PMsg^, Message[1], Size);
200
 
201
    Result := True;
202
  end else
203
  begin
204
    Message := '';
205
    Result := False;
206
  end;
207
 
208
  {FIXME: если FIPCBuffer^.Size = 0, то FIPCBuffer^.Lock все равно > 0}
209
  FIPCBuffer^.Lock := False;
210
end;
211
 
212
procedure TKonsole.ProcessMessage(Message: ShortString);
213
{Вывести сообщение на консоль}
214
var
215
  S: String;
216
  LinesCount: Word;
217
  CR, LF, W: Word;
218
  BottomRow: Boolean = True;
219
begin
220
  if Length(Message) < 1 then Exit;
221
 
222
  repeat
223
    CR := Pos(#13, Message);
224
    LF := Pos(#10, Message);
225
    if (CR > 0) and ((CR < LF) or (LF <= 0)) then
226
      W := CR else
227
    if LF > 0 then
228
      W := LF else
229
      W := Length(Message) + 1;
230
    if W > 0 then
231
    begin
232
      if W > 1 then
233
      begin
234
        S := Copy(Message, 1, W - 1);
235
        Delete(FLines[FCursor.Y], FCursor.X, Length(FLines[FCursor.Y]) - FCursor.X);
236
        Insert(S, FLines[FCursor.Y], FCursor.X);
237
        Inc(FCursor.X, Length(S));
238
      end;
239
      Delete(Message, 1, W);
240
      if W = CR then
241
        {перевод коретки в начало строки}
242
        FCursor.X := 1 else
243
      if W = LF then
244
      begin
245
        {перевод коретки на следующую строку}
246
        BottomRow := False;
247
        Inc(FCursor.Y);
248
        LinesCount := Length(FLines);
249
        while FCursor.Y >= FMaxLines do Dec(FCursor.Y, FMaxLines);
250
        if FCursor.Y < LinesCount then FLines[FCursor.Y] := '';
251
        while FCursor.Y >= LinesCount do
252
        begin
253
          SetLength(FLines, LinesCount + 1);
254
          FLines[LinesCount] := '';
255
          Inc(LinesCount);
256
        end;
257
      end;
258
    end;
259
  until Length(Message) <= 0;
260
 
261
  Paint(BottomRow);
262
end;
263
 
264
procedure TKonsole.ProcessKeyboard(Key: Word);
265
begin
266
  FKeyPressed := Key;
267
end;
268
 
269
function TKonsole.GetRect(): TKosRect;
270
var
271
  ThreadInfo: TKosThreadInfo;
272
begin
273
  kos_threadinfo(@ThreadInfo, FThreadSlot);
274
  Result := ThreadInfo.WindowRect;
275
end;
276
 
277
function TKonsole.GetKeyPressed(): Word;
278
begin
279
  Result := FKeyPressed;
280
  FKeyPressed := 0;
281
end;
282
 
283
procedure TKonsole.Paint(BottomRow: Boolean);
284
var
285
  Buffer: array[Byte] of Char;
286
  Rect: TKosRect;
287
  J: Longint;
288
  Width, Height, Row: Longint;
289
  CaptionHeight, BorderWidth, FontWidth, FontHeight: Longint;
290
begin
291
  CaptionHeight := 16;
292
  BorderWidth := 5;
293
  FontWidth := 6;
294
  FontHeight := 9;
295
 
296
  kos_begindraw();
297
 
298
  if not BottomRow then
299
  begin
300
    {отрисовка окна}
301
    kos_definewindow(60, 60, 400, 400, $63000000);
302
    {вывод заголовка}
303
    Move(FCaption[1], Buffer, Length(FCaption));
304
    Buffer[Length(FCaption)] := #0;
305
    kos_setcaption(Buffer);
306
  end;
307
 
308
  {подготовка к выводу строк}
309
  Rect := GetRect();
310
  Dec(Rect.Width, BorderWidth * 2);
311
  Dec(Rect.Height, CaptionHeight + BorderWidth * 2);
312
  Width  := Rect.Width div FontWidth;
313
  Height := Rect.Height - FontHeight;
314
  Row := FCursor.Y;
315
 
316
  while Height > 0 do
317
  begin
318
    {вывод одной строки}
319
    J := Length(FLines[Row]);
320
    if J > Width then J := Width;
321
    kos_drawtext(0, Height, Copy(FLines[Row], 1, J), $00DD00, $FF000000);
322
    {заливка оставшегося пространства в строке}
323
    J := J * FontWidth;
324
    kos_drawrect(J, Height, Rect.Width - J + 1, FontHeight, $000000);
325
    {подготовка к выводу следующей строки}
326
    Dec(Height, FontHeight);
327
    Dec(Row);
328
    if BottomRow or ((Row < 0) and (Length(FLines) < FMaxLines)) then Break;
329
    while Row < 0 do Inc(Row, FMaxLines);
330
  end;
331
  if FCursor.X <= Width then
332
    {отрисовка курсора}
333
    kos_drawrect((FCursor.X - 1) * FontWidth, Rect.Height - 2, FontWidth, 2, $FFFFFF);
334
  if not BottomRow then
335
    {заливка оставшейся части окна}
336
    kos_drawrect(0, 0, Rect.Width + 1, Height + FontHeight, $000000);
337
 
338
  kos_enddraw();
339
end;
340
 
341
procedure TKonsole.Write(Message: ShortString);
342
var
343
  I: Integer;
344
begin
345
  {XXX: возможна ситуация при которой сообщение не будет отправлено}
346
  if FOpened then
347
  begin
348
    I := 20;
349
    while (kos_sendmsg(FThreadID, @Message[1], Length(Message)) = 2) and (I > 0) do
350
    begin
351
      Dec(I);
352
      ThreadSwitch;
353
    end;
354
  end;
355
end;