mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-28 10:02:14 +00:00
ADD: Start to implement console under Windows
This commit is contained in:
parent
7f418c434f
commit
de5ab4781e
3 changed files with 361 additions and 0 deletions
106
src/platform/uterminal.pas
Normal file
106
src/platform/uterminal.pas
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
{
|
||||
Double Commander
|
||||
-------------------------------------------------------------------------
|
||||
Terminal emulator abstract class
|
||||
|
||||
Copyright (C) 2009 Koblov Alexander (Alexx2000@mail.ru)
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
}
|
||||
|
||||
unit uTerminal;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, uCmdBox;
|
||||
|
||||
type
|
||||
Cint = Integer;
|
||||
|
||||
{ TTerminal }
|
||||
|
||||
TTerminal = class
|
||||
protected
|
||||
FChildPid: THandle;
|
||||
Fpty: LongInt;
|
||||
public
|
||||
{en
|
||||
Read info from pty
|
||||
}
|
||||
function Read_pty(var Output: UTF8String; const TimeOut: LongInt = 10): LongInt; virtual; abstract;
|
||||
{en
|
||||
Create new pty and start cmd
|
||||
}
|
||||
function Fork_pty(const RowCount, ColCount: Integer; const Command: UTF8String; const Params: UTF8String = ''): THandle; virtual; abstract;
|
||||
{en
|
||||
Write string to pty
|
||||
}
|
||||
function Write_pty(const Input: UTF8String): Boolean; virtual; abstract;
|
||||
//---------------------
|
||||
function SendBreak_pty(): Boolean; virtual; abstract; // ^C
|
||||
function SendSignal_pty(Sig: Cint): Boolean; virtual; abstract;
|
||||
function SetScreenSize(ColCount, RowCount: Integer): Boolean; virtual; abstract;
|
||||
//---------------------
|
||||
function KillShell: LongInt; virtual; abstract;
|
||||
//---------------------}
|
||||
property ShellPid: THandle read FChildPid;
|
||||
property PtyPid: LongInt read Fpty;
|
||||
end;
|
||||
|
||||
{ TConsoleThread }
|
||||
|
||||
TConsoleThread = class(TThread)
|
||||
protected
|
||||
FLock: System.TRTLCriticalSection;
|
||||
FTerm: TTerminal;
|
||||
FRowsCount,
|
||||
FColsCount: Integer;
|
||||
FOut: TCmdBox;
|
||||
FShell: String;
|
||||
public
|
||||
property Terminal: TTerminal read FTerm;
|
||||
property RowsCount: integer read FRowsCount write FRowsCount;
|
||||
property ColsCount: integer read FColsCount write FColsCount;
|
||||
property CmdBox: TCmdBox read FOut write FOut;
|
||||
property Shell: String read FShell write FShell;
|
||||
end;
|
||||
|
||||
function CreateConsoleThread: TConsoleThread;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
{$IF DEFINED(WINDOWS)}
|
||||
uWinTerm;
|
||||
{$ELSEIF DEFINED(UNIX)}
|
||||
uTerm;
|
||||
{$ENDIF}
|
||||
|
||||
function CreateConsoleThread: TConsoleThread;
|
||||
{$IF DEFINED(WINDOWS)}
|
||||
begin
|
||||
Result:= TWinConThread.Create;
|
||||
end;
|
||||
{$ELSEIF DEFINED(UNIX)}
|
||||
begin
|
||||
Result:= TConThread.Create;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
end.
|
||||
|
||||
255
src/platform/win/uwinterm.pas
Normal file
255
src/platform/win/uwinterm.pas
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
unit uWinTerm;
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Classes, SysUtils, Windows, uTerminal;
|
||||
|
||||
type
|
||||
|
||||
{ TWinTerm }
|
||||
|
||||
TWinTerm = class(TTerminal)
|
||||
private
|
||||
FSecurityAttributes: TSecurityAttributes;
|
||||
FStartupInfo: TStartupInfo;
|
||||
FProcessInformation: TProcessInformation;
|
||||
PipeStdInRead,
|
||||
PipeStdInWrite,
|
||||
PipeStdOutRead,
|
||||
PipeStdOutWrite: THandle;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
//---------------------
|
||||
function Read_Pty(var Output: UTF8String; const TimeOut: LongInt = 10): LongInt; override; // Read info from pty
|
||||
function Fork_pty(const RowCount, ColCount: Integer; const Command: UTF8String; const Params: UTF8String=''): THandle; override;//Create new pty and start cmd
|
||||
function Write_pty(const Input: UTF8String): Boolean; override; //write str to pty
|
||||
//---------------------
|
||||
function SendBreak_pty(): Boolean; override; // ^C
|
||||
function SendSignal_pty(Sig: Cint): Boolean; override;
|
||||
function SetScreenSize(ColCount, RowCount: Integer): Boolean; override;
|
||||
//---------------------
|
||||
function KillShell: LongInt;
|
||||
end;
|
||||
|
||||
{ TWinConThread }
|
||||
|
||||
TWinConThread = class(TConsoleThread)
|
||||
private
|
||||
FBuffer: UTF8String;
|
||||
procedure AddSymbol;
|
||||
protected
|
||||
procedure Execute; override;
|
||||
public
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
FileUtil, uOSUtils;
|
||||
|
||||
function ConsoleToUTF8(const Str: AnsiString): UTF8String;
|
||||
{$ifdef MSWindows}
|
||||
var
|
||||
Dst: PChar;
|
||||
{$endif}
|
||||
begin
|
||||
Result:= Str;
|
||||
{$ifdef MSWindows}
|
||||
Dst:= AllocMem((Length(Result) + 1) * SizeOf(Char));
|
||||
if OEMToChar(PChar(Result), Dst) then
|
||||
Result:= SysToUTF8(Dst);
|
||||
FreeMem(Dst);
|
||||
{$endif}
|
||||
end;
|
||||
|
||||
{ TWinTerm }
|
||||
|
||||
constructor TWinTerm.Create;
|
||||
begin
|
||||
|
||||
end;
|
||||
|
||||
destructor TWinTerm.Destroy;
|
||||
begin
|
||||
KillShell;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
function TWinTerm.Read_Pty(var Output: UTF8String; const timeout: LongInt): LongInt;
|
||||
var
|
||||
I: Integer;
|
||||
dwRead, BufSize, DesBufSize: DWORD;
|
||||
Res: Boolean;
|
||||
pcOutput: PChar;
|
||||
begin
|
||||
try
|
||||
BufSize:= 0;
|
||||
dwRead:= 0;
|
||||
Output:= EmptyStr;
|
||||
repeat
|
||||
for I:= 0 to 9 do
|
||||
begin
|
||||
Res:= PeekNamedPipe(PipeStdOutRead, nil, 0, nil, @DesBufSize, nil);
|
||||
Res:= Res and (DesBufSize > 0);
|
||||
if Res then Break;
|
||||
Sleep(TimeOut);
|
||||
end;
|
||||
if Res then
|
||||
begin
|
||||
if DesBufSize > BufSize then
|
||||
begin
|
||||
GetMem(pcOutput, DesBufSize);
|
||||
BufSize:= DesBufSize;
|
||||
end;
|
||||
Res:= ReadFile(PipeStdOutRead, pcOutput^, BufSize, dwRead, nil);
|
||||
end;
|
||||
until not Res;
|
||||
except
|
||||
end;
|
||||
if dwRead > 0 then
|
||||
begin
|
||||
Output:= ConsoleToUTF8(pcOutput);
|
||||
FreeMem(pcOutput);
|
||||
end;
|
||||
Result:= dwRead;
|
||||
end;
|
||||
|
||||
function TWinTerm.Fork_pty(const rows, cols: Integer; const cmd: UTF8String;
|
||||
const params: UTF8string): THandle;
|
||||
var
|
||||
hTmp1, hTmp2: THandle;
|
||||
begin
|
||||
ZeroMemory(@FSecurityAttributes, SizeOf(FSecurityAttributes));
|
||||
FSecurityAttributes.nLength:= SizeOf(FSecurityAttributes);
|
||||
FSecurityAttributes.bInheritHandle:= True;
|
||||
FSecurityAttributes.lpSecurityDescriptor:= nil;
|
||||
|
||||
// create input/output pipes
|
||||
CreatePipe(PipeStdInRead, PipeStdInWrite, @FSecurityAttributes, 0);
|
||||
CreatePipe(PipeStdOutRead, PipeStdOutWrite, @FSecurityAttributes, 0);
|
||||
|
||||
DuplicateHandle(GetCurrentProcess(), PipeStdInWrite, GetCurrentProcess(), @hTmp1, 0, False, DUPLICATE_SAME_ACCESS);
|
||||
DuplicateHandle(GetCurrentProcess(), PipeStdOutRead, GetCurrentProcess(), @hTmp2, 0, False, DUPLICATE_SAME_ACCESS);
|
||||
|
||||
CloseHandle(PipeStdInWrite);
|
||||
CloseHandle(PipeStdOutRead);
|
||||
|
||||
PipeStdInWrite:= hTmp1;
|
||||
PipeStdOutRead:= hTmp2;
|
||||
|
||||
ZeroMemory(@FStartupInfo, SizeOf(FStartupInfo));
|
||||
FStartupInfo.cb:= SizeOf(FStartupInfo);
|
||||
with FStartupInfo do
|
||||
begin
|
||||
dwFlags:= STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
|
||||
wShowWindow:= SW_HIDE;
|
||||
hStdInput:= PipeStdInRead;
|
||||
hStdOutput:= PipeStdOutWrite;
|
||||
end;
|
||||
|
||||
ZeroMemory(@FProcessInformation, SizeOf(FProcessInformation));
|
||||
|
||||
CreateProcessW(nil,
|
||||
PWideChar(UTF8Decode(cmd)), // command line
|
||||
nil, // process security attributes
|
||||
nil, // primary thread security attributes
|
||||
TRUE, // handles are inherited
|
||||
0, // creation flags
|
||||
nil, // use parent's environment
|
||||
nil, // use parent's current directory
|
||||
FStartupInfo, // STARTUPINFO pointer
|
||||
FProcessInformation); // receives PROCESS_INFORMATION
|
||||
|
||||
Result:= FProcessInformation.hProcess;
|
||||
end;
|
||||
|
||||
function TWinTerm.Write_pty(const Input: UTF8String): Boolean;
|
||||
var
|
||||
dwWritten, BufSize: DWORD;
|
||||
pcCommand: PChar;
|
||||
begin
|
||||
pcCommand:= PChar(UTF8ToConsole(Input));
|
||||
BufSize:= Length(pcCommand);
|
||||
Result:= WriteFile(PipeStdInWrite, pcCommand^, BufSize, dwWritten, nil);
|
||||
Result:= Result and (BufSize = dwWritten);
|
||||
end;
|
||||
|
||||
function TWinTerm.SendBreak_pty(): Boolean;
|
||||
begin
|
||||
Result:= False;
|
||||
end;
|
||||
|
||||
function TWinTerm.SendSignal_pty(Sig: Cint): Boolean;
|
||||
begin
|
||||
Result:= False;
|
||||
end;
|
||||
|
||||
function TWinTerm.SetScreenSize(aCols, aRows: Integer): Boolean;
|
||||
begin
|
||||
Result:= False;
|
||||
end;
|
||||
|
||||
function TWinTerm.KillShell: LongInt;
|
||||
begin
|
||||
try
|
||||
CloseHandle(PipeStdInRead);
|
||||
CloseHandle(PipeStdInWrite);
|
||||
CloseHandle(PipeStdOutRead);
|
||||
CloseHandle(PipeStdOutWrite);
|
||||
CloseHandle(FProcessInformation.hThread);
|
||||
CloseHandle(FProcessInformation.hProcess);
|
||||
except
|
||||
end;
|
||||
end;
|
||||
|
||||
{ TWinConThread }
|
||||
|
||||
procedure TWinConThread.AddSymbol;
|
||||
begin
|
||||
if Assigned(FOut) then
|
||||
FOut.Write(FBuffer);
|
||||
end;
|
||||
|
||||
procedure TWinConThread.Execute;
|
||||
begin
|
||||
FShell:= GetShell;
|
||||
if Length(FShell) = 0 then
|
||||
FShell:= RunTerm;
|
||||
if Assigned(FTerm) then
|
||||
FTerm.Fork_pty(FRowsCount, FColsCount, FShell);
|
||||
while True do
|
||||
begin
|
||||
if Assigned(FTerm) then
|
||||
begin
|
||||
if FTerm.Read_pty(FBuffer, 0) > 0 then
|
||||
Synchronize(@AddSymbol)
|
||||
else
|
||||
Sleep(1);
|
||||
end else Break;
|
||||
end;
|
||||
end;
|
||||
|
||||
constructor TWinConThread.Create;
|
||||
begin
|
||||
inherited Create(True);
|
||||
System.InitCriticalSection(FLock);
|
||||
FTerm:= TWinTerm.Create;
|
||||
FRowsCount:= 50;
|
||||
FColsCount:= 100;
|
||||
end;
|
||||
|
||||
destructor TWinConThread.Destroy;
|
||||
begin
|
||||
FreeAndNil(FTerm);
|
||||
System.DoneCriticalSection(FLock);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue