查看: 14585|回复: 15

[已发主站] 【已通用】超级免DLL输入法

[复制链接]

路人党员

梦石
0
星屑
52
在线时间
2276 小时
注册时间
2010-12-30
回帖
3011
发表于 2012-7-24 21:41:07 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 英顺的马甲 于 2015-8-17 10:41 编辑

脚本已经加强,支持文本选择并且已经通用(其实本来就不难通用 =.=||)


最近研究API研究的起劲,对着MSDN几天后,
拟定了一个输入法的方案便开始写起脚本来了,
写着写着,突然!怎么感觉似曾相识?!
原来有人写过了~囧
http://rpg.blue/thread-93059-1-1.html
仔细看了一下,虽然脚本很相像,
但是总觉得我的方案好多了,
至少我的功能完整,至少~囧


经过一系列的研究,要不调用DLL把输入条直接镶在RGSS Player内至少凭我的程度是办不到的
(就算用dll我也办不到~囧),在我的方案内解决了一个上述地址中脚本的一个bug,
要获取输入中光标的位置和限制字数除了取SendMessage的返回值别无他法==

这个输入法用到了三个脚本

获取窗口句柄(已经有了可不必):
  1. #==============================================================================
  2. # ■ Kernel
  3. #------------------------------------------------------------------------------
  4. #  该模块中定义了可供所有类使用的方法。Object 类中包含了该模块。
  5. #==============================================================================
  6. module Kernel
  7.   #--------------------------------------------------------------------------
  8.   # ● 需要的 Windows API 函数
  9.   #--------------------------------------------------------------------------
  10.   GetWindowThreadProcessId = Win32API.new("user32", "GetWindowThreadProcessId", "LP", "L")
  11.   GetWindow = Win32API.new("user32", "GetWindow", "LL", "L")
  12.   GetClassName = Win32API.new("user32", "GetClassName", "LPL", "L")
  13.   GetCurrentThreadId = Win32API.new("kernel32", "GetCurrentThreadId", "V", "L")
  14.   GetForegroundWindow = Win32API.new("user32", "GetForegroundWindow", "V", "L")
  15.   #--------------------------------------------------------------------------
  16.   # ● 获取窗口句柄
  17.   #--------------------------------------------------------------------------
  18.   def get_hWnd
  19.     # 获取调用线程(RM 的主线程)的进程标识
  20.     threadID = GetCurrentThreadId.call
  21.     # 获取 Z 次序中最靠前的窗口
  22.     hWnd = GetWindow.call(GetForegroundWindow.call, 0)
  23.     # 枚举所有窗口
  24.     while hWnd != 0
  25.       # 如果创建该窗口的线程标识匹配本线程标识
  26.       if threadID == GetWindowThreadProcessId.call(hWnd, 0)
  27.         # 分配一个 11 个字节的缓冲区
  28.         className = " " * 11
  29.         # 获取该窗口的类名
  30.         GetClassName.call(hWnd, className, 12)
  31.         # 如果匹配 RGSS Player 则跳出循环
  32.         break if className == "RGSS Player"
  33.       end
  34.       # 获取下一个窗口
  35.       hWnd = GetWindow.call(hWnd, 2)
  36.     end
  37.     return hWnd
  38.   end
  39. end
