[질문] 코드 문제 .......
(* 해결해 주시는 분께 영어학습 교재 무비잉글리쉬 교재를 드립니다.)
공부하려고 55,000이나 주고 구입 한 것입니다. 영어공부 하는데 많은 도움이 되었습니다. 상태는 A+ 급)
** 목적은 키보드 메크로 프로그램을 만들어 보려는 것입니다.
** 예를 들면, 어떤 키를 누르면, 자신이 저장해 두었던 주소 (서울 강서구 13 office box ..) 라는 글이 저절로 들어가게 하려는 것이지요.
** 이 때 1바이트 코드들은 작동이 잘 되는데, 2바이트 코드들은 잘 안되네요. 윈도우 버젼에 따라서도 문제가 있고요.
/////////////////////////////
폼에 버튼1개, 에디터 박스 2개를 추가하고 아래와 같이 코딩했습니다.
그런데 AB라고 하는 문자는 의도대로 나오는데, '가'라고 하는 문자는 안나옵니다.
분명 유니코드 문제(2바이트 문자) 인것 같은데, 어떻게 하면 2번의 명령으로 '가'라는 문자가 제데로 나오게 할 수 있을까요 ?
edit2.text := s; 라고 하면 당연히 잘 되겠지만, 아래와 같이 2번의 명령라인으로 잘 나오게 하는 방법이 있을 것 같은데,
고수님들와 고견 부탁드립니다.
꾸벅.
그럼.
//////////////
//// 테스트용
///////////////
procedure TForm1.Button1Click(Sender: TObject);
var
s :String;
begin
s := 'AB';
edit1.text := s[1];
edit1.text := edit1.text + s[2];
s := '가';
edit2.text := s[1];
edit2.text := edit2.text + s[2];
end;
================
///////////// 이쪽은 지금 작업 중인 전체 소스입니다 (참고로, 본 소스는 인터넷에서 구했습니다)///////
unit hkSend;
interface
uses
SysUtils,
Messages,
Forms,
Windows,
mmSystem,
Classes;
type
TSendKeyError = (skSuccess, skInvalidToken, skUnknownError);
function SendKeys(S: String): TSendKeyError;
function AllSpecialKeysReleased(ExtraKey: UINT): Boolean;
implementation
type
ESendKeyError = class(Exception);
EInvalidToken = class(ESendKeyError);
TKeyDef = record
Key : String;
Code: UINT;
end;
TMessageList = class(TList)
public
destructor Destroy; override;
end;
const
MaxKeys = 46;
ShiftKey = '+';
ControlKey = '^';
AltKey = '%';
EnterKey = '~';
WindowsKey = '#';
KeyGroupOpen = '{';
KeyGroupClose = '}';
KeyTokens = '{}~%^+#';
KeyDefs : array[1..MaxKeys] of TKeyDef = (
(Key: 'BACKSPACE' ; Code: VK_BACK),
(Key: 'BKSP' ; Code: VK_BACK),
(Key: 'BS' ; Code: VK_BACK),
(Key: 'SPACE' ; Code: VK_SPACE),
(Key: 'CAPS' ; Code: VK_CAPITAL),
(Key: 'CAPSLOCK' ; Code: VK_CAPITAL),
(KEy: 'CLEAR' ; Code: VK_CLEAR),
(Key: 'DEL' ; Code: VK_DELETE),
(Key: 'DELETE' ; Code: VK_DELETE),
(Key: 'DOWN' ; Code: VK_DOWN),
(Key: 'END' ; Code: VK_END),
(Key: 'ENTER' ; Code: VK_RETURN),
(Key: 'ESC' ; Code: VK_ESCAPE),
(Key: 'ESCAPE' ; Code: VK_ESCAPE),
(Key: 'HOME' ; Code: VK_HOME),
(Key: 'INS' ; Code: VK_INSERT),
(Key: 'INSERT' ; Code: VK_INSERT),
(Key: 'LEFT' ; Code: VK_LEFT),
(Key: 'NUM' ; Code: VK_NUMLOCK),
(Key: 'NUMLOCK' ; Code: VK_NUMLOCK),
(Key: 'DOWN' ; Code: VK_DOWN),
(Key: 'PAGEDOWN' ; Code: VK_NEXT),
(Key: 'PGDN' ; Code: VK_NEXT),
(Key: 'PAGEUP' ; Code: VK_PRIOR),
(Key: 'PGUP' ; Code: VK_PRIOR),
(Key: 'RIGHT' ; Code: VK_RIGHT),
(Key: 'SCROLL' ; Code: VK_SCROLL),
(Key: 'SCROLLLOCK' ; Code: VK_SCROLL),
(Key: 'PRINTSCREEN'; Code: VK_SNAPSHOT),
(Key: 'PRTSC' ; Code: VK_SNAPSHOT),
(Key: 'TAB' ; Code: VK_TAB),
(Key: 'UP' ; Code: VK_UP),
(Key: 'F1' ; Code: VK_F1),
(Key: 'F2' ; Code: VK_F2),
(Key: 'F3' ; Code: VK_F3),
(Key: 'F4' ; Code: VK_F4),
(Key: 'F5' ; Code: VK_F5),
(Key: 'F6' ; Code: VK_F6),
(Key: 'F7' ; Code: VK_F7),
(Key: 'F8' ; Code: VK_F8),
(Key: 'F9' ; Code: VK_F9),
(Key: 'F10' ; Code: VK_F10),
(Key: 'F11' ; Code: VK_F11),
(Key: 'F12' ; Code: VK_F12),
(Key: 'WIN' ; Code: VK_LWIN),
(Key: 'APP' ; Code: VK_APPS));
var
bPlaying, // 지금 이전의 키 메크로 작업 중인가?
bWinPressed,
bAltPressed,
bControlPressed,
bShiftPressed : Boolean;
Delay : DWord;
destructor TMessageList.Destroy;
var
i : Integer;
begin
for i:=0 to Count-1 do
Dispose(PEventMsg(Items[i]));
inherited;
end;
// Key가 들어오면 이를 Key Table에서 Code를 찾아내어 return한다.
function FindKeyInArray(Key: String; var Code: UINT): Boolean;
var
i : Integer;
begin
Result := False;
for i:=Low(KeyDefs) to High(KeyDefs) do
if UpperCase(Key)=KeyDefs[i].Key then
begin
Code := KeyDefs[i].Code;
Result := True;
Exit;
end;
end;
const
vkKeySet = [VK_SPACE, Ord('A')..Ord('Z'), VK_MENU, VK_F1..VK_F12];
// Keybd_event를 발생시칸다.
procedure SimulateKey(Code: UINT; Down: Boolean);
const
KeyFlag : array[Boolean] of UINT = (KEYEVENTF_KEYUP, 0);
begin
// MapVirtualKey : Virtual-Key code를 (H/W)Scan Code로 변환한다.
Keybd_Event(Code, MapVirtualKey(Code, 0), KeyFlag[Down], 0);
end;
// loop를 돌면서 waiting을 한다.
// ???
procedure Wait;
var
dwCurrent: DWord;
begin
dwCurrent := timeGetTime;
repeat
until timeGetTime-dwCurrent>=Delay;
end;
// 특수키가 눌러졌을떄 이벤트를 발생시킨다.
procedure SimulateKeyPress(Code: UINT);
begin
// alt, ctrl, shift, win key를 down하는 event를 발생시킨다.
if bAltPressed then SimulateKey(VK_MENU, True);
if bControlPressed then SimulateKey(VK_CONTROL, True);
if bShiftPressed then SimulateKey(VK_SHIFT, True);
if bWinPressed then SimulateKey(VK_LWIN, True);
// key를 down(true)하고 나서 다시 release(false)하는 형식으로 한다.
SimulateKey(Code, True);
SimulateKey(Code, False);
// alt, ctrl, shift, win key를 release하는 event를 발생시킨다.
if bWinPressed then
begin
SimulateKey(VK_LWIN, False);
bWinPressed := False;
end;
if bShiftPressed then
begin
SimulateKey(VK_SHIFT, False);
bShiftPressed := False;
end;
if bControlPressed then
begin
SimulateKey(VK_CONTROL, False);
bControlPressed := False;
end;
if bAltPressed then
begin
SimulateKey(VK_MENU, False);
bAltPressed := False;
end;
// key의 입력이 너무 빠르지 않도록 delay를 둔다.
if Delay>0 then Wait;
end;
//
procedure NormalKeyPress(C: Char);
var
KeyCode,
Shift : UINT;
Code : String;
begin
KeyCode := vkKeyScanEx(C, GetKeyboardLayout(0));
if KeyCode=-1 then
begin
SimulateKey(VK_MENU, True);
try
Code := '0' + IntToStr(Ord(C));
while Code<>'' do
begin
case Code[1] of
'0': SimulateKeyPress(VK_NUMPAD0);
'1': SimulateKeyPress(VK_NUMPAD1);
'2': SimulateKeyPress(VK_NUMPAD2);
'3': SimulateKeyPress(VK_NUMPAD3);
'4': SimulateKeyPress(VK_NUMPAD4);
'5': SimulateKeyPress(VK_NUMPAD5);
'6': SimulateKeyPress(VK_NUMPAD6);
'7': SimulateKeyPress(VK_NUMPAD7);
'8': SimulateKeyPress(VK_NUMPAD8);
'9': SimulateKeyPress(VK_NUMPAD9);
end;
Delete(Code, 1, 1);
end;
finally
SimulateKey(VK_MENU, False);
end;
end
else
begin
// KeyCode의 상위 bit를 얻는다. ( Alt, Ctrl, Shift )
Shift := Hi(KeyCode);
// 1 0x00000001 : Shift
// 2 0x00000010 : Ctrl
// 4 0x00000100 : Alt
// 6 0x00000110 : Alt, Ctrl
// 7 0x00000111 : Alt, Ctrl, Shift
if Shift in [1, 7] then bShiftPressed := True;
if Shift in [2, 6, 7] then bControlPressed := True;
if Shift in [6, 7] then bAltPressed := True; // ?? why not include '4'
{ if ((Shift and 1)=1) or ((Shift and 6)=6) then bShiftPressed := True;
if (Shift and 2)=2 then bControlPressed := True;
if (Shift and 4)=4 then bAltPressed := True;}
// 일반적인 키보드 키
SimulateKeyPress(LoByte(KeyCode));
end;
end;
//{DELAY}에서 그 시간을 가져온다.
procedure CheckDelay(var Token: String);
var
P, Q : Integer;
sDelay: String;
begin
P := Pos('{DELAY', UpperCase(Token));
if P>0 then
begin
sDelay := Copy(Token, P+6, Length(Token));
Q := Pos('}', sDelay);
if Q>1 then
begin
sDelay := Copy(sDelay, 1, Q-1);
if (Length(sDelay)>0) and (sDelay[1]='=') then
begin
Delete(sDelay, 1, 1);
dec(Q);
end;
if Q>1 then
Delay := StrToIntDef(Copy(sDelay, 1, Q-1), 0)
else
raise EInvalidToken.Create('Invalid value for Delay');
end
else
raise EInvalidToken.Create('Incorrect delay syntax');
if Q>0 then
Delete(Token, P, Q+7)
else
raise EInvalidToken.Create('Invalid token');
end;
end;
// key를 처리한다.
procedure ProcessKey(S: String);
var
Index : Integer;
Token : String;
KeyCode: UINT;
begin
Index := 1;
repeat
case S[Index] of
KeyGroupOpen:
begin
Token := '';
inc(Index);
while (Index<Length(S)) and (S[Index]<>KeyGroupClose) do
begin
Token := Token + S[Index];
inc(Index);
if (Length(Token)=12) and (S[Index]<>KeyGroupClose) then
raise EInvalidToken.Create('No closing brace')
end;
if (Index<Length(S)-1) and (S[Index]=KeyGroupClose) and (S[Index+1]=KeyGroupClose) then
begin
inc(Index);
Token := Token + S[Index];
end;
if (Length(Token)=1) and (Pos(Token, KeyTokens)>0) then
NormalKeyPress(Token[1])
else if FindKeyInArray(Token, KeyCode) then
SimulateKeyPress(KeyCode);
end;
WindowsKey:
bWinPressed := True;
AltKey:
bAltPressed := True;
ControlKey:
bControlPressed := True;
ShiftKey:
bShiftPressed := True;
EnterKey:
SimulateKeyPress(VK_RETURN);
else
NormalKeyPress(S[Index]);
end;
inc(Index);
until Index > Length(S);
end;
// Key의 상태를 얻는다.
function CheckState(KeyCode: UINT): Boolean;
begin
Result := (GetAsyncKeyState(KeyCode) and $80000000)=0;
end;
// 모든 key가 released 되었는지를 check
function AllSpecialKeysReleased(ExtraKey: UINT): Boolean;
begin
Result := CheckState(VK_LWIN) and CheckState(VK_RWIN) and
CheckState(VK_CONTROL) and CheckState(VK_MENU) and
CheckState(VK_SHIFT) and ((ExtraKey=0) or (CheckState(ExtraKey)));
end;
// SendKeys..
// key들을 보내겠다.
// key가 모두 release되었는지를 check하고..
// 모두 release될때 까지 기다린 다음에
// 작업을 한다.
function SendKeys(S: String): TSendKeyError;
begin
Result := skSuccess;
if bPlaying or (S='') then Exit;
bPlaying := True;
try
bAltPressed := False;
bControlPressed := False;
bShiftPressed := False;
repeat
Application.ProcessMessages;
until AllSpecialKeysReleased(0);
try
CheckDelay(S);
ProcessKey(S);
except
on E:ESendKeyError do
begin
if E is EInvalidToken then
Result := skInvalidToken;
end
else
Result := skUnknownError;
end;
finally
bPlaying := False;
end;
end;
end.
IsDBCSLeadByte(Byte(S));