⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keyinput.pas

📁 3D GameStudio 的Delphi开发包
💻 PAS
字号:
//////////////////////////////////////////////////////////////////////
//
// Delphi InKey Function for the A6_5x Engine (acknex.dll) done by
// Michal Messerschmidt aka LazyDog of Lazy Dog Software
// (www.LazyDogSoftware.com)
// (c) Lazy Dog Software / Michael Messerschmidt 2006
//
// SDK Version 6.50.6
//
// tested on Delphi 5,6,7,2005 & 2006
//////////////////////////////////////////////////////////////////////

unit keyinput;

interface
uses A6Engine;

Type TInKeyResult = (InKeyNotDone,InKeyAbort,InKeyDone);

var InKeyResult : TInKeyResult = InKeyNotDone;

procedure InKey(AString : PString; TheText : PText);
procedure ProcessInKey;

implementation
uses Engine_Library, Windows, Messages, Classes;

Type TInKeyState = (None,NeedInit,Working,NeedClose);

     PSaveKey = ^TSaveKey;
     TSaveKey = Record
                  addr : Pointer; //address to the key event on_enter, on_esc etc
                  func : Pointer; //address to the function assigned to the key event
                end;


Var KeyEvents : TList;
    InKeyVisible : Boolean = False;
    InKeyActive : Boolean = False;
    InKeyState : TInKeyState = None;
    InKeyCurrKey,
    InKeyStr : PString;
    InKeyText: PText;
    InKeySave : String;
    InKeyWork : String;
    InKeyPos : Integer = 1;
    InKeyMax : Integer = 0;


procedure SaveKeyEvents;

var I : Integer;
    MainAddr,
    fAddr : Pointer;
    KeyRec : PSaveKey;
begin
  InKeyWork := InKeyStr.char;
  InKeySave := InKeyWork;
  InKeyState := Working;
  KeyEvents := TList.Create;
  MainAddr := @ev.on_bksp;                  // point to the first key event

  for I := 0 to 87 do                       // on_bksp to on_pause
  begin
    fAddr := PPEvent(PPEvent(MainAddr)^)^;  // get the address of the function stored in the event

    if fAddr <> Nil then
    begin
      New(KeyRec);
      KeyRec^.addr := MainAddr;
      KeyRec^.func := fAddr;
      KeyEvents.Add(KeyRec);
      PPEvent(PPEvent(MainAddr)^)^ := Nil;  // remove all on key events
    end;

    Inc(PPEvent(MainAddr));                 // increment the pointer to the next key event
  end;

  if InKeyText <> Nil then                  // if the string we're working on is visible show caret
    if FlagIsOn(InKeyText.flags,_VISIBLE) then
      if CreateCaret(ev.hWndMain,0,InKeyText.font.dx,0) then
        if ShowCaret(ev.hWndMain) then
        begin
          InKeyVisible := True;
          SetCaretPos(_INT(InKeyText.pos_x),_INT(InKeyText.pos_y)+InKeyText.font.dy);
        end;
end;

procedure RestoreKeyEvents;

var I : Integer;
    MainAddr : Pointer;
    KeyRec : PSaveKey;
begin
  for I := KeyEvents.Count -1 downto 0 do
  begin
    KeyRec := KeyEvents.Items[I];
    MainAddr := KeyRec^.addr;                    // get the pointer to a key event
    PPEvent(PPEvent(MainAddr)^)^ := KeyRec.func; // restore what was in the key event
    Dispose(KeyRec);                             // remove memory allocated
    KeyEvents.Delete(I);                         // remove from the list
  end;

  KeyEvents.Free;
  InKeyState := None;
  InKeyActive := False;
  ev.inkey_active^ := OFF;

  if InKeyVisible then                           // if we created caret destroy it now
  begin
    InKeyVisible := False;
    HideCaret(ev.hWndMain);
    DestroyCaret;
  end;
end;

procedure MoveCaret(Amt : Integer);

var p : TPoint;
begin
  //-1 = Home 0 = backwards 1 = forward >1 = end
  if not InKeyVisible then Exit;

  GetCaretPos(p);

  Case Amt of
    -1 : p.X := _INT(InKeyText.pos_x);
     0 : Dec(p.X,InKeyText.font.dx);
     1 : Inc(p.X,InKeyText.font.dx);
    else Inc(p.X,Amt*InKeyText.font.dx);
  end;

  SetCaretPos(p.X,p.Y);
end;

procedure InKey(AString : PString; TheText : PText);

var Msg : TMsg;
    HasMsg : Boolean;
begin
  if InKeyActive then Exit;

  InKeyActive := True;
  InKeyState := NeedInit;
  InKeyResult := InKeyNotDone;

  SetString(InKeyWork,AString.char,AString.length);
  InKeyText:= TheText;
  InKeyStr := AString;
  InKeyPos := 1;
  InKeyMax := AString.length - 1;

  //clear out the keyboard buffer
  repeat
    HasMsg := PeekMessage(Msg,ev.hWndMain,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE);
  until not HasMsg;

  ev.inkey_active^ := ON;
end;

function ReplaceNoShiftedKey(Code : Integer) : Char;

const FirstRowReplace  = '`-=';   // value to replace a shifted number key
      SecondRowReplace = '[]\';               //
      ThirdRowReplace  = ';''';
      FourthRowReplace = ',./';
begin
  case Code of
       41 : Result := FirstRowReplace[1];
    12,13 : Result := FirstRowReplace[Code-11];
    26,27 : Result := SecondRowReplace[Code-25];
    43    : Result := SecondRowReplace[Code-40];
    39,40 : Result := ThirdRowReplace[Code-38];
   51..53 : Result := FourthRowReplace[Code-50];
       57 : Result := ' ';
       else Result := ' ';
  end;
