查看: 4024|回复: 4

[讨论] 键盘 按键 键码 win32api GetAsyncKeyState GetKeyState Input VA

[复制链接]
梦石
0
星屑
1297
在线时间
995 小时
注册时间
2014-12-14
回帖
2939

开拓者

发表于 2018-3-26 18:52:35 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
本帖最后由 Vortur 于 2018-3-30 02:54 编辑

[fold=前言]  这里分享“VA的自制按键脚本”,这个脚本可以帮助作者在游戏中加入一些原本不存在的按键。学会了的话,就可以制作自己的全键盘脚本啦!❤
  上一集的链接是《显示字符》,下一集我们研究《游戏主循环》



  [/fold]
宏观算法
[fold=展开]  有一个对象A来记录按键的状态:“按下”、“点击”;程序通过读取对象A来判断按键状态
  它不停地、极快地刷新,以至于新状态不断地覆盖旧状态。当程序读取对象A时,总会读取到当前的状态,而不会受到旧状态的影响



  [/fold]
具体实现
[fold=新建模块,调用win32api][pre lang="ruby"]
module FeloneInput
GetAsyncKeyState = Win32API.new('user32', 'GetAsyncKeyState', 'i','i')
end[/pre]
  “GetAsyncKeyState = xxx...”表示将函数A赋值给名为“GetAsyncKeyState”的常量,上集我们知道了“变量”的定义,常量就是“首字大写的变量”
  “Win32API.new”表示生成一个win32api对象
  “('user32', 'GetAsyncKeyState', 'i','i')”表示这个win32api对象有四个参数:
  1. 'user32'
  要到计算机“windows\system32”子目录下,或者 RM工程的根目录中寻找名为“user32”的、后缀为“.dll”的文件
  2.  'GetAsyncKeyState'
  在上述文件中,调用名为“ GetAsyncKeyState”的函数
  3. 'i'
  在调用“GetAsyncKeyState”函数的“call”方法时,递入参数的类型为【整数类型】。例如:“GetAsyncKeyState.call(i)”表示将“i”递入“GetAsyncKeyState”函数中执行“call”这个方法
  4. 'i'
  “ GetAsyncKeyState”函数的返回值的类型为【整数类型】




  [/fold][fold=建立哈希表][pre lang="ruby"]Key_States = Hash.new {0}[/pre]
  建立一个哈希表,用来存储键盘状态
  “Key_States”表示这个哈希表中的第“i”位对象的值
  “Hash.new {0}”表示这个哈希表第“0”位的值为0;目前这个哈希表中只有1个对象



  [/fold][fold=建立刷新结构][pre lang="ruby"]
def self.update
  0x70.times {|i|
    GetAsyncKeyState.call(i) == 0 ? Key_States = 0 : Key_States += 1
  }
end[/pre]
“n.times{|i|做点什么}”表示“从‘0’开始,做n次‘|i|’右边的事情”
  当n=1时,这个循环只执行1次,“i”将会等于“0”,然后执行右方的代码
  当n=2时,这个循环执行2次,第一次i=0,执行右方的代码;第二次i=1,再执行右方的代码


“0x70”是一个十六进制的数,表示十进制的112,也就是说,这个循环要执行112次。关于进制的转换:计算器→查看→程序员

综上,这段代码的意义为:
  每次刷新,都要从0开始,做112次赋值。当“GetAsyncKeyState.call(键码)”函数的返回值为0的时候,那么“Key_States[键码] ”就为0,否则加1(在哈希表“Key_States”中,第“键码”位的对象对应存储键码为“键码”的键位信息)
  在具体使用时,需要将“FeloneInput.update”(调用“FeloneInput”模块的“update”方法)置入游戏主循环中,随【游戏状态】的更新而更新



  [/fold][fold=判断玩家键盘消息][pre lang="ruby"]
def self.press?(sym)
        return true if Key_States[sym] > 0
        return false
end
def self.trigger?(sym)
        return true if Key_States[sym] == 1
        return false
end
def self.repeat?(sym)
        s = Key_States[sym]
        return true if s == 1 || s > 23 && s % 6 == 0
        return false
end[/pre]
  上面的含义是:“当玩家按下‘sym’键(包括点击和持续压下)时,FeloneInput.press?(sym)将返回真;FeloneInput.trigger?(sym)将返回假”,“当玩家点击一次‘sym’键时,FeloneInput.trigger?(sym)将返回真。当然,FeloneInput.press?(sym)也返回真”



  [/fold]
附录
[fold=附全部代码]
[pre lang="ruby"]
#encoding:utf-8
#==============================================================================
# ■ FeloneInput
#------------------------------------------------------------------------------
#  管理“键盘消息”的模块
#==============================================================================
module FeloneInput
        #--------------------------------------------------------------------------
        # ● 调用 windows 函数(32位)
        #--------------------------------------------------------------------------
        GetAsyncKeyState = Win32API.new('user32', 'GetAsyncKeyState', 'i','i')
        #--------------------------------------------------------------------------
        # ● 新建哈希表,存放按键状态
        #--------------------------------------------------------------------------
        Key_States = Hash.new {0}
        #--------------------------------------------------------------------------
        # ● 更新
        #--------------------------------------------------------------------------
        def self.update
                0x70.times {|i|
                        GetAsyncKeyState.call(i) == 0 ? Key_States = 0 : Key_States += 1
                }
        end
        #--------------------------------------------------------------------------
        # ● 获取玩家键盘消息
        #--------------------------------------------------------------------------
        def self.press?(sym)
                return true if Key_States[sym] > 0
                return false
        end
        def self.trigger?(sym)
                return true if Key_States[sym] == 1
                return false
        end
        def self.repeat?(sym)
                s = Key_States[sym]
                return true if s == 1 || s > 23 && s % 6 == 0
                return false
        end
       
end
[/pre]
[/fold][fold=win32api教程]
秀秀的教程
晴兰的教程
win32手册
[/fold][fold=键码表]
[pre lang="ruby"]=begin
##==============================================================================
##  鼠标键(16位)
##==============================================================================
#0x01        #鼠标左键
#0x02        #鼠标右键
#0x04        #鼠标中键
##==============================================================================
##  主键盘(16位)
##==============================================================================
##--------------------------------------------------------------------------
## ● 字母键
##--------------------------------------------------------------------------
#0x41        #A
#0x42        #B
#0x43        #C
#0x44        #D
#0x45        #E
#0x46        #F
#0x47        #G
#0x48        #H
#0x49        #I
#0x4A        #J
#0x4B        #K
#0x4C        #L
#0x4D        #M
#0x4E        #N
#0x4F        #O
#0x50        #P
#0x51        #Q
#0x52        #R
#0x53        #S
#0x54        #T
#0x55        #U
#0x56        #V
#0x57        #W
#0x58        #X
#0x59        #Y
#0x5A        #Z
##--------------------------------------------------------------------------
## ● 英文键
##--------------------------------------------------------------------------
#0x08        #BACKSPACE
#0x09        #TAB
#0x0D        #ENTER
#0x10        #SHIFT
#0x11        #CTLR
#0x12        #ALT
#0x13        #PAUSE
#0x14        #CAPS LOCK
#0x1B        #ESC
#0x20        #SPACEBAR
#0x21        #PAGE UP
#0x22        #PAGE DOWN
#0x23        #END
#0x24        #HOME
#0x25        #LEFT ←
#0x26        #UP ↑
#0x27        #RIGHT →
#0x28        #DOWN ↓
#0x29        #SELECT
#0x2A        #PRINT
#0x2B        #SELECT
#0x2C        #PRINT SCREEN
#0x2D        #INS
#0x2E        #DEL
#0xA0        #左 SHIFT
#0xA1        #右 SHIFT
#0xA2        #左 CONTROL
#0xA3        #右 CONTROL
#0xA4        #左 ALT
#0xA5        #右 ALT
##--------------------------------------------------------------------------
## ● 数字键
##--------------------------------------------------------------------------
#0x30        #0
#0x31        #1
#0x32        #2
#0x33        #3
#0x34        #4
#0x35        #5
#0x36        #6
#0x37        #7
#0x38        #8
#0x39        #9
##--------------------------------------------------------------------------
## ● 功能键
##--------------------------------------------------------------------------
#0x70        #F1
#0x71        #F2
#0x72        #F3
#0x73        #F4
#0x74        #F5
#0x75        #F6
#0x76        #F7
#0x77        #F8
#0x78        #F9
#0x79        #F10
#0x7A        #F11
#0x7B        #F12
##==============================================================================
##  副键盘(16位)
##==============================================================================
#0x60        #Numericpad 0
#0x61        #Numericpad 1
#0x62        #Numericpad 2
#0x63        #Numericpad 3
#0x64        #Numericpad 4
#0x65        #Numericpad 5
#0x66        #Numericpad 6
#0x67        #Numericpad 7
#0x68        #Numericpad 8
#0x69        #Numericpad 9
#0x6A        #Multiply (*)
#0x6B        #Add (+)
#0x6C        #Separator ()
#0x6D        #Subtract (-)
#0x6E        #Decimal (.)
#0x6F        #Divide (/)
#0x90        #NUM LOCK
#0x91        #SCROLL LOCK
=end[/pre]
[/fold][fold=“GetAsyncKeyState”与“GetKeyState”的区别]
  观点1
  观点2
  这两个观点恰好是相悖的,也不造为什么

