Q&A

  • 코드 문제 ...
[질문] 코드 문제 .......
(* 해결해 주시는 분께 영어학습 교재 무비잉글리쉬 교재를 드립니다.)
공부하려고 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.
2  COMMENTS
  • Profile
    양익호 2002.11.06 20:59
    예전에 한글과 영문 특수키로 조합된 화일의 스트로크를 계산하다가 사용한 함수인데 한번 확인해 보시기 바랍니다.

    IsDBCSLeadByte(Byte(S));


  • Profile
    박장용 2002.11.04 20:30
    procedure TForm1.Button1Click(Sender: TObject);
    var
      s :WideString;
    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;

    • 정문도
    • 2002.11.04 22:51
    • 4 COMMENTS
    • /
    • 0 LIKES
    • 김병곤
      2002.11.05 01:36
      완전히 델파이를 모르시는 분이라면 님에게는 맞지 않는 책을 구입하신겁니다. 님이 산 책은 중급서입니다...
    • 김지엽
      2002.11.04 22:59
      저도 뭐, 고수는 아니구. 특히 한참동안 델파이가 아닌 다른 언어만 사용해와서 잘 모르긴 합니다만.. 처음...
    • 정문도
      2002.11.04 23:09
      이렇게 빨이 답변글이 올라올줄 몰랐습니다. 우선 말씀감사드리구여.. 제가 산책이 초보자가 보기에 맞는...
    • 김대훈
      2002.11.05 03:20
      님께서 구입하신책을 그냥 보심이 좋을듯합니다. 그리고 보면서 무조건 실습... 그리고 델파이 헬프도 ...
    • 김형규
    • 2002.11.04 21:30
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 우소
      2002.11.05 00:02
      델파이를 시작 하자 마자 그런건 가요 아님 전에 짜던 프로그램 화일을 열었을때 인가요? 왜 에러가 발생...
    • 김형규
      2002.11.05 00:16
      델파이를 실행하면 빈 프로젝트화면이 뜨잖아요 세로운 빈 프로젝트를 열때도 그렇구요. 기존의 프로...
    • 서광원
    • 2002.11.04 20:56
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 물고기나라
      2002.11.05 01:44
      전체 레코드수는 이미 알고 있는거니깐 페이지번호 바로 옆에다 레이블하나 갖다놓구 '전체 레코...
    • 박준영
    • 2002.11.04 19:26
    • 0 COMMENTS
    • /
    • 0 LIKES
    • KDDG_hyun
    • 2002.11.04 19:17
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 콤보
      2002.12.16 21:12
      Delphi 7 has been released and has the usual QuickReport standard bundled with it. If the compon...
    • 김진천
    • 2002.11.04 19:03
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 이승민
      2002.11.04 21:41
      모 제가 허접스럽게 말씀드리는 것일지 모르지만 만일 TCP소켓을 사용하셨다면 한번에 보넬수 있는 바이트 ...
    • 김해성
    • 2002.11.04 18:58
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 물고기나라
      2002.11.05 01:54
      OnClick 코딩 부분에서 이벤트 발생시 이미 해당 레코드로 이동했으니깐 해당 쿼리컴포너트나 테이블의 ...
    • 이태원
    • 2002.11.04 12:54
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 씨나락
      2002.11.04 23:38
      컴포넌트가 없어서 무시하구 열어서 대충 소스를 보았습니다. 제가 알기로는 MDI폼을 구현할려면.. ...
    • 이태원
      2002.11.05 01:42
      다시 말씀 드리지만 MDI 풀어 놓았습니다. child 폼으로 설정 해 놓지 않았습니다. 아마 MDI 가 안되...
    • 유성욱
    • 2002.11.04 10:04
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 양익호
      2002.11.06 20:59
      예전에 한글과 영문 특수키로 조합된 화일의 스트로크를 계산하다가 사용한 함수인데 한번 확인해 보시기 ...
    • 박장용
      2002.11.04 20:30
      procedure TForm1.Button1Click(Sender: TObject); var   s :WideString; begin s := 'AB'; ...
    • 문현치
    • 2002.11.04 06:45
    • 1 COMMENTS
    • /
    • 0 LIKES
    • KYH
      2002.11.04 11:36
      일단 작업하신 코드가 있으면 더 잘 답변드릴수 있을거 같네여.... 질문하신 내용으로 대충 감잡아...
    • 나정훈
    • 2002.11.03 10:14
    • 1 COMMENTS
    • /
    • 0 LIKES
    • 나정훈
      2002.11.04 03:43
      한델 팁 게시판 874번이든가 초보자를 위한 동적생성이라는 제목검색을 하면 되군요. 감사합니다.
    • DelChoBo
    • 2002.11.03 00:38
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 아르스
    • 2002.11.02 23:17
    • 0 COMMENTS
    • /
    • 0 LIKES
    • 밥팅민수
      2002.11.03 12:27
      지금도 있는지는 모르겠지만... 자체한글 라이브러리가 두 개 정도 있었습니다. 하나는 태극이고 하...
    • 김세형
      2002.11.04 00:04
      저는 TCriticalSection을 썼습니당~ ^^;; TCriticalSection형 전역변수를 생성한다음,,동기화 시키고자 ...
    • 이승민
    • 2002.11.02 19:50
    • 2 COMMENTS
    • /
    • 0 LIKES
    • 최은석
      2002.11.02 21:06
      당순히 커서모양을 바꾸시려고 하신다면..... 아래처럼 해보시죠... Screen.Cursor := crHelp; <-- ...
    • 이승민
      2002.11.02 21:39
      SetSystemCursor 를 사용해서 System의 Cursor를 바꾸려고 하거든요. 근데 VC에있는 OCR_HELP 가 없어요.
    • 강정구
      2002.11.02 20:27
      procedure TFrmBuyPrint.GetPrintData(prFlag : Boolean); var    SQLString,buyingDate : S...
    • 머슴
      2002.11.02 19:56
        Parameters.ParamByName('BUY_NAME').Value := Cbobuycode.Text;   에서 에러...
    • 샤리
      2002.11.02 20:25
      그런데요.. 그럼 밑에 에러나는     Code.DataSet.FieldByName('ITEM_CODE').AsSt...
    • DelChoBo
      2002.11.02 23:21
      앞에 에러는 머슴님께서 답변해 주신게 맞는거 같고... 이부분의 코드들은 에러를 떠나서 코딩상 전혀...
    • 윤정식
    • 2002.11.02 19:21
    • 0 COMMENTS
    • /
    • 0 LIKES