OneKey3.exe for Bricscad V17~V19 Ver.1.24b 2018/12/02~12
OneKey.exe は、BcadMoseMove に移行しました。
・ 2018/12/12 一時Oスナップに「図心 gce」。(OneKey3 Ver.1.24b)
・ 2018/12/08 エラー回避に Bricscad のイベント通知を追加。(OneKey3 Ver.1.24a)
■OneKey2.exe との違い
・OneKey2 の対象は、複数起動された Bricscad のうちアクティブな Bricscad でしたが、最初に見つかった 1つの Bricscad
のみにしました。
・OneKey2 では、LISP の読み込みメッセージ等でエラーになることがありましたが、図面 OPEN 中の 0.7 秒程度は何もしないことで、これを回避しました。
■概要
3つの機能があります。
・IME 自動オフ (IME Off)
・マウス移動による [Enter] 発行 (OneKey)
・座標入力時、[Ctrl] キーによるスナップモード切替(Ver.1.21)
■スクリーンショット

■IME Off
コマンドラインの文字列が ": " だけの時、IME をオフにします。
※不要の場合は、「IME Off:Auto」のチェックを外してください。
■OneKey
※不要の場合は、「OneKey : Auto」のチェックを外してください。
・コマンド入力中:
マウス右上方向で [Enter] キーを発行します。
例えば、コマンドラインに "z" を入力しマウスを右上に移動すると、ZOOM コマンドが実行されます。
自動入力候補(コートコンプリート)を使うため、マウス右上以外は無効としています。
文字数の制限はありません。
・コマンドオプション入力中:
"["、"]" の文字列がある、または "点"、"ポイント"、"コーナ"、"中心"の文字列があり、"@"、数字入力でない時のみ、マウス方向制限なしで
[Enter] キーを発行します。
また、下記の文字(大/小文字区別なし)の場合は、一時Oスナップに書き換えます。
M, MI, MD, MM : mid (中点)
C, CE, CN, CC : cen (中心)
Q, QU, QA, QQ : qua (四半円点)
I, IT, II : int (交点)
E, EN, ED, EE : end(端点)
T, TA, TN, TT : tan (接線)
N, NE, NA : nea (近接点)
P, PE, PR, PP : per (垂線)
S, IN, IS : ins (挿入基点)
O, D, ND : nod (点)
NN, NO : non (解除)
V, M2, MT, MP, MMM : m2p (2点間中点)
EX, ET : ext (延長)
F, FR, FM : from (基点設定)
A, AP : app (仮想交点)
PA : par (平行)
X, XX : [ESC]キー
G, GC :gce (図心) (1.24bより)
※コマンドオプションが優先されます。
■[Ctrl]キーによるスナップモード変更
座標入力中に [Ctrl]キーを押すと、スナップモードが反転します。
■起動と終了
起動すると、スクリーンの右下にフォームが表示されます。
Bricscad の サポートフォルダに、on_start.lsp をメモ帳などで作成(すでにある場合は、下記一行を追加)すると、自動で起動されます。
(startapp "C:\\xxxx\\yyyy\\OneKey3.exe")
フォルダ(パス)の区切り \\ は¥¥です。
Bricscad が終了すると、追従して終了します。
■マウス移動量の変更
OneKey3.exe が起動していない時に、OneKey3.exe と同じフォルダの OneKey3.ini をメモ帳などで編集してください。
MouseMove=20 ←この数値を変更
■以前 (AutoCAD 用) のバージョンとの違い
・マウス移動で、コマンド発行。名前のとおり OneKey でコマンドオプションを発行するツールでしたが、かなりクセがあり動きが分かりにくいため、
ほぼマウス移動で [Enter] キーを発行する単純なものに変更しました。
・コマンドラインオプションのリスト表示の機能は、CAD 本体に実装されたため削除しました。
・[Shift] キーによる直交モード反転は、CAD 本体に実装されたため削除しました。
・[Ctrl] キーによるスナップモード反転は、削除しました。
・「アイコントレイに格納」は取りやめました。
・IME の強制オフ(IME Off) を統合しました。
■著作権、免責事項等
・本ツールの著作権は、作者 f.izawa が所有し、これを主張します。
・本ツールを使用したことによる事故、損害等の一切について作者はその責を負いません。
■開発環境
・Delphi 10.2.3 Tokyo Community Edition
・Bricscad V17 Pro, V19 Pro
・Windows 10 64bit
■作者連絡先
e-mail: f.izawa@dream.com
URL: http://www.izawa-web.com/
■ダウンロード
・OneKey3.zip (Ver.1.24b EXE 本体 + ReadMe)
OneKey2、Onekey3 共、動作不安定のため、ダウンロードは中止にしました。
■Delphi ソースコード (Ver.1.24a)
※キーフックのコードは、Mr.XRAY 氏のサンプルコードを使用しています。
※ BcadCtrl19.pas は不要になりました。
※ BricscadApp_TLB, BricscadDb_TLB は、[コンポーネント] - [コンポーネントのインポート...] -「タイプライブラリの取り込み」で作成します。
// 2018/12/09
unit OneKey3Unit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, ShellAPI, Vcl.ExtCtrls,
Vcl.StdCtrls, IMM, System.UITypes, IniFiles, Menus,
ComObj, ActiveX, BricscadApp_TLB, BricscadDb_TLB;
Type
// パラメータ付きのイベントをタイプ別に用意
TParamWideStringEvent = procedure(ASender: TObject; const Param: WideString) of object;
TParamVarWordBoolEvent = procedure(ASender: TObject; var Param: WordBool) of object;
type
TAcadApplicationEventsSink = class(TInterfacedObject, IUnknown, IDispatch)
private
FOwner : TObject;
FOnNewDrawing : TNotifyEvent;
FOnBeginOpen : TParamWideStringEvent;
FOnEndOpen : TParamWideStringEvent;
FOnUnknownEvent : TNotifyEvent;
FOnBeginQuit : TParamVarWordBoolEvent;
protected
{
イベントシンククラスのインスタンスが用意できたら,このイベントシンクの存在を
サーバーに知らせます。
これで,サーバーはイベントシンクを呼び出せるようになります。
サーバーにイベントシンクの存在を知らせるには,グローバル手続き InterfaceConnect
を呼び出し,以下を渡します。
・イベントを生成するサーバーとのインターフェース
・イベントシンクが処理するイベントインターフェースの GUID
・イベントシンクの IUnknown インターフェース
・サーバーとイベントシンクの接続を表す Longint 値を受け取る変数
}
{ IUnknown }
function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
{ IDispatch }
function GetTypeInfoCount(out Count: Integer): HRESULT; virtual; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HRESULT; virtual; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HRESULT; virtual; stdcall;
function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HRESULT; virtual; stdcall;
public
constructor Create(Owner:TObject);
property OnNewDrawing : TNotifyEvent read FOnNewDrawing write FOnNewDrawing;
property OnBeginOpen : TParamWideStringEvent read FOnBeginOpen write FOnBeginOpen;
property OnEndOpen : TParamWideStringEvent read FOnEndOpen write FOnEndOpen;
property OnBeginQuit : TParamVarWordBoolEvent read FOnBeginQuit write FOnBeginQuit;
property OnUnknownEvent : TNotifyEvent read FOnUnknownEvent write FOnUnknownEvent;
end;
type
TOneKeyForm = class(TForm)
Timer1: TTimer;
CheckBox1: TCheckBox;
Shape1: TShape;
Label1: TLabel;
CheckBox2: TCheckBox;
Timer2: TTimer;
procedure FormCreate(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormDestroy(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
private
{ Private 宣言 }
FAcadApplication : IAcadApplication;
EventChanel : TAcadApplicationEventsSink;
CPC: IConnectionPointContainer;
CP : IConnectionPoint;
cookie : Integer;
procedure BcadBeginOpen(Sender: TObject;const FileName: WideString);
procedure BcadEndOpen(Sender: TObject;const FileName: WideString);
procedure BcadNewDrawing(Sender: TObject);
procedure BcadBeginQuit(Sender: TObject; var Cancel: WordBool);
public
{ Public 宣言 }
protected
procedure WMApp110(var Message: TMessage); message WM_APP + 110;
end;
type
LPKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT;
tagKBDLLHOOKSTRUCT = record
vkCode : DWORD;
scanCode : DWORD;
flags : DWORD;
time : DWORD;
dwExtraInfo : ULONG_PTR;
end;
KBDLLHOOKSTRUCT = tagKBDLLHOOKSTRUCT;
PKbDllHookStruct = LPKBDLLHOOKSTRUCT;
var
OneKeyForm: TOneKeyForm;
KeyHookHandle : HHOOK;
TargetWnd : HWND;
BcadHwnd : HWND;
BcadCmdHwnd: HWND;
cmdstr : string;
cmdopt : string;
TmCnt : integer;
TmFlag : boolean;
bcadCaption, oldCaption : string;
// マウス座標を保持
mousex, mousey : integer;
// マウス移動判断の閾値
mousexy : integer;
// 前回のコマンドライン文字列
cmdold : string;
// Bcad が起動中ON
bcadflag : boolean;
tmbusy : boolean;
pt : TPoint;
OneKeySleep : boolean;
function makeCmdOptionList(const cmds: string): string;
implementation
{$R *.dfm}
//-----------------------------------------------------------------------------
// キーフックのコールバック関数
//-----------------------------------------------------------------------------
function LowLevelKeyProc(Code: Integer; wPar: WPARAM; lPar: LPARAM): LRESULT; stdcall;
var
Lkbdll : PKBDLLHOOKSTRUCT;
begin
if Code < 0 then begin
Result := CallNextHookEx(KeyHookHandle, Code, wPar, lPar);
exit;
end;
Lkbdll := PKBDLLHOOKSTRUCT(lPar);
if Code = HC_ACTION then begin
if wPar = WM_KEYDOWN then begin
PostMessage(OneKeyForm.Handle, WM_APP + 110, wPar, Lkbdll.vkCode);
end
else if wPar = WM_KEYUP then begin
PostMessage(OneKeyForm.Handle, WM_APP + 110, wPar, Lkbdll.vkCode);
end
end;
Result := CallNextHookEx(KeyHookHandle, Code, wPar, lPar);
end;
procedure BcadSendKeys(const keystr: string);
{ Bricscad をアクティブにして、Keyを押す}
var
i : integer;
s: string;
begin
SetForegroundWindow(BcadHwnd);
s := UpperCase(keystr);
for i := 1 to Length(s) do begin
keybd_event(Byte(s[i]), 0, 0, 0);
keybd_event(Byte(s[i]), 0, KEYEVENTF_KEYUP, 0);
Sleep(1);
end;
end;
//-----------------------------------------------------------------------------
// フックしたキーボード情報を受取る
// KEYDOWNで送られてくる
//-----------------------------------------------------------------------------
procedure TOneKeyForm.WMApp110(var Message: TMessage);
var
LKey : WORD;
LMsgKind : WORD;
LhTarget : HWND;
LMsgStr : String;
begin
LKey := Message.LParam;
LMsgKind := Message.WParam;
if LMsgKind = $100 then LMsgStr := 'KeyDown'
else if LMsgKind = $101 then LMsgStr := 'KeyUp'
else LMsgStr := 'Key???';
//最前面のウィンドウのハンドルがTargetWndと同じだったら処理
//この条件を削除すれば,全てのウィンドウでのキー操作を検出することになる
LhTarget := GetForegroundWindow;
if (LhTarget = TargetWnd) and IsWindowEnabled(LhTarget) then begin
if ShortCutToText(LKey) = 'Ctrl' then begin
if (cmdstr = '') or
((cmdstr <> '') and ((Pos('点', cmdstr) > 0) or (Pos('ポイント', cmdstr) > 0) or
(cmdstr.IndexOf('コーナ') >= 0) or (cmdstr.IndexOf('中心') >= 0))) then begin
keybd_event(VK_F9, 0, 0, 0);
keybd_event(VK_F9, 0, KEYEVENTF_KEYUP, 0);
Sleep(1);
end;
end;
end;
end;
// -----------------------------------------------------------------------------
{ TAcadApplicationEvents }
// -----------------------------------------------------------------------------
function TAcadApplicationEventsSink.GetTypeInfo(Index, LocaleID: Integer;
out TypeInfo): HResult;
begin
Result := E_NOTIMPL;
end;
function TAcadApplicationEventsSink.QueryInterface(const IID: TGUID;
out Obj): HResult;
begin
Result := E_NOINTERFACE;
Pointer(Obj) := nil;
if GetInterface(IID, Obj) then Result := S_OK;
if IsEqualGUID(IID,_DAcadApplicationEvents) and GetInterface(IDispatch,Obj) then
Result := S_OK;
end;
function TAcadApplicationEventsSink.GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
begin
Result := E_NOTIMPL;
end;
function TAcadApplicationEventsSink._AddRef: Integer;
begin
Result := 2;
end;
function TAcadApplicationEventsSink.GetTypeInfoCount(out Count: Integer): HRESULT;
begin
Count := 0;
Result := S_OK;
end;
function TAcadApplicationEventsSink.Invoke(DispID: Integer; const IID: TGUID;
LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo,
ArgErr: Pointer): HResult;
var
FParamWideString : Widestring;
FData : TVariantArg;
FParamWordBool : WordBool;
begin
Case DispID of
2 : if Assigned(FOnNewDrawing) then FOnNewDrawing(FOwner);
8 : if Assigned(FOnBeginQuit) then begin
if TDispParams(Params).cArgs = 1 then begin
FParamWordBool :=false;
FData := PVariantArgList(TDispParams(Params).rgvarg)^[0];
if FData.vt = VT_BOOL then FParamWordBool := FData.vbool;
FOnBeginQuit(FOwner, FParamWordBool);
end;
end;
21 : if Assigned(FOnBeginOpen) then begin
if TDispParams(Params).cArgs = 1 then begin
FData := PVariantArgList(TDispParams(Params).rgvarg)^[0];
if FData.vt = VT_BSTR then FParamWideString := FData.bstrVal;
FOnBeginOpen(FOwner, FParamWideString);
end;
end;
22 : if Assigned(FOnEndOpen) then begin
if TDispParams(Params).cArgs = 1 then begin
FData := PVariantArgList(TDispParams(Params).rgvarg)^[0];
if FData.vt = VT_BSTR then FParamWideString := FData.bstrVal;
FOnEndOpen(FOwner, FParamWideString);
end;
end;
else if Assigned(FOnUnknownEvent) then FOnUnknownEvent(FOwner);
end;
Result := S_OK;
end;
function TAcadApplicationEventsSink._Release: Integer;
begin
Result := 1;
end;
constructor TAcadApplicationEventsSink.Create(Owner:TObject);
begin
inherited Create;
FOwner := Owner;
end;
// -----------------------------------------------------------------------------
// BricsCAD が起動されているか
function IsBcadActive:boolean;
const
BcadClassName = 'BricscadApp.AcadApplication';
var
ClassID : TGUID;
UnKnown : IUnknown;
begin
ClassID := ProgIDtoClassID(BcadClassName);
result := Succeeded(GetActiveObject(ClassID, nil, Unknown));
end;
//******************************************
// 他のプロセス内のコントロールの文字列を得る
//******************************************
function GetWindowString(h: HWND): string;
var
p : PChar;
len : LongInt;
begin
result := '';
//ウィンドウの文字列のバイト数を取得
//終端のNULL文字を含まない文字列の長さ(バイト数)
len := SendMessage(h, WM_GETTEXTLENGTH, 0, 0);
if len > 0 then begin
//終端のNULL文字を含むサイズを確保
GetMem(p, (len + 1) * 2);
//格納するバッファの最大サイズ(終端のNULL文字を含む長さ)
//文字列バッファ
SendMessage(h, WM_GETTEXT, (len + 1) * 2, LongInt(p));
//文字列がバッファサイズより長いとき、後部がカットされる
result := string(p);
FreeMem(p);
end;
end;
function GetBcadHwndCmdLineHandle(hMain: HWND): HWND;
var
h, h2 : HWND;
hCmdBar : HWND;
hCmdLine : HWND;
i : integer;
ClassName : array [0..254] of char;
PID, MainPID : DWORD;
begin
FillChar(ClassName[0], 255, #0);
GetWindowThreadProcessId(hMain, @MainPID);
hCmdBar := FindWindowEx(hMain, 0, nil, 'コマンドライン');
h := hCmdBar;
for i := 1 to 4 do begin
h2 := GetWindow(h, GW_CHILD);
if h2 = 0 then break
else h := h2;
end;
hCmdLine := GetWindow(h, GW_HWNDNEXT);
GetClassName(hCmdLine, ClassName, 255);
if string(ClassName) <> 'RICHEDIT50W' then hCmdLine := 0;
if hCmdLine = 0 then begin
hCmdBar := FindWindow(nil, 'コマンドライン');
GetWindowThreadProcessId(hMain, @PID);
if PID = MainPID then begin
h := hCmdBar;
for i := 1 to 5 do begin
h2 := GetWindow(h, GW_CHILD);
if h2 = 0 then break
else h := h2;
end;
hCmdLine := GetWindow(h, GW_HWNDNEXT);
GetClassName(hCmdLine, ClassName, 255);
if string(ClassName) <> 'RICHEDIT50W' then hCmdLine := 0;
end;
end;
result := hCmdLine;
end;
procedure TOneKeyForm.BcadBeginOpen(Sender: TObject; const FileName: WideString);
begin
OneKeySleep := True;
end;
procedure TOneKeyForm.BcadEndOpen(Sender: TObject; const FileName: WideString);
begin
OneKeySleep := True;
end;
procedure TOneKeyForm.BcadNewDrawing(Sender: TObject);
begin
OneKeySleep := True;
end;
procedure TOneKeyForm.BcadBeginQuit(Sender: TObject; var Cancel: WordBool);
begin
end;
procedure TOneKeyForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
ini : TIniFile;
begin
Timer1.Enabled := False;
try
ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
try
ini.WriteInteger('OneKey', 'MouseMove', mousexy);
ini.WriteBool('OneKey','ImeOff', CheckBox1.Checked);
ini.WriteBool('OneKey','OneKey', CheckBox2.Checked);
finally
ini.Free;
end;
except
;
end;
end;
procedure TOneKeyForm.FormCreate(Sender: TObject);
var
ini : TIniFile;
begin
Label1.Caption := '';
oldCaption := '';
// マウス移動判断の閾値の初期値
mousexy := 20;
mousex := 0;
mousey := 0;
// スクリーンの右下隅に表示
Left := Screen.Width - Width - 10;
Top := Screen.Height - Height - 130;
ini := TIniFile.Create(ChangeFileExt(ParamStr(0), '.ini'));
try
mousexy := ini.ReadInteger('OneKey','MouseMove', mousexy);
CheckBox1.Checked := ini.ReadBool('OneKey','ImeOff', True);
CheckBox2.Checked := ini.ReadBool('OneKey','OneKey', True);
finally
ini.Free;
end;
if KeyHookHandle = 0 then
KeyHookHandle := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyProc, hInstance, 0);
end;
procedure TOneKeyForm.FormDestroy(Sender: TObject);
begin
try
if KeyHookHandle <> 0 then UnhookWindowsHookEx(KeyHookHandle);
if Assigned(EventChanel) then FreeAndNil(EventChanel);
except
;
end;
end;
procedure TOneKeyForm.FormShow(Sender: TObject);
begin
Timer1.Enabled := True;
end;
function makeObjectSnapStr(const cmdo: string; const optstr: string): string;
begin
result := '';
// オプションリストに存在
if cmdo.IndexOf(',' + optstr + ',') < 0 then begin
// 一時オブジェクトスナップ
// 中点:MID
if optstr = 'M' then result := 'id' + #13
else if optstr = 'MI' then result := 'd' + #13
else if optstr = 'MD' then result := #08 + 'id' + #13
else if optstr = 'MM' then result := #08 + 'id' + #13
// 中心:CEN
else if optstr = 'C' then result := 'en' + #13
else if optstr = 'CE' then result := 'n' + #13
else if optstr = 'CN' then result := #08+'en' + #13
else if optstr = 'CC' then result := #08+'en' + #13
// 四半円点:QUA
else if optstr = 'Q' then result := 'ua' + #13
else if optstr = 'QU' then result := 'a' + #13
else if optstr = 'QA' then result := #08 + 'ua' + #13
else if optstr = 'QQ' then result := #08 + 'ua' + #13
// 端点:END
else if optstr = 'E' then result := 'nd' + #13
else if optstr = 'EN' then result := 'd' + #13
else if optstr = 'ED' then result := #08 + 'nd' + #13
else if optstr = 'EE' then result := #08 + 'nd' + #13
// 交点:INT
else if optstr = 'I' then result := 'nt' + #13
else if optstr = 'IT' then result := #08 + 'nt' + #13
else if optstr = 'II' then result := #08 + 'nt' + #13
// 接線:TAN
else if optstr = 'T' then result := 'an' + #13
else if optstr = 'TA' then result := 'n' + #13
else if optstr = 'TN' then result := #08 + 'an' + #13
else if optstr = 'TT' then result := #08 + 'an' + #13
// 近接点:NEA
else if optstr = 'N' then result := 'ea' + #13
else if optstr = 'NE' then result := 'a' + #13
else if optstr = 'NA' then result := #08 + 'ea' + #13
// 垂線:PER
else if optstr = 'P' then result := 'er' + #13
else if optstr = 'PE' then result := 'r' + #13
else if optstr = 'PR' then result := #08 + 'er' + #13
else if optstr = 'PP' then result := #08 + 'er' + #13
// 挿入基点:INS
else if optstr = 'S' then result := #08 + 'ins' + #13
else if optstr = 'IS' then result := #08 + 'ns' + #13
else if optstr = 'IN' then result := 's' + #13
// 点:NOD
else if optstr = 'D' then result := #08 + 'nod' + #13
else if optstr = 'O' then result := #08 + 'nod' + #13
else if optstr = 'ND' then result := #08 + 'od' + #13
// 解除:NON
else if optstr = 'NN' then result := #08 + 'on' + #13
else if optstr = 'NO' then result := 'n' + #13
// 2点間中点:M2P
else if optstr = 'V' then result := #08 + 'm2p' + #13
else if optstr = 'MT' then result := #08 + 'tp' + #13
else if optstr = 'M2' then result := #08 + '2p' + #13
else if optstr = 'MP' then result := #08 + '2p' + #13
else if optstr = 'MMM' then result := #08#08 + '2p' + #13
// 延長:EXT
//else if optstr = 'E' then result := 'xt' + #13
else if optstr = 'EX' then result := 't' + #13
else if optstr = 'ET' then result := #08 + 'xt' + #13
// 基点設定:FROM
else if optstr = 'F' then result := 'rom' + #13
else if optstr = 'FR' then result := 'om' + #13
else if optstr = 'FM' then result := #08 + 'rom' + #13
// 仮想交点:APP
else if optstr = 'A' then result := 'pp' + #13
else if optstr = 'AP' then result := 'p' + #13
// 平行:PAR
else if optstr = 'PA' then result := 'r' + #13
//else if optstr = 'PR' then result := #08 + 'ar' + #13
// [ESC]
else if optstr = 'X' then result := #27
else if optstr = 'XX' then result := #27;
end;
end;
function makeCmdOptionList(const cmds: string): string;
var
n, m : integer;
s, s2 : string;
begin
result := '';
s := cmds;
if (s.IndexOf('(') > 0) and (s.IndexOf(')') > 0) then begin
m := Pos('[', s);
n := Pos(']', s);
if (m > 0) and (n > m) then s := Copy(s, m + 1, n-m-1);
if s <> '' then begin
while True do begin
m := Pos('(', s);
n := Pos(')', s);
if (m > 0) and (n > m) then begin
s2 := Copy(s, m + 1, n - m -1);
if (s2.Length > 0) and (s2.Length <= 5) then result := result + s2 + ',';
Delete(s, 1, n);
end
else break;
end;
end;
end
else if (s.IndexOf('選択:') > 0) then begin
result := 'W,L,C,BOX,ALL,F,WP,CP,G,CL,A,R,M,P,U,AU,SI,';
end;
// OPT は、','で囲まれている状態にする
if result <> '' then result := ',' + result;
end;
procedure TOneKeyForm.Timer1Timer(Sender: TObject);
var
optstr : string; // コマンドオプション
s : string;
entflag, posflag : boolean;
IME: HWND; // uses Imm
n : integer;
curFlag : boolean;
begin
try
//curFlag := False;
// 初回起動時は1.5秒程度何もしない
if not TmFlag then Inc(TmCnt);
if TmCnt >= 15 then TmFlag := True;
if TmFlag and not tmbusy then begin
tmbusy := True;
// [Enter]キー発行
entflag := False;
// コマンドライン取得
BcadCmdHwnd := GetBcadHwndCmdLineHandle(BcadHwnd);
if IsWindowEnabled(BcadCmdHwnd) then
cmdstr := GetWindowString(BcadCmdHwnd)
else
cmdstr := '';
if OneKeySleep then begin
oldCaption := bcadCaption;
TmFlag := False;
// 0.7 秒程度何もしない
TmCnt := 8;
tmbusy := False;
if Shape1.Brush.Color <> clRed then begin
Shape1.Brush.Color := clRed;
Shape1.Pen.Color := clRed;
end;
OneKeySleep := False;
end
else begin
// キーフックの対象を更新
TargetWnd := BcadHwnd;
if (': ' <> cmdstr) then begin
if Shape1.Brush.Color <> clWhite then begin
Shape1.Brush.Color := clWhite;
Shape1.Pen.Color := clWhite;
end;
end;
if IsWindowEnabled(BcadHwnd) and IsWindowEnabled(BcadCmdHwnd) then begin
posflag := True; // 基準点を更新
// マウス座標取得
curFlag := GetCursorPos(pt) ;
//curFlag := True;
//pt := Mouse.CursorPos;
if curFlag and (GetForegroundWindow = BcadHwnd) then begin
s := IntToStr(pt.X - mousex) + ', ' + IntToStr(mousey - pt.Y);
Label1.Caption := s;
end
else begin
if Label1.Caption <> '' then Label1.Caption := '';
if Shape1.Brush.Color <> clYellow then begin
Shape1.Brush.Color := clYellow;
Shape1.Pen.Color := clYellow;
end;
end;
// コマンドオプションを取得
cmdopt := makeCmdOptionList(cmdstr);
// コマンド入力待ち
if (': ' = cmdstr) then begin
// IME Off
if CheckBox1.Checked then begin
if Shape1.Brush.Color <> clLime then begin
Shape1.Brush.Color := clLime;
Shape1.Pen.Color := clLime;
end;
IME := ImmGetDefaultIMEWnd(BcadCmdHwnd);
// ON であれば OFF にする
if Boolean(SendMessage(IME, WM_IME_CONTROL, $0005, 0)) then
SendMessage(IME, WM_IME_CONTROL, $0006, 0);
end;
end
// コマンド入力中
else if (cmdstr.IndexOf(':') = 0) then begin // 先頭の文字が':'
// オプション入力待ち
if cmdstr.Length > 2 then begin // ': '=2文字
// 方向は右上のみ(オートコンプリート対策)
if curFlag and ((pt.X - mousex) > mousexy) and ((mousey - pt.Y) > mousexy) then
entflag := True;
end;
end
else begin
// オプション文字列 ':'以降
n := LastDelimiter(':', cmdstr);
if n > 0 then optstr := Trim(Copy(cmdstr, n + 1))
else optstr := '';
if optstr <> '' then begin
optstr := UpperCase(optstr);
// オプション文字あり
if ((cmdstr.IndexOf('[') > 0) and (cmdstr.IndexOf(']') > 0)) or
(cmdstr.IndexOf('点') >= 0) or (cmdstr.IndexOf('回転') >= 0) or
(cmdstr.IndexOf('コーナ') >= 0) or (cmdstr.IndexOf('ポイント') >= 0) then begin
// 方向制限なし
if curFlag and ((abs(pt.X - mousex) > mousexy) or (abs(mousey - pt.Y) > mousexy)) then begin
s := Copy(optstr, 1, 1);
// 数値入力以外 (念のため) '-'~'9'
if not ((s = '@') or ((s >= '-') and (s <= '9'))) then begin
// 一時オブジェクトスナップ
s := makeObjectSnapStr(cmdopt, optstr);
if s <> '' then begin
if CheckBox2.Checked then begin
Timer1.Enabled := False;
BcadSendKeys(s);
Sleep(100);
Timer1.Enabled := True;
end;
end
else
entflag := True;
end;
end;
end;
end;
end;
if curFlag and (posflag or entflag) then begin
// 基準点を更新
mousex := pt.X;
mousey := pt.Y;
end;
if CheckBox2.Checked and entFlag then begin
Timer1.Enabled := False;
// [Enter] 発行
BcadSendKeys(#13);
Sleep(100);
Timer1.Enabled := True;
end;
end;
cmdold := cmdstr;
tmbusy := False;
// 追従して終了
if not bcadflag then begin
if IsWindow(BcadHwnd) then begin
bcadflag := True;
SetForegroundWindow(BcadHwnd);
end;
end
else begin
if not IsWindow(BcadHwnd) then begin
TmFlag := False;
TmCnt :=0;
tmbusy := True;
Timer1.Enabled := False;
Close;
end;
end;
end;
end;
except
on E: Exception do begin
s := E.ClassName + sLineBreak + E.Message;
MessageBox(Handle, PChar(s), '終了します.', MB_ICONINFORMATION);
TmFlag := False;
TmCnt :=0;
tmbusy := True;
Timer1.Enabled := False;
Close;
end;
end;
end;
procedure TOneKeyForm.Timer2Timer(Sender: TObject);
begin
if not IsWindow(BcadHwnd) then begin
if IsBcadActive then begin
// 起動中の Bricscad を取得
FAcadApplication := GetActiveOleObject('BricscadApp.AcadApplication') as IACadApplication;
if Assigned(FAcadApplication) then begin
// ウィンドウハンドルを保持
BcadHwnd := FAcadApplication.HWND_;
// イベントシンク
EventChanel := TAcadApplicationEventsSink.Create(self);
// イベントシンクの存在をBricscad に通知
FAcadApplication.QueryInterface(IConnectionPointContainer, CPC);
CPC.FindConnectionPoint(_DAcadApplicationEvents, CP);
CP.Advise(EventChanel, cookie);
// イベントを登録
EventChanel.OnNewDrawing := BcadNewDrawing;
EventChanel.OnBeginOpen := BcadBeginOpen;
EventChanel.OnEndOpen := BcadEndOpen;
EventChanel.OnBeginQuit := BcadBeginQuit;
Timer2.Enabled := False;
end;
end;
end;
end;
end.