end;

function ReplaceShiftedKey(Code : Integer) : Char;

const FirstRowReplace  = '!@#$%^&*()_+{}|';   // value to replace a shifted number key
      SecondRowReplace = '{}|';               //
      ThirdRowReplace  = ':"';
      FourthRowReplace = '<>?';
begin
  case Code of
    2..13 : Result := FirstRowReplace[Code-1];
    26,27 : Result := SecondRowReplace[Code-25];
    43    : Result := SecondRowReplace[Code-40];
    39,40 : Result := ThirdRowReplace[Code-38];
   51..53 : Result := FourthRowReplace[Code-50];
       else Result := ' ';   
  end;
end;

procedure ProcessInKey;

type TIntSet = set of 0..255;

const NumKeys  : TIntSet = [2..11];        // 1-9,0
      ShiftSpecialProcess : TIntSet = [2..13,26,27,39,40,51..53];
      NoShiftSpecialProcess : TIntSet = [41,12,13,26,27,39,40,43,51..53,57];

var Temp : Integer;
    Msg : TMsg;
    ScanCode : Integer;
    Caps : TKeyboardState;
    ShiftedKey,
    CapsLock : Boolean;
begin
  if not InKeyActive then Exit;

  if InKeyState = NeedInit then
    SaveKeyEvents;

  if InKeyState = Working then
  begin
    if ev.inkey_active^ = OFF then   // the user wants to abort
    begin
      Msg.message := WM_KEYDOWN;     // force a message value that
      Msg.wParam  := VK_ESCAPE;      // will execute the abort code
    end
    else                             // get keystrokes
    if not PeekMessage(Msg,ev.hWndMain,WM_KEYFIRST,WM_KEYLAST,PM_REMOVE) then Exit;

    if Msg.message = WM_KEYDOWN then // prevent processing same code on Key up event
    case Msg.wParam  of
      VK_TAB,
      VK_PRIOR,
      VK_NEXT,
      VK_UP,
      VK_DOWN,
      VK_INSERT,
      VK_SHIFT,
      VK_CONTROL,
      VK_CAPITAL,
      VK_LWIN,
      VK_RWIN,
      VK_APPS,
      VK_F1..VK_F24,
      VK_NUMLOCK : Exit;

      VK_ESCAPE : begin
                    str_cpy(InKeyStr,PChar(InKeySave));
                    InKeyState := NeedClose;
                    InKeyResult := InKeyAbort;
                  end;

      VK_BACK : begin
                  if InKeyPos = 1 then Exit;

                  Dec(InKeyPos);
                  Delete(InKeyWork,InKeyPos,1);
                  str_cpy(InKeyStr,PChar(InKeyWork));
                  MoveCaret(0);
                end;

     VK_RETURN: begin
                  InKeyState := NeedClose;
                  InKeyResult := InKeyDone;
                end;

     VK_HOME : begin
                 InKeyPos := 1;
                 MoveCaret(-1);
               end;

     VK_LEFT : if InKeyPos > 1 then
               begin
                 Dec(InKeyPos);
                 MoveCaret(0);
               end;

     VK_RIGHT : if InKeyPos < InKeyStr.length-1 then
                begin
                  Inc(InKeyPos);
                  MoveCaret(1);
                end;

     VK_END : begin
                Temp := InKeyStr.length-1 - InKeyPos;

                if Temp > 0 then
                begin
                  Inc(InKeyPos,Temp);
                  MoveCaret(Temp);
                end;
              end;

     VK_DELETE : begin
                   if InKeyStr.length < 2 then Exit;

                   Delete(InKeyWork,InKeyPos,1);
                   str_cpy(InKeyStr,PChar(InKeyWork));
                 end;

      else
      begin
        // get the scancode of the key pressed (bits 16-23 zero based)
        ScanCode := (Msg.lParam and $00FF0000) shr 16;

        // find out if shift key is down
        ShiftedKey := GetKeyState(VK_SHIFT) < 0;

        // find out if caps lock key is down
        GetKeyboardState(Caps);
        CapsLock := Caps[VK_CAPITAL] > 0;

        // process the key
        if (ShiftedKey and (ScanCode in ShiftSpecialProcess)) then
          InKeyCurrKey.char[0] := ReplaceShiftedKey(ScanCode)
        else
        if (not ShiftedKey and (ScanCode in NoShiftSpecialProcess)) then
          InKeyCurrKey.char[0] := ReplaceNoShiftedKey(ScanCode)
        else
        begin
          str_for_key(InKeyCurrKey,_VAR(ScanCode));

          if ShiftedKey or CapsLock then       // shift or caps lock key down
            if not (ScanCode in NumKeys) then  // not a shifted number key
              str_upr(InKeyCurrKey);           // upper case the letter
        end;

        if InKeyStr.length < 2 then            // started with an empty string
          InKeyWork := InKeyCurrKey.char[0]
        else
        if InKeyStr.length-1 < InKeyPos then   // adding to our string
          InKeyWork := InKeyWork + InKeyCurrKey.char[0]
        else
          InKeyWork[InKeyPos] := InKeyCurrKey.Char[0]; // replacing a character

        // place the character into the string the user passed
        str_cpy(InKeyStr,PChar(InKeyWork));

        // if we are not at the max length of the string move the caret forward
        if InKeyPos < InKeyMax then
        begin
          MoveCaret(1);
          Inc(InKeyPos);
        end;
      end;
    end;
  end;

  if InKeyState = NeedClose then
    RestoreKeyEvents;
end;

initialization
  InKeyCurrKey := str_create(' ');

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -