Project1

标题: 任意字符输入的实现 [打印本页]

作者: 各种压力的猫君    时间: 2012-2-7 18:00
标题: 任意字符输入的实现
1.API

RUBY 代码复制
  1. require 'Win32API'
  2. # require 'dl/win32'
  3.  
  4. class Win32API
  5.   # type flag
  6.   MB_OK               = 0
  7.   MB_OKCANCEL         = 1
  8.   MB_ABORTRETRYIGNORE = 2
  9.   MB_YESNOCANCEL      = 3
  10.   MB_YESNO            = 4
  11.   MB_RETRYCANCEL      = 5
  12.  
  13.   # return values
  14.   IDOK     = 1
  15.   IDCANCEL = 2
  16.   IDABORT  = 3
  17.   IDRETRY  = 4
  18.   IDIGNORE = 5
  19.   IDYES    = 6
  20.   IDNO     = 7
  21.  
  22.   def Win32API.MessageBox(wnd, text, caption, type = MB_OK)
  23.     messagebox = Win32API.new('user32', 'MessageBox', %w(p p p i), 'i')
  24.  
  25.     messagebox.call(wnd, text, caption, type)
  26.   end
  27.  
  28.   def Win32API.MessageBoxEx(wnd, text, caption, type = MB_OK, languageid = 0)
  29.     messagebox = Win32API.new('user32', 'MessageBoxEx', %w(p p p i i), 'i')
  30.  
  31.     messagebox.call(wnd, text, caption, type, languageid)
  32.   end
  33. end
  34.  
  35. p Win32API.MessageBox(0, "test message", "test caption")
  36. p Win32API.MessageBoxEx(0, "test message", "test caption")
  37. p Win32API.MessageBox(0, "てすと", "テスト")
  38. p Win32API.MessageBoxEx(0, "てすと", "テスト")


(在RM里用的话需要注释掉第一行)
因为MessageBox可以很容易实现,我想能不能同样轻松地调用InputBox。

于是折腾半天一直都反复报错:
  1. Script '' line 42: RuntimeError occurred.

  2. GetProcAddress: InputBox or InputBoxA
复制代码
RUBY 代码复制
  1. inputbox = Win32API.new('user32', 'InputBox', %w(p p i i p), 'p')


倒地不起……谁帮我解决下 233

2.控制台

因为Ace新加入了一个控制台(类似Windows系统的cmd么……)
通过 gets 可以获取控制台输入,而控制台可以支持输入法……所以不失为一种解决方法。

但是怎样在需要的时候打开/关闭控制台,设置控制台窗口的大小、位置又成了难点 = = b

3.自己写个程序读取并写入某个文本文档,然后再在RM中读取

流程如下:

① RM调用脚本,将一些参数写入文本 =>
② 由RM启动自写程序挂起游戏并等待自写程序结束后继续执行 =>
③ 自写程序读取文本文档中的内容,根据文本文档中的内容设置窗口标题、提示文本、文本框默认文本、
  窗口大小、位置、按钮文本、是否回显为"*"号(密码输入用)等一系列参数,并生成输入窗口等待玩家输入 =>
④ 玩家输入完成后通过确定按钮或会车键结束,自写程序将输入内容写入到文本文档并关闭自身 =>
⑤ RM检测到自写程序已结束,从文本文档相应行数读取输入文本

(好麻烦 = = b 能不能写个DLL把中间的文本操作换成内存操作……咱是做不到了 OTL)



目前自己只想到这三种方法……请各位补充。
作者: 凌依约    时间: 2012-2-7 18:52

先Mark:

然后下面是个人拙见.....
1.API的思路
   亲,InputBox是VB中的函数,不是API的哟,并且W32API中也貌似没有类似功能的API(貌似貌似)
   不过可以预先用其它的语言(C啦D啦还有易什么的)写一个包含输入框的DLL,然后用API调用,不过在全屏的时候真的大丈夫?
