[AHK2] 实现简单的贴图工具

发布时间 2023-09-05 12:02:44作者: 落寞的雪

介绍

  • 使用
    !` 开启左键选择区域,左键松开自动贴图。

脚本没什么难理解的地方,但有些地方使用了很好的技巧,在:

  • 实现拖动
  • 双击事件

更多功能自行探索即可。

代码

#Requires AutoHotkey v2.0
#SingleInstance Force

CoordMode 'Mouse', 'Screen'
CoordMode 'ToolTip', 'Screen'

#Include 'G:\AHK\Ahk_v2\common\Tip.ahk' ; 先前写的`更常用的ToolTip`

; '#898374'
class Config {
  static useRandomBgc := false ; NOTE: some bugs there, cannot be used against a solid color background
  static defaultBgc := '00c5cd'
  static guiOption := '+AlwaysOnTop -Caption +Border +ToolWindow'
  static guiTransparent := 160

  static singleton := false ; if true ,the gui instance will be reused
}

!`:: {
  ToolTip 'READY', 100, 50
  Hotkey 'LButton', StartClip, 'On'
  Hotkey 'Esc', Cancel, 'On'
}

Cancel(*) {
  Hotkey 'LButton', 'Off'
  Tip.ShowTip('CANCEL')
}

StartClip(*) {
  g := Config.singleton
    ? GetGui()
    : Gui(Config.guiOption)
  g.BackColor := Config.useRandomBgc
    ? GetRandomColor()
    : Config.defaultBgc
  MouseGetPos &begin_x, &begin_y
  g.Show('x' begin_x ' y' begin_y)
  WinSetTransparent(Config.guiTransparent, 'ahk_id' g.Hwnd)
  static count := 0 ; DEBUG
  while GetKeyState('LButton', 'P') {
    MouseGetPos &end_x, &end_y
    x := End_x < Begin_x ? End_x : Begin_x
    y := End_y < Begin_y ? End_y : Begin_y
    ; caculate gui size
    scope_x := Abs(begin_x - end_x)
    scope_y := Abs(begin_y - end_y)
    ToolTip count++ ; DEBUG
    g.Move(x, y, scope_x, scope_y)
  }
  Hotkey 'LButton', 'Off'
  ToolTip
  proxy := g.AddText('xp w' scope_x ' h' scope_y,)
  proxy.OnEvent('DoubleClick', (*) => WinClose('ahk_id' g.Hwnd))
  fn := MoveWin.Bind(g.Hwnd)
  proxy.OnEvent('Click', fn)
  ClipScreen(g.Hwnd)
}

MoveWin(hwnd, *) {
  MouseGetPos(&px, &py)
  WinGetPos(&wx, &wy, , , 'ahk_id' hwnd)
  dx := wx - px, dy := wy - py
  SetWinDelay -1
  While GetKeyState("LButton", "P") {
    MouseGetPos(&nx, &ny)
    WinMove(nx + dx, ny + dy, , , 'ahk_id' hwnd)
  }
}

GetGui() {
  static g := Gui(Config.guiOption)
  return g
}

GetRandomColor() {
  rx := Random(0, A_ScreenWidth)
  ry := Random(0, A_ScreenHeight)
  return Config.defaultBgc := PixelGetColor(rx, ry, 'RGB')
}

#Esc:: {
  global
  res := MsgBox('Exit?', , 0x1)
  if res != 'OK'
    return
  try ; only 'try'
    DllCall('user32.dll\ReleaseDC', 'int', 0, 'uint', hdc_frame)
  DllCall('user32.dll\ReleaseDC', 'int', 0, 'uint', hdd_frame)
  ExitApp()
}

!Esc:: {
  Tip.ShowTip('Clear all')
  for w in WinGetList('ahk_pid ' ProcessExist())
    try
      WinClose 'ahk_id' w
    catch
      MsgBox 'Error ocur on -> ' w
}

hdd_frame := DllCall("GetDC", 'UInt', 0)
hdc_frame := ''

ClipScreen(MagnifierID) {
  global hdc_frame := DllCall("GetDC", 'UInt', MagnifierID)
  ; WinSetTransparent(255, 'ahk_id' MagnifierID) ; is unnecessary
  WinSetTransColor(Config.defaultBgc, 'ahk_id' MagnifierID)
  WinGetPos(&x, &y, &Rx, &Ry, 'ahk_id' MagnifierID)

  DllCall("gdi32.dll\StretchBlt", 'UInt', hdc_frame, 'Int'
    , 0, 'Int', 0, 'Int', Rx, 'Int', Ry
    , 'UInt', hdd_frame, 'UInt', x, 'UInt', y
    , 'Int', Rx, 'Int', Ry, 'UInt', 0xCC0020) ; SRCCOPY

  ; main work is done
  Tip.ShowTip('OVER')
}