Skip to content

Commit

Permalink
Merge pull request #28 from phil294/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
phil294 committed Dec 19, 2022
2 parents 9179db3 + a7ec521 commit 86f259a
Show file tree
Hide file tree
Showing 15 changed files with 91 additions and 49 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ AHK_X11 can be used completely without a terminal. You can however if you want u
<details><summary><strong>CLICK TO SEE WHICH COMMANDS ARE IMPLEMENTED AND WHICH ARE MISSING</strong>. Note however that this is not very representative. For example, no `Gui` sub command is included in the listing. For a better overview on what is already done, skim through the <a href="https://phil294.github.io/AHK_X11"><b>FULL DOCUMENTATION HERE</b></a>.</summary>

```diff
DONE 42% (92/219):
DONE 42% (93/219):
+ Else, { ... }, Break, Continue, Return, Exit, GoSub, GoTo, IfEqual, Loop, SetEnv, Sleep, FileCopy,
+ SetTimer, WinActivate, MsgBox, Gui, SendRaw, #Persistent, ExitApp,
+ EnvAdd, EnvSub, EnvMult, EnvDiv, ControlSendRaw, IfWinExist/IfWinNotExist, SetWorkingDir,
Expand All @@ -69,7 +69,7 @@ DONE 42% (92/219):
+ WinMove, WinRestore, MouseGetPos, MouseMove, GetKeyState, KeyWait, ControlClick, WinGetText,
+ WinGetTitle, WinGetClass, PixelGetColor, CoordMode, GuiControl, ControlGetPos, ControlGetText,
+ WinGet, Input, Loop (parse a string), ToolTip, If var [not] in/contains MatchList, ControlSetText,
+ PixelSearch
+ PixelSearch, #Include

NEW 4% (8/219): (not part of spec or from a more recent version)
@@ Echo, ahk_x11_print_vars, FileRead, RegExGetPos, RegExReplace, EnvGet, @@
Expand All @@ -84,7 +84,7 @@ REMOVED 5% (12/219):
# AutoTrim: It's always Off. It would not differentiate between %a_space% and %some_var%.
# It's possible but needs significant work.

TO DO 47% (103/219): alphabetically
TO DO 47% (102/219): alphabetically
- BlockInput, ClipWait, Control, ControlFocus, ControlGet, ControlGetFocus,
- ControlMove,
- DetectHiddenText, DetectHiddenWindows, Drive, DriveGet, DriveSpaceFree,
Expand All @@ -107,7 +107,7 @@ TO DO 47% (103/219): alphabetically
- WinHide, WinMenuSelectItem, WinMinimizeAll,
- WinMinimizeAllUndo, WinSet, WinSetTitle, WinShow, WinWait, WinWaitActive,
- WinWaitClose, WinWaitNotActive, #CommentFlag, #ErrorStdOut, #EscapeChar,
- #HotkeyInterval, #HotkeyModifierTimeout, #Include, #MaxHotkeysPerInterval, #MaxMem,
- #HotkeyInterval, #HotkeyModifierTimeout, #MaxHotkeysPerInterval, #MaxMem,
- #MaxThreads, #MaxThreadsBuffer, #MaxThreadsPerHotkey, #NoTrayIcon, #WinActivateForce

Also planned, even though it's not part of 1.0.24 spec:
Expand Down Expand Up @@ -231,15 +231,15 @@ AHK_X11 is an interpreted language, not a compiled one. This means that no compi

Parsing a single line takes about 30 µs (this happens once at startup), and execution time depends on what a command does:
- `x = 1`: 70 ns (0.00000007 s)
- `FileRead, x, y.txt`: 10 µs (0.000010 s)
- `FileRead, x, y.txt`: 10 µs (0.00001 s)
- `WinGetTitle, A`: 87 µs (0.000087 s)
- `WinActivate, title`: 60 ms (0.0060 s)
- `Send, a`: 530 µs (0.00053 s)
- `Clipboard = a`: 6 ms (0.006 s)
- `SendRaw, a`: 9 ms (0.009 s) (??)
- `WinActivate, title`: 60 ms (0.06 s)
- `WinGetText`: 0-3 s (!)

You can run fine-grained performance tests with the following special hidden instruction:
You can run fine-grained benchmarks with the following special hidden instruction:

```AutoHotkey
AHK_X11_track_performance_start
Expand Down
12 changes: 7 additions & 5 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ <h2>Table of contents </h2>
<a href="#">Flow of Control</a>
<ul>
<li>
<a class="tbd" href="#h_Include.htm">#Include/#IncludeAgain</a>
<a href="#h_Include.htm">#Include/#IncludeAgain</a>
</li>
<li>
<a href="#Block.htm">Block</a>
Expand Down Expand Up @@ -805,7 +805,7 @@ <h2>Table of contents </h2>
<a href="#h_Hotstring.htm">#Hotstring</a>
</li>
<li>
<a class="tbd" href="#h_Include.htm">#Include/#IncludeAgain</a>
<a href="#h_Include.htm">#Include/#IncludeAgain</a>
</li>
<li>
<a class="tbd" href="#h_MaxHotkeysPerInterval.htm">#MaxHotkeysPerInterval</a>
Expand Down Expand Up @@ -2816,7 +2816,7 @@ <h2 class="calibre9"><span class="calibre23">The "Last Found" Window </span></h2
<td height="16" class="calibre4">Changing <a href="#Hotstrings.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">hotstring</a> options or ending characters.</td>
</tr>
<tr class="calibre3">
<td height="16" class="tbd calibre4"><a href="#h_Include.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">#Include</a></td>
<td height="16" class="calibre4"><a href="#h_Include.htm" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">#Include</a></td>
<td height="16" class="calibre4">Causes the script to behave as though the specified file's contents are present.</td>
</tr>
<tr class="calibre3">
Expand Down Expand Up @@ -5041,7 +5041,7 @@ <h2 class="calibre9"><span class="calibre23">The "Last Found" Window </span></h2
</p>
</div>
</div>
<div class="calibreMain tbd">
<div class="calibreMain">
<div class="calibreEbookContent">
<a id="h_Include.htm" href="#h_Include.htm">#</a> <h2 class="calibre17">#Include / #IncludeAgain</h2>
<hr size="2" class="calibre24" />
Expand Down Expand Up @@ -6087,10 +6087,12 @@ <h2 class="calibre9"><span class="calibre23">The "Last Found" Window </span></h2
<p class="calibre8">1: Prevent unmodified keys<br class="calibre12" /> 2: Prevent Shift-only keys <br class="calibre12" /> 4: Prevent Control-only keys <br class="calibre12" /> 8: Prevent Alt-only keys<br class="calibre12" /> 16: Prevent Shift-Control keys <br class="calibre12" /> 32: Prevent Shift-Alt keys <br class="calibre12" /> 64: This value is not supported (it will not behave correctly).<br class="calibre12" /> 128: Prevent Shift-Control-Alt keys.</p>
<p class="calibre8">For example, Limit1 would prevent unmodified hotkeys such as letters and numbers from being entered, and Limit15 would require at least two modifier keys. If the user types a forbidden modifier combination, the Control+Alt combination is visibly and automatically substituted.</p>
<p class="calibre8">The Hotkey control has limited capabilities. For example, it does not support mouse/joystick hotkeys or the Windows key (LWin and RWin). One way to work around this is to provide one or more <a href="#Gui.htm__CheckBox" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">checkboxes</a> as a means for the user to enable extra modifiers such as the Windows key.</p>
</div>
<p class="calibre8"><br class="calibre12" />
<strong class="calibre14"><span class="calibre30"><a id="Gui.htm__Picture" href="#Gui.htm__Picture" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">#</a> Picture</span></strong> (or <strong class="calibre14"><span class="calibre30">Pic</span></strong>): An area containing an image (see last paragraph for supported file types). The <em class="calibre21">Text</em> parameter is the filename of the image, which is assumed to be in <a href="#Variables.htm__WorkingDir" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">%A_WorkingDir%</a> if an absolute path isn't specified. To retain the image's actual width and/or height, omit the W and/or H options. Otherwise, the image is scaled to the specified width and/or height. To shrink or enlarge the image while preserving its aspect ratio, specify -1 for one of the dimensions and a positive number for the other. For example, specifying "w200 h-1" would make the image 200 pixels wide and cause its height to be set automatically. If the picture cannot be loaded or displayed (e.g. file not found), the control is left empty and its height and width are set to zero.
<strong class="calibre14"><span class="calibre30"><a id="Gui.htm__Picture" href="#Gui.htm__Picture" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">#</a> Picture</span></strong> (or <strong class="calibre14"><span class="calibre30">Pic</span></strong>): An area containing an image (see last paragraph for supported file types). The <em class="calibre21">Text</em> parameter is the filename of the image, which is assumed to be in <a href="#Variables.htm__WorkingDir" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">%A_WorkingDir%</a> if an absolute path isn't specified. <span class="tbd">To retain the image's actual width and/or height, omit the W and/or H options. Otherwise, the image is scaled to the specified width and/or height. To shrink or enlarge the image while preserving its aspect ratio, specify -1 for one of the dimensions and a positive number for the other. For example, specifying "w200 h-1" would make the image 200 pixels wide and cause its height to be set automatically. If the picture cannot be loaded or displayed (e.g. file not found), the control is left empty and its height and width are set to zero.</span>
</p>
<p class="calibre8">To use a picture as a background for other controls, the picture should normally be added prior to those controls. However, if those controls are input-capable and the picture has a <a href="#Gui.htm__label" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">g-label</a>, create the picture after the other controls and include +0x4000000 (which is WS_CLIPSIBLINGS) in the picture's <em class="calibre21">Options</em>. This trick also allows a picture to be the background behind a Tab control.</p>
<div class="tbd">
<p class="calibre8"><strong class="calibre14">Icons and cursors</strong>: In v1.0.24, icons (.ico), cursors (.cur), and animated cursors (.ani) are supported on all operating systems. In addition, icons can be loaded from EXE and DLL files that contain them. To use an icon other than the first one in the file, include in <em class="calibre21">Options</em> the word Icon followed by the number of the icon. In the following example, the second icon would be used: <em class="calibre21">Gui, Add, Picture, Icon2, C:\My Application.exe</em>. Note: Specifying an icon number causes a different icon loading method to be used, which might prevent a .ani file from being animated. It also prevents AltSubmit (see next paragraph) from taking effect.</p>
<p class="calibre8"><a id="Gui.htm__PicAltSubmit" href="#Gui.htm__PicAltSubmit" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">#</a> Specifying the word AltSubmit in <em class="calibre21">Options</em> tells the program to use Microsoft's GDIPlus.dll to load the image, which might result in a different appearance for certain types of images. For example, it would load an icon containing a transparent background as a transparent bitmap, which allows the <a href="#Gui.htm__BackgroundTrans" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">BackgroundTrans</a> option to take effect for such an icon. If GDIPlus is not available (see next paragraph), AltSubmit is ignored and the image is loaded using the normal method.</p>
<p class="calibre8">All operating systems support GIF, JPG, and BMP images. With AutoHotkey v1.0.22+ running on Windows XP or later, additional image formats such as PNG, TIF, ICO, Exif, WMF, and EMF are supported. Operating systems older than XP can be given support by copying Microsoft's free GDI+ DLL into the AutoHotkey.exe folder (but in the case of a <a href="#Scripts.htm__ahk2exe" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">compiled script</a>, copy the DLL into the script's folder). To download the DLL, search for the following phrase at <a href="http://www.microsoft.com" class="pcalibre3 pcalibre1 pcalibre calibre5 pcalibre2">www.microsoft.com</a>: gdi redistributable.</p>
Expand Down
2 changes: 1 addition & 1 deletion shard.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: ahk_x11
version: 0.3.0
version: 0.4.1