2.控制台的思路
   打开控制台的话看看这段:
  1. 比如ifconfig.exe这个控制台的程序(windows下的一个显示ip的控制台程序)
  2. 使用IO管道
  3. 创建ipconfig.exe进程,同时与之建立管道连接
  4. ipcon=IO.popen("ipconfig.exe","r")
  5. res=ipcon.read
  6. ipcon.close

  7. res里面存的就是ipconfig.exe控制台输出的结果了。
  8. 用ipcon.write也可以向该控制台程序发送指令,这就形成了交互(当然此时popen参数里的"r"改成"r+"。
复制代码
这个原理可以用到Game.exe程序里,不过现在在外面,手头上没有ACE,就没法试
然后之前看了下那个光的圆周率大大的控制台脚本,发现他在打开控制台的情况下,通过调用API函数来进行打开和隐藏,不知道可不可以在游戏开始时就打开控制台并隐藏
需要的时候才调出来.

ACE的控制台貌似就是基于Windows的控制台显示的,修改大小的话可能可以用API修改,然后再把边框去掉,不过这样做好像很不稳定,稍一不慎就Down掉了...

3.自己做程序来传输
这个思路MS可行,不过看起来就和1.API的那个差不多,用文件传太不安全了,不如用API反调回游戏还比较好


个人觉得的话用封装了输入对话框的DLL + API通过指针传给游戏比较可行...

作者: IamI    时间: 2012-2-7 19:01
常规方法是用 API 造一个窗口,里面放个 Textbox 的真货,伪造成就是这个窗体的。这样常常伴有焦点问题。
开创者:神思
夏娜写过一个DLL输入脚本,瑕疵有,总体问题不大。
最后请允许我吐个槽:挂起程序时间长了不被系统终止么?虽然这年头没有 10s 了……
作者: 各种压力的猫君    时间: 2012-2-7 20:13
本帖最后由 各种压力的猫君 于 2012-2-7 20:14 编辑
IamI 发表于 2012-2-7 19:01
常规方法是用 API 造一个窗口,里面放个 Textbox 的真货,伪造成就是这个窗体的。这样常常伴有焦点问题。
...


刚试了神思的,发现左右键移动光标/选中时光标不会移动(只是显示不动,实际上有移动没错)
用日文输入法会出现一个超难看的输入窗 = = b 是我输入法的问题么(度娘的日文输入……试了M$的也一样)

除了那个光标没发现什么BUG啊……有什么问题的话还望明示……
作者: yangff    时间: 2012-2-7 21:05
本帖最后由 yangff 于 2012-2-7 21:08 编辑

建议使用IMM API,这是最棒的,兼容全屏亲~
下面两个不支持全屏 = =
其次,CreateWindow+Clip消息
最后可以考虑http://rpg.blue/thread-121929-1-1.html,这个脚本我也写过,连vbs都咔嚓掉了,手绘InputBox= =
作者: orzfly    时间: 2012-2-8 00:20
immapi需要回调函数的吧
作者: IamI    时间: 2012-2-8 17:56
XP里,只用一个,那啥问题都没,光标慢是因为缓冲字节少了一,补上即可。
如果你想在其他 Rb 环境里用来做奇怪的事情,麻烦就比较大……
作者: dant    时间: 2012-2-10 08:53
本帖最后由 dant 于 2012-2-10 08:54 编辑

控制台不要想了,这货不支持Unicode
虽然知道显示隐藏可以用AllocConsole/FreeConsole
调整大小可以用SetConsoleScreenBufferSize
[line]2[/line]
不用外部窗口的话,唯一的实现方法是处理WM_CHAR和使用IMM API

作者: 杂兵天下    时间: 2012-2-10 14:53
本帖最后由 杂兵天下 于 2012-2-10 14:58 编辑

LZ明晃晃的版猪字样瞎了我的钛合金狗眼。。。。
RUBY 代码复制
  1. class Game_Interpreter
  2.   def command_303
  3.     return if $game_party.in_battle
  4.     $game_console.run("p \"角色原名:\"+$game_actors[param[0]].name
  5.     p \"请输入角色新名字\"
  6.     gnm=s2u(gets)
  7.     gnm=gnm[0..gnm.length-3]
  8.     $game_actors[param[0]].name=gnm
  9.     terminate",@params)
  10.     wait(50)
  11.   end
  12. end
  13. #==============================================================================
  14. #   ■ [RMVA]基于控制台的Debugger
  15. #------------------------------------------------------------------------------
  16. #   版本:1.00b
  17. #   作者:光的圆周率
  18. #   许可协议: FSL - NAM
  19. #
  20. #   已经被我改的面目全非了。
  21. #------------------------------------------------------------------------------
  22. #  脚本来自66RPG.com 转载请保留版权信息
  23. #==============================================================================
  24.  
  25. class Game_Console
  26.   SetWindowText   = Win32API.new("user32", "SetWindowTextA"      , "LP", "L")
  27.   SetFocus        = Win32API.new("user32", "SetForegroundWindow" , "L" , "L")
  28.   GetWindowRect   = Win32API.new("user32", "ShowWindow"  , "LL" , "L")
  29.   def terminate#毁尸灭迹。一段toeval代码的最后必须加上terminate。
  30.     system("cls")
  31.     GetWindowRect.call(@Con_hWnd,0)
  32.     SetFocus.call(@Mai_hWnd)
  33.   end
  34.   def initialize
  35.     @Con_hWnd  = get_ChWnd
  36.     @Mai_hWnd  = get_hWnd
  37.     terminate
  38.   end
  39.   def run(toeval="",param=nil)
  40.     SetFocus.call(@Con_hWnd)
  41.     SetWindowText.call(@Con_hWnd,"Console")
  42.     GetWindowRect.call(@Con_hWnd,4)
  43.     eval toeval
  44.   end
  45. end
  46. #==============================================================================
  47. # ■ Kernel
  48. #------------------------------------------------------------------------------
  49. #  获取游戏窗口及控制台窗口的脚本
  50. #   作者 : 紫苏
  51. #------------------------------------------------------------------------------
  52. #  脚本来自66RPG.com 转载请保留版权信息
  53. #==============================================================================
  54. module Kernel
  55.   GetWindowThreadProcessId = Win32API.new("user32", "GetWindowThreadProcessId", "LP", "L")
  56.   GetWindow = Win32API.new("user32", "GetWindow", "LL", "L")
  57.   GetClassName = Win32API.new("user32", "GetClassName", "LPL", "L")
  58.   GetCurrentThreadId = Win32API.new("kernel32", "GetCurrentThreadId", "V", "L")
  59.   GetForegroundWindow = Win32API.new("user32", "GetForegroundWindow", "V", "L")
  60.   def get_hWnd
  61.     threadID = GetCurrentThreadId.call
  62.     hWnd = GetWindow.call(GetForegroundWindow.call, 0)
  63.     while hWnd != 0
  64.       if threadID == GetWindowThreadProcessId.call(hWnd, 0)
  65.         className = " " * 11
  66.         GetClassName.call(hWnd, className, 12)
  67.         break if className == "RGSS Player"
  68.       end
  69.       hWnd = GetWindow.call(hWnd, 2)
  70.     end
  71.     return hWnd
  72.   end
  73.   def get_ChWnd
  74.     threadID = GetCurrentThreadId.call
  75.     hWnd = GetWindow.call(GetForegroundWindow.call, 0)
  76.     while hWnd != 0
  77.       if threadID == GetWindowThreadProcessId.call(hWnd, 0)
  78.         className = " " * 18
  79.         GetClassName.call(hWnd, className, 19)
  80.         break if className == "ConsoleWindowClass"
  81.       end
  82.       hWnd = GetWindow.call(hWnd, 2)
  83.     end
  84.     return hWnd
  85.   end
  86. end

奥,我忘记了。
要真正用这个东西必须在Main上写
RUBY 代码复制
  1. $game_console=Game_Console.new
  2. rgss_main { SceneManager.run }

然后必须用game console命令打开带命令提示符的RGSS Interpreter。
如此麻烦的东西。。。LZ还是不要研究了
作者: chd114    时间: 2012-5-28 13:37
RMXP的可以用?




欢迎光临 Project1 (https://rpg.blue/) Powered by Discuz! X3.1