[/fold]PS.有没说清楚的,随时问
【RMVA教程】
---------------------
欲买桂花同载酒,终不似,少年游.

醉啸 长风万里

梦石
0
星屑
6512
在线时间
6616 小时
注册时间
2007-12-16
回帖
4301

贵宾

发表于 2018-3-26 22:53:52 | 显示全部楼层
如果要做商业游戏那种玩家自定义按键的话貌似修改按键很简单?修改之后如何保存和处理冲突才是问题?

还在龟速填坑中
回复

使用道具 举报

梦石
0
星屑
1297
在线时间
995 小时
注册时间
2014-12-14
回帖
2939

开拓者

 楼主| 发表于 2018-3-27 07:12:52 | 显示全部楼层
本帖最后由 Vortur 于 2018-3-27 04:06 编辑
仲秋启明 发表于 2018-3-26 04:53
如果要做商业游戏那种玩家自定义按键的话貌似修改按键很简单?修改之后如何保存和处理冲突才是问题? ...


  唔...在下没有想辣么深,这是从自己的游戏《他乡何恙》里拆出来的脚本,这里附一个自定义按键的beta,用这个思路的话,实现阁下的功能应该是可以了
  至于兼容性...所有代码都重写了,兼容性自然不需要担心了吧!?如果想做成“脚本插件”这种代码,只需在在模块“FeloneInput”里设置一些常量,并将其重命名为“Input”,再插入到“BattleManager”下,应该就可以了啪!?❤

附:用户自定义键位beta
Scripts.zip (1.74 KB, 下载次数: 86)


P.S.尝试写了下“自定义按键”的脚本插件,发现主要问题有两个:
  1. Input模块中,不能置入预设变量
  2. 符号“:A”、“:B”等,在下无法将其重新赋值






  
【RMVA教程】
---------------------
欲买桂花同载酒,终不似,少年游.
回复

使用道具 举报

梦石
0
星屑
4623
在线时间
1207 小时
注册时间
2016-4-7
回帖
944

开拓者

发表于 2018-3-27 18:37:15 | 显示全部楼层
仲秋启明 发表于 2018-3-26 22:53
如果要做商业游戏那种玩家自定义按键的话貌似修改按键很简单?修改之后如何保存和处理冲突才是问题? ...

我印象中 xp 有个带虚拟按键层的键盘输入脚本 思路是你可以创建一个虚拟的键盘映射层 这样开发的时候所引用的按键和最终实际生效的按键并不需要对应 这样只要修改这个vk层就可以做到自定义按键
附庸的附庸不是我的附庸,女儿的女儿还是我的女儿。CK2沉迷ing
回复

使用道具 举报

梦石
0
星屑
1297
在线时间
995 小时
注册时间
2014-12-14
回帖
2939

开拓者

 楼主| 发表于 2018-3-27 20:37:40 | 显示全部楼层
本帖最后由 Vortur 于 2018-3-27 03:37 编辑
dearake 发表于 2018-3-27 00:37
我印象中 xp 有个带虚拟按键层的键盘输入脚本 思路是你可以创建一个虚拟的键盘映射层 这样开发的时候所引 ...


呃呃呃...
[fold=“虚拟的键盘映射层”是这样吗?]
Scripts.zip (1.74 KB, 下载次数: 2)
[/fold]  思路就是:“在监听玩家键盘消息时,以预置变量存储键码”,只需在游戏中设置一个修改变量内容的功能,即可实现“玩家自定义按键”
  尝试了一下把这个脚本写成脚本插件,发现预置变量出现在“Input”模块中将会报错,可能“Input”的加载要早于变量(实际情况是,无论将预置变量的加载置于何处,总是报错“未为名方法”);另外,“符号”的重赋值在下也不会TAT

  要是能找到一个重写Input模块的范例就好了,记得曾经在哪里见过的...唉,类似这个:重写按键符号


  
【RMVA教程】
---------------------
欲买桂花同载酒,终不似,少年游.
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部