复制代码
输入框核心脚本:[pre lang="ruby"]#==============================================================================
# ■ TextBox  by EngShun
#------------------------------------------------------------------------------
#  输入框的类。
#==============================================================================
class TextBox
  #--------------------------------------------------------------------------
  # ● 设置API
  #--------------------------------------------------------------------------
  CreateWindow = Win32API.new('user32','CreateWindowExW','lpplllllllll','l')
  ShowWindow = Win32API.new('user32','ShowWindow','ll','l')
  DestroyWindow = Win32API.new('user32','DestroyWindow','l','l')
  GetWindowText = Win32API.new('user32','GetWindowTextW','lpl','l')
  SetWindowText = Win32API.new("user32", "SetWindowTextW", "lp", "l")
  SetWindowPos = Win32API.new("user32", "SetWindowPos", "lliiiii", "i")
  GetWindowTextLength = Win32API.new('user32','GetWindowTextLengthW','l','l')
  UpdateWindow = Win32API.new('user32','UpdateWindow','l','i')
  SetFocus = Win32API.new('user32','SetFocus','l','l')
  SendMessage = Win32API.new('user32','SendMessageW','llll','l')
  GetKeyState = Win32API.new("user32","GetAsyncKeyState",'I','I')
  #--------------------------------------------------------------------------
  # ● 定义实例变量
  #--------------------------------------------------------------------------
  attr_accessor :focus
  #--------------------------------------------------------------------------
  # ● 初始化
  #--------------------------------------------------------------------------
  def initialize(text = "",limit = 8,number=false, x = 0, y = 458)
    c = 0x40011000
    c = (c|0x00001000) if number
    @window = CreateWindow.call(0, mb2wc('EDIT'), mb2wc(text), c, x, y, 240, 22, get_hWnd, 0, 0, 0)
    SendMessage.call(@window,0xC5,limit,0)
    @focus = true
    @disposed = false
  end
  #--------------------------------------------------------------------------
  # ● 释放
  #--------------------------------------------------------------------------
  def dispose
    @disposed = true
    DestroyWindow.call(@window)
  end
  #--------------------------------------------------------------------------
  # ● 刷新
  #--------------------------------------------------------------------------
  def update
    return if !@focus or @disposed
    UpdateWindow.call(@window)
    SetFocus.call(@window)
  end
  #--------------------------------------------------------------------------
  # ● 获取内容
  #--------------------------------------------------------------------------
  def text
    return if @disposed
    l = GetWindowTextLength.call(@window)
    str = [0].pack('S') * (l + 1)
    GetWindowText.call(@window, str, l+1)
    return wc2mb(str)
  end
  #--------------------------------------------------------------------------
  # ● 更改内容
  #--------------------------------------------------------------------------
  def text=(str)
    SetWindowText.call(@window, mb2wc(str))
    return if @disposed
  end
  #--------------------------------------------------------------------------
  # ● 设定位置
  #--------------------------------------------------------------------------
  def set_pos(x, y)
    SetWindowPos.call(@window, 0, x, y, 240, 22, 0x80)
  end
  #--------------------------------------------------------------------------
  # ● 获取光标位置
  #--------------------------------------------------------------------------
  def selection
    return if @disposed
    pos = SendMessage.call(@window,0xB0,0,0)
    return loword(pos),hiword(pos)
  end
  #--------------------------------------------------------------------------
  # ● 设置光标位置
  #--------------------------------------------------------------------------
  def select(*i)
    return if @disposed
    i[1] = i[0] if i.size == 1
    SendMessage.call(@window,0xB1,i[0],i[1])
  end
  #--------------------------------------------------------------------------
  # ● 获取限制
  #--------------------------------------------------------------------------
  def limit
    return if @disposed
    return SendMessage.call(@window,0xD5,0,0)
  end
  #--------------------------------------------------------------------------
  # ● 设置限制
  #--------------------------------------------------------------------------
  def limit=(i)
    return if @disposed
    SendMessage.call(@window,0xC5,i,0)
  end
  #--------------------------------------------------------------------------
  # ● 是否按下回车键
  #--------------------------------------------------------------------------
  def press_enter?
    return if @disposed
    return (@focus and Input.trigger?(Input::C) and (GetKeyState.call(13) != 0))
  end
  #--------------------------------------------------------------------------
  # ● 处理消息用
  #--------------------------------------------------------------------------
  def hiword(dword)
    return [dword].pack('L').unpack('SS')[1]
  end
  #--------------------------------------------------------------------------
  # ● 处理消息用
  #--------------------------------------------------------------------------
  def loword(dword)
    return [dword].pack('L').unpack('SS')[0]
  end
  #--------------------------------------------------------------------------
  # ● wchar -> char
  #--------------------------------------------------------------------------
  def wc2mb(text)
    ary = text.unpack('S*')
    ary.delete_at(-1)
    return ary.pack('U*')
  end
  #--------------------------------------------------------------------------
  # ● char -> wchar
  #--------------------------------------------------------------------------
  def mb2wc(text)
    return (text.unpack('U*') + [0]).pack('S*')
  end
  private :mb2wc ,:wc2mb ,:hiword ,:loword # 定义私有功能
end[/pre]输入框精灵类[pre lang="ruby"]#==============================================================================
# ■ Sprite_TextBox  by EngShun
#------------------------------------------------------------------------------
#  显示输入框用的活动块。
#==============================================================================
class Sprite_TextBox < Sprite
  #--------------------------------------------------------------------------
  # ● 设置缓存的类
  #--------------------------------------------------------------------------
  Cache = Struct.new(:bc ,:fc ,:sbc ,:sfc ,:fs ,:text ,:selection )
  #--------------------------------------------------------------------------
  # ● 定义实例变量
  #--------------------------------------------------------------------------
  attr_accessor :textbox
  attr_accessor :back_color
  attr_accessor :sel_back_color
  attr_accessor :sel_font_color
  attr_reader   :width
  attr_reader   :height
  #--------------------------------------------------------------------------
  # ● 初始化
  #--------------------------------------------------------------------------
  def initialize(x = 0,y = 0,w = 128,h = 32,bc = Color.new(255,255,255),fc = Color.new(0,0,0),sbc=Color.new(0,0,255),sfc=Color.new(255,255,255),tb = TextBox.new)
    super(nil)
    self.x = x
    self.y = y
    self.bitmap = Bitmap.new(4096,512)
    self.bitmap.font.color = fc
    @width = w
    @height = h
    self.src_rect.width = w
    self.src_rect.height = h
    if self.bitmap.font.methods.include?(:shadow)
      self.bitmap.font.shadow = false
      if self.bitmap.font.methods.include?(:outline)
        self.bitmap.font.outline = false
      end
    end
    @sel_back_color = sbc
    @sel_font_color = sfc
    @back_color = bc
    @textbox = tb
    tb.set_pos(x, y)
    @cache = Cache.new
    self.src_rect.set(0,0,w,h)
    refresh
  end
  #--------------------------------------------------------------------------
  # ● 刷新
  #--------------------------------------------------------------------------
  def update
    super
    return unless @textbox.focus
    @textbox.update
    if (self.bitmap.font.color != @cache.fc) or
       (self.bitmap.font.size != @cache.fs) or
       (@textbox.selection != @cache.selection) or
       (@sel_back_color != @cache.sbc) or
       (@sel_font_color != @cache.sfc) or
       (@textbox.text != @cache.text) or
       (@back_color != @cache.bc)
      refresh
    end
  end
  #--------------------------------------------------------------------------
  # ● 释放
  #--------------------------------------------------------------------------
  def dispose
    self.bitmap.dispose
    @textbox.dispose
    super
  end
  def width=(v)
    @width = v
    self.src_rect.width = v
    refresh
  end
  def height=(v)
    @height = v
    self.src_rect.height = v
    refresh
  end
  #--------------------------------------------------------------------------
  # ● 内容刷新
  #--------------------------------------------------------------------------
  def refresh
    @cache.fc = self.bitmap.font.color
    @cache.fs = self.bitmap.font.size
    @cache.sbc = @sel_back_color
    @cache.sfc = @sel_font_color
    @cache.text = @textbox.text
    @cache.bc = @back_color
    w = 4096
    h = @height
    self.bitmap.fill_rect(0,0,w,h,@back_color)
    self.bitmap.draw_text(4,0,w-4,h,@textbox.text)
    start = @textbox.selection.min
    _end = @textbox.selection.max
    length = _end - start
    t = @cache.text.scan(/./)[0,start].join("")
    s = self.bitmap.text_size(t).width
    if length == 0
      self.bitmap.fill_rect(s + 4, 2, 1, h-4, self.bitmap.font.color)
      if s > self.src_rect.x + @width
        self.src_rect.x = s - @width + 8
      elsif s < self.src_rect.x
        self.src_rect.x = s
      end
    else
      t2 = @cache.text.scan(/./)[start,length].join("")
      s2 = self.bitmap.text_size(t2).width
      @cache.fc = @cache.fc.clone
      self.bitmap.fill_rect(4+s,2,s2,h-4,@sel_back_color)
      self.bitmap.font.color = @sel_font_color.clone
      self.bitmap.draw_text((4 + s),0,s2,h,t2)
      self.bitmap.font.color = @cache.fc
      if start < @cache.selection.min and s < self.src_rect.x
        self.src_rect.x = s
      elsif _end > @cache.selection.max and (s + s2) > self.src_rect.x + @width
        self.src_rect.x = (s + s2) - @width + 8
      end
    end
    @cache.selection = @textbox.selection
  end
  private :refresh # 设置私有功能