authors:
- Philip Waritschlager <[email protected]>
Expand Down
16 changes: 16 additions & 0 deletions src/build/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module Build

@block_comment = false
@hotstring_default_options = ""
@already_included = [] of Path

def parse_into_cmds!(lines : Indexable(String))
@cmds.clear
Expand Down Expand Up @@ -90,6 +91,21 @@ module Build
@hotstring_default_options = args.strip
end
elsif first_word == "#requires" # noop for ahk discord bot. Command is v1.1.33+.
elsif first_word.starts_with?("#include")
path = Path[args].expand
if first_word != "#includeagain"
return if @already_included.includes?(path)
end
@already_included << path
i = -1
File.new(path).each_line do |line|
i += 1
begin
add_line line, i
rescue e
raise Exception.new ((e.message || "") + "\n#Include line: #{i}"), e.cause
end
end
elsif line.starts_with?("#!") && line_no == 0 # hashbang
elsif first_word == "if"
split = args.split(/ |\n/, 3, remove_empty: true)
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/base.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module Cmd
# runner can be accessed via `thread.runner`.
# When `class.conditional`, the return value determines the next branch.
# When `class.sets_error_level`, the thread's `ErrorLevel` will be set
# to the return value .
# to the return value.
# In all other cases, the return value is ignored.
abstract def run(thread, args)

Expand Down
17 changes: 10 additions & 7 deletions src/cmd/gtk/gui/gui-add.cr
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,6 @@ class Cmd::Gtk::Gui::GuiAdd < Cmd::Base
thread.runner.display.gui.gui(thread, gui_id, no_wait: true) do |gui|
widget : ::Gtk::Widget? = nil
case type.downcase
when "text"
widget = ::Gtk::Label.new text
widget.has_window = true
widget.events = ::Gdk::EventMask::BUTTON_PRESS_MASK.to_i
widget.connect "button-press-event", run_g_label
when "edit"
if opt["r"]?.try &.[:n].try &.> 1
widget = ::Gtk::ScrolledWindow.new vexpand: true, hexpand: false, shadow_type: ::Gtk::ShadowType::IN
Expand All @@ -48,7 +43,7 @@ class Cmd::Gtk::Gui::GuiAdd < Cmd::Base
when "button" # TODO: "default" stuff from docs
widget = ::Gtk::Button.new label: text
widget.connect "clicked", run_g_label
button_click_label = "button" + text.gsub(/[ &\n\r]/, "")
button_click_label = "button" + text.gsub(/[ &\n\r]/, "").downcase
widget.on_clicked do
begin runner.add_thread button_click_label, 0
rescue
Expand All @@ -69,8 +64,16 @@ class Cmd::Gtk::Gui::GuiAdd < Cmd::Base
end
widget.active = (opt["choose"][:n] || 1) - 1 if opt["choose"]?
widget.connect "changed", run_g_label
when "picture", "pic"
widget = ::Gtk::Image.new_from_file text
widget.has_window = true
widget.events = ::Gdk::EventMask::BUTTON_PRESS_MASK.to_i
widget.connect "button-press-event", run_g_label
else
raise Run::RuntimeException.new "Unknown Gui control '#{type}'"
widget = ::Gtk::Label.new text
widget.has_window = true
widget.events = ::Gdk::EventMask::BUTTON_PRESS_MASK.to_i
widget.connect "button-press-event", run_g_label
end

widget.override_background_color(::Gtk::StateFlags::NORMAL, gui.control_color) if gui.control_color
Expand Down
16 changes: 11 additions & 5 deletions src/cmd/misc/run.cr
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Cmd::Misc::Run < Cmd::Base
end

success = false
stdout = stderr = ""

# TODO: This only sets up the dialog but the printing logic is missing. Not sure
# how to implement the draw_page callback for arbitrary file types, so I disabled
Expand All @@ -53,6 +54,10 @@ class Cmd::Misc::Run < Cmd::Base
# success = ...
# end

if edit
success, stdout, stderr = try_execute("gtk-launch \"$(xdg-mime query default text/plain)\" '#{target}'", chdir: pwd, stdout: !!output_stdout, stderr: !!output_stderr)
end

thread.runner.display.gui.act do
begin
if target.starts_with?("www.")
Expand All @@ -66,17 +71,18 @@ class Cmd::Misc::Run < Cmd::Base

if ! success && open
success, stdout, stderr = try_execute(target, chdir: pwd, stdout: !!output_stdout, stderr: !!output_stderr)
if success
thread.runner.set_user_var(output_stdout, stdout) if output_stdout
thread.runner.set_user_var(output_stderr, stderr) if output_stderr
end
end

if ! success
path = ::File.expand_path(target)
success = try_execute("xdg-open " + path) && ""
end

if success
thread.runner.set_user_var(output_stdout, stdout) if output_stdout && ! output_stdout.empty?
thread.runner.set_user_var(output_stderr, stderr) if output_stderr && ! output_stderr.empty?
end

if opt["useerrorlevel"]?
thread.set_thread_built_in_static_var("ErrorLevel", success ? "0" : "ERROR")
else
Expand All @@ -87,7 +93,7 @@ class Cmd::Misc::Run < Cmd::Base
end
end

if output_var_pid && ! @wait && success.is_a?(Int64)
if output_var_pid && ! output_var_pid.empty? && ! @wait && success.is_a?(Int64)
thread.runner.set_user_var(output_var_pid, success.to_s)
end
end
Expand Down
7 changes: 5 additions & 2 deletions src/cmd/x11/keyboard/input.cr
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ class Cmd::X11::Keyboard::Input < Cmd::Base
timeout = nil
visible = false
match_anywhere = false
ignore_generated_input = false
thread.parse_letter_options(args[1]? || "") do |c, n|
case c
when 'b' then ignore_backspace = true
when 'c' then case_sensitive = true
when 'i' then ignore_generated_input = true
when 'l' then max = n.try &.to_i || 1
when 't' then timeout = n
when 'v' then visible = true
Expand All @@ -46,8 +48,9 @@ class Cmd::X11::Keyboard::Input < Cmd::Base
end

buf = ""
listener = thread.runner.display.register_key_listener do |key_event, keysym, char| # TODO: inconsistency: KeyEvent/char vs. KeyCombination.key_name
next if key_event.type != ::X11::KeyRelease
listener = thread.runner.display.register_key_listener do |key_event, keysym, char, is_paused| # TODO: inconsistency: KeyEvent/char vs. KeyCombination.key_name
next if is_paused && ignore_generated_input
next if key_event.type != ::X11::KeyPress
end_key = end_keys.find { |k| k.keysym == keysym }
if end_key
next channel.send("EndKey:#{end_key.key_name}")
Expand Down
17 changes: 11 additions & 6 deletions src/cmd/x11/mouse/mouse-click.cr
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,17 @@ class Cmd::X11::Mouse::MouseClick < Cmd::Base
when "xbutton2", "x2" then XDo::Button::Button9
else XDo::Button::Left
end
x_current, y_current, screen = thread.runner.display.x_do.mouse_location
x = args[1]?.try &.to_i? || x_current
y = args[2]?.try &.to_i? || y_current
current_x, current_y, screen = thread.runner.display.x_do.mouse_location
x = args[1]?.try &.to_i?
y = args[2]?.try &.to_i?
if x && y
if thread.settings.coord_mode_mouse == ::Run::CoordMode::RELATIVE
x, y = Cmd::X11::Window::Util.coord_relative_to_screen(thread, x, y)
end
else
x = current_x
y = current_y
end
count = args[3]?.try &.to_i? || 1
up = down = false
case args[5]?.try &.downcase
Expand All @@ -26,9 +34,6 @@ class Cmd::X11::Mouse::MouseClick < Cmd::Base
if relative
thread.runner.display.x_do.move_mouse x, y
else
if thread.settings.coord_mode_mouse == ::Run::CoordMode::RELATIVE
x, y = Cmd::X11::Window::Util.coord_relative_to_screen(thread, x, y)
end
thread.runner.display.x_do.move_mouse x, y, screen
end
thread.runner.display.x_do.mouse_down button if ! up
Expand Down
7 changes: 3 additions & 4 deletions src/run/display.cr
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,14 @@ module Run

# TODO: put keysym and char into key_event in callers?
private def handle_event(key_event, keysym, char)
return if @is_paused
@key_listeners.each do |sub|
spawn same_thread: true do
sub.call(key_event, keysym, char)
sub.call(key_event, keysym, char, @is_paused)
end
end
end
@key_listeners = [] of Proc(::X11::KeyEvent, UInt64, Char?, Nil)
def register_key_listener(&block : ::X11::KeyEvent, UInt64, Char? -> _)
@key_listeners = [] of Proc(::X11::KeyEvent, UInt64, Char?, Bool, Nil)
def register_key_listener(&block : ::X11::KeyEvent, UInt64, Char?, Bool -> _)
@key_listeners << block
block
end
Expand Down
7 changes: 4 additions & 3 deletions src/run/display/hotkeys.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ module Run
end

def run
@runner.display.register_key_listener do |key_event, keysym, char|
handle_event(key_event, keysym, char)
@runner.display.register_key_listener do |key_event, keysym, char, is_paused|
handle_event(key_event, keysym, char, is_paused)
end
@runner.display.on_pause { pause }
@runner.display.on_suspend { resume }
Expand Down Expand Up @@ -62,7 +62,8 @@ module Run
hotkey
end

def handle_event(key_event, keysym, char)
def handle_event(key_event, keysym, char, is_paused)
return if is_paused
up = key_event.type == ::X11::KeyRelease || key_event.type == ::X11::ButtonRelease # TODO: externalize somehow because this is duplicate in various places

hotkey = @hotkeys.find do |hotkey|
Expand Down
Loading

0 comments on commit 86f259a

Please sign in to comment.