Subversion Repositories Kolibri OS

Rev

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