zoukankan      html  css  js  c++  java
  • 关于Action快捷键和小键盘的问题

    在使用全尺寸键盘的时候 键盘右边都有一排小键盘

    但是这个小键盘的数字键值和普通键盘的数字键值是不一样的

    在ANSI码里 标准数字键值是$30..$39, 而小键盘的键值是$60..$69

    这样问题就来了 , 我们在属性编辑器里设置Action的ShortCut的时候, 使用的都是文字表示, 而VCL架构里, ShortCut的文字表示是不区分大小键盘数字键的

    我们先看一下文字是真么转换成ShortCut的:

    在Menus单元: TextToShortCut(Text: string): TShortCut; 函数

    function TextToShortCut(Text: string): TShortCut;
    
      { If the front of Text is equal to Front then remove the matching piece
        from Text and return True, otherwise return False }
    
      function CompareFront(var Text: string; const Front: string): Boolean;
      begin
        Result := False;
        if (Length(Text) >= Length(Front)) and
          (AnsiStrLIComp(PChar(Text), PChar(Front), Length(Front)) = 0) then
        begin
          Result := True;
          Delete(Text, 1, Length(Front));
        end;
      end;
    
    var
      Key: TShortCut;
      Shift: TShortCut;
    begin
      Result := 0;
      Shift := 0;
      while True do
      begin
        if CompareFront(Text, MenuKeyCaps[mkcShift]) then Shift := Shift or scShift
        else if CompareFront(Text, '^') then Shift := Shift or scCtrl
        else if CompareFront(Text, MenuKeyCaps[mkcCtrl]) then Shift := Shift or scCtrl
        else if CompareFront(Text, MenuKeyCaps[mkcAlt]) then Shift := Shift or scAlt
        else Break;
      end;
      if Text = '' then Exit;
      for Key := $08 to $255 do { Copy range from table in ShortCutToText }
        if AnsiCompareText(Text, ShortCutToText(Key)) = 0 then
        begin
          Result := Key or Shift;
          Exit;
        end;
    end;

    注意加亮的那几行, 实际上就是吧$08~$255的所有字符和传入的做个比较, 那么我们的焦点就关注到ShortCutToText上了:

    function ShortCutToText(ShortCut: TShortCut): string;
    var
      Name: string;
    begin
      case WordRec(ShortCut).Lo of
        $08, $09:
          Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcBkSp) + WordRec(ShortCut).Lo - $08)];
        $0D: Name := MenuKeyCaps[mkcEnter];
        $1B: Name := MenuKeyCaps[mkcEsc];
        $20..$28:
          Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcSpace) + WordRec(ShortCut).Lo - $20)];
        $2D..$2E:
          Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcIns) + WordRec(ShortCut).Lo - $2D)];
        $30..$39: Name := Chr(WordRec(ShortCut).Lo - $30 + Ord('0'));
        $41..$5A: Name := Chr(WordRec(ShortCut).Lo - $41 + Ord('A'));
        $60..$69: Name := Chr(WordRec(ShortCut).Lo - $60 + Ord('0'));
        $70..$87: Name := 'F' + IntToStr(WordRec(ShortCut).Lo - $6F);
      else
        Name := GetSpecialName(ShortCut);
      end;
      if Name <> '' then
      begin
        Result := '';
        if ShortCut and scShift <> 0 then Result := Result + MenuKeyCaps[mkcShift];
        if ShortCut and scCtrl <> 0 then Result := Result + MenuKeyCaps[mkcCtrl];
        if ShortCut and scAlt <> 0 then Result := Result + MenuKeyCaps[mkcAlt];
        Result := Result + Name;
      end
      else Result := '';
    end;

    很明显, 这里面把标准数字键和小键盘数字键全部映射成0~9了, 那么自然在TextToShortCut的时候就只会认出标准键盘了

    所以, 一般情况下, 是没办法在属性编辑器里设置小键盘热键的, 只能通过代码解决:

    在代码模式下, Action的ShortCut属性是一个TShortCut类型: TShortCut = Low(Word)..High(Word); 也就是说, 是Ansi字符

    那么我们就可以直接使用键值来设置ShortCut, 而绕过Text转换的步骤, 从而能够达到使用小键盘快捷键的目的:

      Action1.ShortCut := Menus.ShortCut(VK_NUMPAD0, [ssCtrl]);

    这样就很简单的设置了一个ctrl+小键盘0的快捷键

    那么, 如果要同时设置标准键0和小键盘0都能激活这个Action怎么做呢

    这就要使用另一个属性: SecondaryShortCuts, 这个实际上是一个TStringList

      property SecondaryShortCuts: TShortCutList
    
      TShortCutList = class(TStringList)
      private
        function GetShortCuts(Index: Integer): TShortCut;
      public
        function Add(const S: String): Integer; override;
        function IndexOfShortCut(const Shortcut: TShortCut): Integer;
        property ShortCuts[Index: Integer]: TShortCut read GetShortCuts;
      end;

    OK, 现在出现了另一个问题, 我们向SecondaryShortCuts里写入多个快捷键, 是使用的Add, 可惜....Add的是一个文本, 这样我们又回到开始的问题了, 文本没办法区分大小键盘数字键, 咋办...-_-

    有人会说, 吧小键盘设置到ShortCut上, 大键盘用SecondaryShortCuts, OK, 这当然没问题....不过始终不是正统的解决办法(程序员的偏执)

    研究代码吧:

    function TShortCutList.Add(const S: String): Integer;
    begin
      Result := inherited Add(S);
      Objects[Result] := TObject(TextToShortCut(S));
    end;
    
    function TShortCutList.GetShortCuts(Index: Integer): TShortCut;
    begin
      Result := TShortCut(Objects[Index]);
    end;

    似乎有办法解决, add的时候实际上是吧ShortCut强制转换为TObject类型保存进Objects里了(其实是个取巧的办法, 我自己也总这么干...^_^)

    而读取ShortCut的时候根本没读String, 直接读的就是Objects, 那么我们如果直接写Objects能否可行? 试试看:

      Action1.SecondaryShortCuts.AddObject('Ctrl+Num0', TObject(Menus.ShortCut(VK_NUMPAD0, [ssCtrl])));

    OK, 测试完全可行......问题完美解决了

  • 相关阅读:
    Python学习——网站收集
    基于三轴加速计的运动识别与控制系统
    Unity小记
    Unity3d 札记-Survival Shooting 知识点汇总--受到伤害时屏幕闪血光如何做到
    Unity3d 札记-Survival Shooting 知识点汇总--Navigation 自动寻路的运用
    Unity3d 札记-Survival Shooting 知识点汇总--AnimationController
    Unity3d札记 --TanksTutorial收获与总结
    Unity3d 札记-Tanks Tutorial 知识点汇总--游戏流程的控制
    Unity3d 札记-Tanks Tutorial 知识点汇总---如何发射子弹
    Unity3d 札记-Tanks Tutorial 知识点汇总---子弹爆炸效果的实现
  • 原文地址:https://www.cnblogs.com/lzl_17948876/p/3911936.html
Copyright © 2011-2022 走看看