end[/pre]具体就到这边了,请之前写过此类脚本的@神思来给个评语吧==
p/s:脚本整理得有些乱,请多多包涵<(_ _)>



以下提供了一个已经改好了的人物取名脚本(RMXP):
  1. #==============================================================================
  2. # ■ Scene_Name
  3. #------------------------------------------------------------------------------
  4. #  处理名称输入画面的类。
  5. #==============================================================================
  6. class Scene_Name
  7.   #--------------------------------------------------------------------------
  8.   # ● 主处理
  9.   #--------------------------------------------------------------------------
  10.   def main
  11.     @actor = $game_actors[$game_temp.name_actor_id]
  12.     @Window = Window_Base.new(0,176,640,128)
  13.     @window.contents = Bitmap.new(576,96)
  14.     @window.draw_actor_graphic(@actor, 64, 80)
  15.     @window.contents.draw_text(128,0,480,32,"请输入名称:")
  16.     @sprite_tb = Sprite_TextBox.new(144,240,464)
  17.     @sprite_tb.z = 500
  18.     @sprite_tb.textbox.limit = $game_temp.name_max_char
  19.     @sprite_tb.textbox.text = @actor.name
  20.     @sprite_tb.textbox.sel_pos = @actor.name.length
  21.     Graphics.transition
  22.     loop do
  23.       Graphics.update
  24.       Input.update
  25.       update
  26.       break if $scene != self
  27.     end
  28.     Graphics.freeze
  29.     @sprite_tb.dispose
  30.     @window.dispose
  31.   end
  32.   #--------------------------------------------------------------------------
  33.   # ● 刷新画面
  34.   #--------------------------------------------------------------------------
  35.   def update
  36.     @sprite_tb.update
  37.     if @sprite_tb.textbox.press_enter?
  38.       if @sprite_tb.textbox.text == ""
  39.         $game_system.se_play($data_system.buzzer_se)
  40.         return
  41.       end
  42.       @actor.name = @sprite_tb.textbox.text
  43.       $scene = Scene_Map.new
  44.     end
  45.   end
  46. end
复制代码
忘了最重要的==,无图无真相:
demo1.png
demo2.png <=即使全屏输入法照样显示
demo3.png    

超级免DLL输入法.zip

202.82 KB, 下载次数: 2471

评分

参与人数 4星屑 +615 赞 +12 收起 理由
yang1zhi + 8 塞糖
欧买歌 + 7 塞糖
Shy07 + 12 主站收录
Kimu + 600 发布奖励

查看全部评分

本人擅长XP,如果有脚本或者Ruby方面的问题欢迎发电邮到engshun@1ppl.me咨询,本人很少检查电邮所以不一定会及时回复,本人不会直接出手解决问题只会提供一个方向,所以谢绝伸手党
梦石
0
星屑
60
在线时间
72 小时
注册时间
2012-1-15
回帖
166
发表于 2012-7-29 15:57:05 | 显示全部楼层
想问下LZ  这个脚本确定是VA的么? 还有我不愿意中枪

点评

你看看图片上的图标  发表于 2012-8-21 19:16
这里是所有版本的原创区啊,下次你可以先看清楚标题的分类==  发表于 2012-7-31 14:02
VA 原创区 发现你的帖子 表示迷糊  发表于 2012-7-29 16:12
分类不是已经注明是RMXP了么?==  发表于 2012-7-29 16:09
回复

使用道具 举报

名侦探小柯

梦石
10
星屑
4393
在线时间
3739 小时
注册时间
2006-9-6
回帖
36595

极短27获奖MZ评测员开拓者贵宾第3届短篇游戏大赛主流游戏组亚军第5届短篇游戏比赛亚军

发表于 2012-7-29 16:42:45 | 显示全部楼层
效果很自然,就是实在想不出多少RM关于打字的需求……不包括网络聊天的话。

点评

做偽‧戀愛遊戲吧?可以自訂主角姓名...或是養成遊戲之類的  发表于 2012-7-29 18:12
不定期回归 ~ 游戏开发之旅
———————————————————————————————
回复

使用道具 举报

梦石
0
星屑
50
在线时间
212 小时
注册时间
2012-3-5
回帖
206
发表于 2012-7-29 17:31:30 | 显示全部楼层
求VA版~~

点评

对于VA对字符串的处理我已经感到无能了,所以还是期待大神吧==  发表于 2012-7-31 14:00
同求~  发表于 2012-7-30 15:46
回复

使用道具 举报

水星地球侵略

梦石
0
星屑
53
在线时间
757 小时
注册时间
2011-8-23
回帖
5206
发表于 2012-7-29 17:42:16 | 显示全部楼层
然后在下一直没想明白RubyRGSS输入法和MSDN之间有何关联……难不成MSDN上还有关于Ruby的技术文章……
回复

使用道具 举报


  • 更新完成啦
  • 梦石
    0
    星屑
    894
    在线时间
    6267 小时
    注册时间
    2006-6-7
    回帖
    8173
发表于 2012-7-29 17:51:36 | 显示全部楼层
据说用dll都是偷懒的人@灼眼的夏娜

点评

这能@到么  发表于 2012-7-31 10:46
回复

使用道具 举报

梦石
0
星屑
60
在线时间
565 小时
注册时间
2010-10-30
回帖
159
发表于 2012-7-29 18:13:51 | 显示全部楼层
看着还行吧,支持楼主下。
(ARPG)赵云突围: http://rpg.blue/thread-303844-1-1.html
(剧情向战斗)命运赌局: http://rpg.blue/thread-257144-1-1.html
(ARPG)三英战吕布: http://rpg.blue/thread-220451-1-1.html
(R剧)秋风五丈原: http://rpg.blue/thread-211306-1-1.html
回复

使用道具 举报

梦石
0
星屑
60
在线时间
156 小时
注册时间
2011-12-13
回帖
127
发表于 2012-7-30 14:55:35 | 显示全部楼层
直接把Edit窗口显示出来不是更好?

点评

……再套一个父窗口,文字和游戏窗口同级……  发表于 2012-8-20 00:19
在主窗口中加入后就成功了,非常感谢,接下来就是研究字体的设置了==  发表于 2012-7-31 22:37
其实加上WS_CLIPCHILDREN就行了  发表于 2012-7-31 18:22
调用Grahics.update后会强行隐藏所有的子窗口,不调用的话连主窗口都不刷新了==  发表于 2012-7-31 13:59

评分

参与人数 1星屑 +120 收起 理由
英顺的马甲 + 120 非常感谢

查看全部评分

回复

使用道具 举报

梦石
0
星屑
188
在线时间
3 小时
注册时间
2012-8-17
回帖
2
发表于 2012-8-18 12:00:33 | 显示全部楼层
...............
回复

使用道具 举报

梦石
0
星屑
109
在线时间
67 小时
注册时间
2007-12-16
回帖
64
发表于 2012-8-20 00:00:45 | 显示全部楼层
這腳本還是有些小瑕疵~~~
首先文字指標對多字元的反應不大正確(RUBY和WIN對雙字元判定的差異)...
除此之外如果輸入法用ENTER確認的話就...

第一個小問題咱解決了
第二個問題研究中~~~

点评

嘛,其实还有其他bug呢==  发表于 2013-5-25 10:17
回复

使用道具 举报

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

本版积分规则

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

在本版发帖返回顶部