Jump to content
Macro Express Forums

acantor

Members
  • Posts

    1,534
  • Joined

  • Last visited

  • Days Won

    18

Everything posted by acantor

  1. You will need to define every variable you plan to input into the script. You can define dozens or hundreds of variables, if you want. All of those variables shouldn't impact performance significantly. This script accepts variables "a", "b", and "chrome" only: Variable Set String %a% to "" Variable Set String %b% to "" Variable Set String %chrome% to "" Variable Set String %VariableName%: Prompt If Variable %VariableName% Equals "a" OR If Variable %VariableName% Equals "b" OR If Variable %VariableName% Equals "chrome" Variable Set String %%VariableName%% to topmost window title Text Box Display: Values Else MessageBox: Can't use this as a variable! End If <VARIABLE SET STRING Option="\x00" Destination="%a%" NoEmbeddedVars="FALSE"/> <VARIABLE SET STRING Option="\x00" Destination="%b%" NoEmbeddedVars="FALSE"/> <VARIABLE SET STRING Option="\x00" Destination="%chrome%" NoEmbeddedVars="FALSE"/> <COMMENT/> <VARIABLE SET STRING Option="\x01" Destination="%VariableName%" Prompt="What is the name of the variable?" Mask="FALSE" OnTop="TRUE" Left="Center" Top="Center" Monitor="0"/> <COMMENT/> <IF VARIABLE Variable="%VariableName%" Condition="\x00" Value="a" IgnoreCase="TRUE"/> <OR/> <IF VARIABLE Variable="%VariableName%" Condition="\x00" Value="b" IgnoreCase="TRUE"/> <OR/> <IF VARIABLE Variable="%VariableName%" Condition="\x00" Value="chrome" IgnoreCase="TRUE"/> <VARIABLE SET STRING Option="\x05" Destination="%%VariableName%%"/> <TEXT BOX DISPLAY Title="Values" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Tahoma;}{\\f1\\fnil Tahoma;}}\r\n\\viewkind4\\uc1\\pard\\lang4105\\f0\\fs20 VariableName = %VariableName%\r\n\\par \r\n\\par %a%\r\n\\par %b%\r\n\\par %chrome%\\lang1033\\f1\\fs14 \r\n\\par }\r\n" Left="821" Top="Center" Width="871" Height="200" Monitor="0" OnTop="TRUE" Keep_Focus="TRUE" Mode="\x00" Delay="0"/> <ELSE/> <MESSAGEBOX Caption="Can't use this as a variable!" Message="You must specify \"a,\" \"b,\" or \"chrome,\" not \"%VariableName%\" " Icon="4"/> <END IF/>
  2. For at least one badly-behaved app that I've automated, I was forced to Tab (or Shift+Tab) 10, 15, 20, maybe 25 times to reach some targets. It wasn't ideal, but the macros worked reliably.
  3. I don't think that there is a way to export the contents of the "Notes" tab. Consider submitting a feature request to the folks at Insight Software. But comments that I embed in scripts are exported. I know two different ways of embedding comments in scripts: the comment appears on a line by itself, and the comment appears at the end of the instruction: // Comment Type 1 Variable Set String %Clip% from the clipboard contents // Comment Type 2 After importing scripts that I've exported this way, the comments are present. I believe there is a third way to embed comments in Macro Express scripts, but I don't remember how to do it, so can't try!
  4. I mentioned in my previous post that I typically use pixel colour searches to find and click on neutral zones. But there are times it's better to monitor changes in the shape of the mouse pointer. Mouse pointer changes have always been slower than pixel colour searches, but in Windows 10, they are especially molasses-like. Yet the technique can still be made to work by inserting delays, and by increasing the interval between mouse moves. In this example, the macro checks the mouse cursor every 50 pixels until it changes to the "Internet Navigate" cursor. // Hunt for "Account Manager" button Repeat Start (Repeat 10 times) If Mouse Cursor: Internet Navigate Mouse Left Click Delay: 100 milliseconds // Allow time for the "Sign out" button to appear Repeat Exit End If Mouse Move: 0, 50 Relative to Last Position Delay: 50 milliseconds // Allow time for the mouse cursor to settle in its new location End Repeat
  5. When I export macros that include comments, the comments are exactly where they were after I import them. When I export macro information to a text file, the comments are there.
  6. An approach that I use for especially nasty web applications involves identifying a "neutral zone" that when clicked, one or several presses of the Tab key (or Shift + Tab) gives focus to a link or control that is close to where I'm trying to get. Neutral areas are sometimes quite large (although not every web app has one). The only way I know to discover neutral zones is through trial and error experimentation. It's hard to tell from looking at the page. When I'm looking for one, I click everywhere on the screen where nothing is clickable, and then press the Tab key and Shift + Tab. If there is a neutral zone, the focus always goes to the same object on the page that is close to where I want to go. So a script might do something like this to get to the target: 1. Find the neutral zone. 2. Click. 3. Tab Tab Tab Tab Tab I frequently find a neutral zone near the left margin of a webpage. (But not in Outlook.com's Inbox; but there is a large neutral zone underneath the list of messages. When the message list extends to the bottom of the screen, I find that I need to decrease page magnification, sometimes significantly, to be able to click in the area below all messages.) These neutral zones tend to be large, so knowing the exact pixel is not important. I typically use pixel colour searches to zero in on them, sometimes checking every 50 or 100 pixels, which I find is fast enough. Here's an excerpt from a Macro Express script for a web app. The macro searches diagonally south-east in 100 pixel increments for a white pixel. Repeat Start (Repeat 100 times) // First, search diagonally from the top left corner of the window for a white pixel Get Pixel Color from Beneath the Mouse into %PixelColour% If Variable %PixelColour% Equals "16777215" // We have reached a white pixel, which is hopefully within the white box in the Sign In window Repeat Exit End If Mouse Move: 100, 100 Relative to Last Position End Repeat Mouse Left Click In summary, sometimes a single, strategic click can get you close to your target, and then you can Tab or Shift + Tab the rest of the way to the target. Macros that ferret out neutral zones tend to be complex, clunky, and hard to maintain. I avoid them if there are alternatives. But sometimes there are no alternatives. Unfortunately, not every web app has neutral zones. And if that's the case, although automating a task with macros might be possible, it's probably not going to be easy!
  7. On 25 May 2021, I’ll be teaching a three-hour long hands-on course (over Zoom) on software customization at the Guelph Accessibility Conference. The tools we will be learning about are Macro Express, AutoHotkey, and Microsoft Office customization techniques. You can register for my course without registering for the conference. The fee for my course is $135 (Canadian dollars). Introduction to Software Customization for Windows 25 May, 1 - 4 p.m. Eastern Time Taught over Zoom Overview Many applications have features that people with disabilities have difficulty accessing — or cannot access. During this hands-on session, we actually repair accessibility and usability failures. By modifying the behaviour of keyboards, mice, and programs, we "tailor" solutions to better fit the physical, cognitive, and learning needs of individuals. Topics - Macro software - Keyboard remapping - Mouse modifications - Shortcut techniques Objectives Participants will: - Understand macros basics. - Know the steps to create Macro Express scripts, activate them, and set their "scope" (so a macro is recognized in only one program). - Know how to use AutoHotkey to remap keys or mouse buttons. - Know how to add a hotkey to any Microsoft Office application, and assign a hotkey to any feature in Microsoft Word in two ways. Register Register for the Guelph Accessibility Conference
  8. If Variable %all% Contains "%part%" Text Box Display: Yes! Else Text Box Display: No! End If
  9. There are many ways to test for evenness / oddness, including this: Variable Set Decimal %Value%: Prompt Variable Modify Decimal: %HalfValue% = %Value% / 2 Variable Modify Decimal %HalfValue%: Remove Integer Portion (%DecimalsOnly%) If Variable %DecimalsOnly% Equals "0" Text Box Display: Even Else Text Box Display: Odd End If
  10. I've enhanced the main script. (The "Capitalize Engine" script is the same. See code in previous message.) Updates: 1. This version is less "flashy" -- text is selected and de-selected more quickly. 2. It runs a little faster. 3. This version checks for non-letters that "cling" to words, like commas, colons, open and close quotes, question marks, etc., and makes an educated guess on which word to case-rotate. 4. Although the original challenge was to case rotate an unselected word, this script acts on the first word in a selection. It would be nice if the script were to act on every word in a selection, but that's not something I plan to take on. Maybe it can be done with RegEx?? // Case-rotate an unselected word: lowercase ... Titlecase ... UPPERCASE ... back to lowercase ... etc. // The cursor returns to its pre-capitalized location. // LIMITATIONS: // 1. Unreliable in Notepad when non-letters cling to words: Hello. "Hello" Hello! etc. // 2. Doesn't handle "non-standard" punctuation, symbols, and spacing. // 3. Runs a bit slowly! // 4. Although not intended for selections, the macro will act on the first word in a block of text. // HOW IT WORKS: // 0. Check if text is selected. If yes, de-select and act on first word. // 1. Inspect one character to the left of the cursor, and one character to the right of the cursor. // 2. If the left character = "", the cursor is at the start of the document/field. Select right one word. // 3. If the right character = "", the cursor is at the end of the document/field. Select left one word. // 4. If Letter + Letter, the cursor is in the middle of the word. // Select left to start of the word to determine cursor position. Then select right one word. // 5. If Letter + Non-letter, the cursor is at the end of the word. Select left one word. // 6. If Non-letter + Letter, the cursor is at the start of the word. Select right one word. // 7. If Non-letter + Non-letter, take a guess which word to select based on normal punctuation rules. // 8. Transform the capitalization of the selected word. (Handled by a separate, called macro.) // Check if text is selected. If yes, de-select and act on first word in the selection. Clipboard Empty Text Type (Simulate Keystrokes): <CONTROL>c Variable Set String %Clip% from the clipboard contents Variable Set Integer %ClipLength% to the length of variable %Clip% If Variable %ClipLength% Is Greater Than "0" Text Type (Simulate Keystrokes): <ARROW LEFT><CONTROL><ARROW RIGHT> End If // Inspect character to left Clipboard Empty Text Type (Simulate Keystrokes): <SHIFT><ARROW LEFT><CONTROL>c<ARROW RIGHT> Variable Set String %CharLeft% from the clipboard contents // Inspect character to right Clipboard Empty Text Type (Simulate Keystrokes): <SHIFT><ARROW RIGHT><CONTROL>c<ARROW LEFT> Variable Set String %CharRight% from the clipboard contents // Cursor is at the start of the document/field? If Variable %CharLeft% Equals "" Text Type (Simulate Keystrokes): <ARROW LEFT><CONTROL><SHIFT><ARROW RIGHT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position Text Type (Simulate Keystrokes): <CONTROL><ARROW LEFT> Macro Stop End If // Cursor is at the end of the document/field? If Variable %CharRight% Equals "" Text Type (Simulate Keystrokes): <ARROW RIGHT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position (nothing to do) Macro Stop End If Variable Set String %Letters% to "abcdefghijklmnopqrstuvwxyz" // Cursor is in the middle of a word? (Letter + Letter) If Variable %Letters% Contains "%CharLeft%" AND If Variable %Letters% Contains "%CharRight%" Text Type (Simulate Keystrokes): <ARROW RIGHT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c<ARROW LEFT> Variable Set String %WordLeft% from the clipboard contents Variable Set Integer %Offset% to the length of variable %WordLeft% Variable Modify Integer: %Offset% = %Offset% - 1 Text Type (Simulate Keystrokes): <SHIFT><CONTROL><ARROW RIGHT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position (from start of word, move right to the initial position within the word) Text Type (Simulate Keystrokes): <CONTROL><ARROW LEFT> Repeat Start (Repeat %Offset% times) Text Type (Simulate Keystrokes): <ARROW RIGHT> End Repeat Macro Stop End If // Cursor is at the start of a word? (Non-letter + Letter) If Variable %Letters% Does not Contain "%CharLeft%" AND If Variable %Letters% Contains "%CharRight%" Text Type (Simulate Keystrokes): <CONTROL><SHIFT><ARROW RIGHT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position Text Type (Simulate Keystrokes): <CONTROL><ARROW LEFT> Macro Stop End If // Cursor is at the end of a word? (Letter + Non-letter) If Variable %Letters% Contains "%CharLeft%" AND If Variable %Letters% Does not Contain "%CharRight%" Text Type (Simulate Keystrokes): <CONTROL><SHIFT><ARROW LEFT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position (nothing to do) Macro Stop End If // Cursor is in an ambigous location? (Non-letter + Non-letter) If Variable %Letters% Does not Contain "%CharLeft%" AND If Variable %Letters% Does not Contain "%CharRight%" // Make a guess which word to act upon based on normal punctuation rules. Variable Set String %Punc% to ",./<>?;:'"[{]}!@#$%^&*()-_=+\|" // If %CharLeft% is punctuation, act on previous word If Variable %Punc% Contains "%CharLeft%" Text Type (Simulate Keystrokes): <ARROW LEFT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position Text Type (Simulate Keystrokes): <ARROW RIGHT> Macro Stop End If // If %CharRight% is punctuation, act on next word If Variable %Punc% Contains "%CharRight%" Text Type (Simulate Keystrokes): <ARROW RIGHT><CONTROL><SHIFT><ARROW RIGHT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position Text Type (Simulate Keystrokes): <CONTROL><ARROW LEFT><ARROW LEFT> End If Macro Stop End If <COMMENT Value="Case-rotate an unselected word: lowercase ... Titlecase ... UPPERCASE ... back to lowercase ... etc. "/> <COMMENT Value="The cursor returns to its pre-capitalized location."/> <COMMENT/> <COMMENT Value="LIMITATIONS:" _BACK="0080FFFF"/> <COMMENT Value="1. Unreliable in Notepad when non-letters cling to words: Hello. \"Hello\" Hello! etc."/> <COMMENT Value="2. Doesn't handle \"non-standard\" punctuation, symbols, and spacing."/> <COMMENT Value="3. Runs a bit slowly!"/> <COMMENT Value="4. Although not intended for selections, the macro will act on the first word in a block of text."/> <COMMENT/> <COMMENT Value="HOW IT WORKS:" _BACK="0080FFFF"/> <COMMENT Value="0. Check if text is selected. If yes, de-select and act on first word."/> <COMMENT Value="1. Inspect one character to the left of the cursor, and one character to the right of the cursor."/> <COMMENT Value="2. If the left character = \"\", the cursor is at the start of the document/field. Select right one word."/> <COMMENT Value="3. If the right character = \"\", the cursor is at the end of the document/field. Select left one word."/> <COMMENT Value="4. If Letter + Letter, the cursor is in the middle of the word. "/> <COMMENT Value=" Select left to start of the word to determine cursor position. Then select right one word."/> <COMMENT Value="5. If Letter + Non-letter, the cursor is at the end of the word. Select left one word."/> <COMMENT Value="6. If Non-letter + Letter, the cursor is at the start of the word. Select right one word."/> <COMMENT Value="7. If Non-letter + Non-letter, take a guess which word to select based on normal punctuation rules. "/> <COMMENT Value="8. Transform the capitalization of the selected word. (Handled by a separate, called macro.)"/> <COMMENT/> <COMMENT Value="Check if text is selected. If yes, de-select and act on first word in the selection."/> <CLIPBOARD EMPTY/> <TEXT TYPE Action="0" Text="<CONTROL>c"/> <VARIABLE SET STRING Option="\x02" Destination="%Clip%" NoEmbeddedVars="FALSE"/> <VARIABLE SET INTEGER Option="\x0D" Destination="%ClipLength%" Text_Variable="%Clip%"/> <IF VARIABLE Variable="%ClipLength%" Condition="\x03" Value="0" IgnoreCase="FALSE"/> <TEXT TYPE Action="0" Text="<ARROW LEFT><CONTROL><ARROW RIGHT>"/> <END IF/> <COMMENT/> <COMMENT Value="Inspect character to left"/> <CLIPBOARD EMPTY/> <TEXT TYPE Action="0" Text="<SHIFT><ARROW LEFT><CONTROL>c<ARROW RIGHT>"/> <VARIABLE SET STRING Option="\x02" Destination="%CharLeft%" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="Inspect character to right"/> <CLIPBOARD EMPTY/> <TEXT TYPE Action="0" Text="<SHIFT><ARROW RIGHT><CONTROL>c<ARROW LEFT>"/> <VARIABLE SET STRING Option="\x02" Destination="%CharRight%" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="Cursor is at the start of the document/field?"/> <IF VARIABLE Variable="%CharLeft%" Condition="\x00" IgnoreCase="FALSE"/> <TEXT TYPE Action="0" Text="<ARROW LEFT><CONTROL><SHIFT><ARROW RIGHT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position" _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<CONTROL><ARROW LEFT>"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Cursor is at the end of the document/field?"/> <IF VARIABLE Variable="%CharRight%" Condition="\x00" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position (nothing to do)" _BACK="0080FFFF"/> <MACRO STOP/> <END IF/> <COMMENT/> <VARIABLE SET STRING Option="\x00" Destination="%Letters%" Value="abcdefghijklmnopqrstuvwxyz" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="Cursor is in the middle of a word? (Letter + Letter)"/> <IF VARIABLE Variable="%Letters%" Condition="\x06" Value="%CharLeft%" IgnoreCase="TRUE"/> <AND/> <IF VARIABLE Variable="%Letters%" Condition="\x06" Value="%CharRight%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c<ARROW LEFT>"/> <VARIABLE SET STRING Option="\x02" Destination="%WordLeft%" NoEmbeddedVars="FALSE"/> <VARIABLE SET INTEGER Option="\x0D" Destination="%Offset%" Text_Variable="%WordLeft%"/> <VARIABLE MODIFY INTEGER Option="\x01" Destination="%Offset%" Value1="%Offset%" Value2="1"/> <TEXT TYPE Action="0" Text="<SHIFT><CONTROL><ARROW RIGHT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position (from start of word, move right to the initial position within the word)" _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<CONTROL><ARROW LEFT>"/> <REPEAT START Start="1" Step="1" Count="%Offset%" Save="FALSE"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT>"/> <END REPEAT/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Cursor is at the start of a word? (Non-letter + Letter)"/> <IF VARIABLE Variable="%Letters%" Condition="\x07" Value="%CharLeft%" IgnoreCase="TRUE"/> <AND/> <IF VARIABLE Variable="%Letters%" Condition="\x06" Value="%CharRight%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<CONTROL><SHIFT><ARROW RIGHT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position" _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<CONTROL><ARROW LEFT>"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Cursor is at the end of a word? (Letter + Non-letter)"/> <IF VARIABLE Variable="%Letters%" Condition="\x06" Value="%CharLeft%" IgnoreCase="TRUE"/> <AND/> <IF VARIABLE Variable="%Letters%" Condition="\x07" Value="%CharRight%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<CONTROL><SHIFT><ARROW LEFT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position (nothing to do)" _BACK="0080FFFF"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Cursor is in an ambigous location? (Non-letter + Non-letter)"/> <IF VARIABLE Variable="%Letters%" Condition="\x07" Value="%CharLeft%" IgnoreCase="TRUE"/> <AND/> <IF VARIABLE Variable="%Letters%" Condition="\x07" Value="%CharRight%" IgnoreCase="TRUE"/> <COMMENT Value="Make a guess which word to act upon based on normal punctuation rules."/> <VARIABLE SET STRING Option="\x00" Destination="%Punc%" Value=",./<>?;:'\"[{]}!@#$%^&*()-_=+\\|" NoEmbeddedVars="TRUE"/> <COMMENT/> <COMMENT Value="If %CharLeft% is punctuation, act on previous word"/> <IF VARIABLE Variable="%Punc%" Condition="\x06" Value="%CharLeft%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW LEFT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position" _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT>"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="If %CharRight% is punctuation, act on next word"/> <IF VARIABLE Variable="%Punc%" Condition="\x06" Value="%CharRight%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT><CONTROL><SHIFT><ARROW RIGHT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position" _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<CONTROL><ARROW LEFT><ARROW LEFT>"/> <END IF/> <MACRO STOP/> <END IF/> <COMMENT/>
  11. The core of Terry's many excellent suggestions, I would say, is to simplify what you are trying to do. To that end, temporarily take the mouse buttons out of the equation. Instead, make sure your Macro Express script works if you activate it via hotkey. Add a line of code to the start of your script to make it easier to tell that your script is getting activated. (This is for testing purposes only. You will be able to get rid of it soon.) Text Box Display: Yes, the macro has been activated! <TEXT BOX DISPLAY Title="Yes, the macro has been activated!" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil Tahoma;}}\r\n\\viewkind4\\uc1\\pard\\f0\\fs14 \r\n\\par }\r\n" Left="Center" Top="Center" Width="278" Height="200" Monitor="0" OnTop="TRUE" Keep_Focus="TRUE" Mode="\x00" Delay="0"/> Once you've saved the macro, move the mouse pointer to the desired location. But instead of pressing a mouse button, press the hotkey. Is the macro activating? It would help if you were to post your script in the forum.
  12. The solution to this challenge is more challenging to achieve than I anticipated. (When I originally posted it, my solution was flawed. For example, the first and last word of a document must be handled differently than words in the middle.) The difficulties relate to the rules I set out, which I erroneously imagined would simplify matters! 1. Rotate a word through three states: lowercase ... Titlecase ... UPPERCASE ... lowercase etc. 2. The word is NOT selected. This means the macro must somehow capture a word without knowing where the word starts and where the word ends. 3. After changing the capitalization of the word, the cursor should be in the same location as it was before. When the cursor is in the middle of a word, I needed more code. 4. This macro should work in any application. I abandoned the fourth rule after realizing how different the selection process is in different applications, especially when punctuation and white space (e.g., tabs, spaces, carriage returns) are involved. The selection rules in Notepad are bizarre and unlike other applications. I optimized the script for WordPad, although it seems to work in every application I tried except Notepad. The core idea is that the macro checks characters to see if they are letters or non-letters. Based on inspections of the characters on either side of the cursor, the macro decides whether we are at the start, end, or middle of a word. In outline, here's how the macro works: 1. Inspect one character to the left of the cursor. 2. If the character is nothing, we're at the start of the document/field. Select right one word. 3. Inspect one character to the right of the cursor. 4. If the character is nothing, we're at the end of the document/field. Select left one word. 5. If the characters are letter + non-letter, we're at the end of the word. Select left one word. 6. If the characters are non-letter + letter, we're at the start of the word. Select right one word. 7. If the characters are letter + letter, we're in the middle of the word. Select left to the start of the word to determine the position within the word. Then select right one word. 8. If the characters are non-letter + non-letter, take an educated guess: try to select the current word. 9. Transform the capitalization of the selected word. (Handled by a separate, called macro.) I'm not claiming this solution is practical. It works (although not reliably in Notepad), but it's a bit clunky. I've made an AutoHotkey script that does the same thing, and it executes almost instantly. But this has been a fun Macro Express project. If you have a simpler way to case rotate an unselected word using Macro Express, please post your solution! ========================= Main script: ========================= Variable Set String %Letters% to "abcdefghijklmnopqrstuvwxyz" // Capture character to left Clipboard Empty Text Type (Simulate Keystrokes): <SHIFT><ARROW LEFT><CONTROL>c Variable Set String %CharLeft% from the clipboard contents // We must be at the start of the document/field If Variable %CharLeft% Equals "" Text Type (Simulate Keystrokes): <CONTROL><SHIFT><ARROW RIGHT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position Text Type (Simulate Keystrokes): <CONTROL><ARROW LEFT> Macro Stop End If // Capture character to right Clipboard Empty Text Type (Simulate Keystrokes): <ARROW RIGHT><SHIFT><ARROW RIGHT><CONTROL>c Variable Set String %CharRight% from the clipboard contents // We must be at the end of the document/field If Variable %CharRight% Equals "" Text Type (Simulate Keystrokes): <ARROW RIGHT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position (nothing to do) Macro Stop End If // Left = Non-letter and Right = Alpha If Variable %Letters% Does not Contain "%CharLeft%" AND If Variable %Letters% Contains "%CharRight%" Text Type (Simulate Keystrokes): <ARROW LEFT><CONTROL><SHIFT><ARROW RIGHT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position (move left one word) Text Type (Simulate Keystrokes): <CONTROL><ARROW LEFT> Macro Stop End If // Left = Letter and Right = Non-letter If Variable %Letters% Contains "%CharLeft%" AND If Variable %Letters% Does not Contain "%CharRight%" Text Type (Simulate Keystrokes): <ARROW LEFT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position (nothing to do) Macro Stop End If // Left = Letter and Right = Letter If Variable %Letters% Contains "%CharLeft%" AND If Variable %Letters% Contains "%CharRight%" Text Type (Simulate Keystrokes): <ARROW RIGHT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c Variable Set String %WordLeft% from the clipboard contents Variable Set Integer %Offset% to the length of variable %WordLeft% Variable Modify Integer: %Offset% = %Offset% - 1 Text Type (Simulate Keystrokes): <ARROW RIGHT><CONTROL><ARROW LEFT><SHIFT><CONTROL><ARROW RIGHT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position (from start of word, move right to the initial position within the word) Text Type (Simulate Keystrokes): <CONTROL><ARROW LEFT> Repeat Start (Repeat %Offset% times) Text Type (Simulate Keystrokes): <ARROW RIGHT> End Repeat Macro Stop End If // Left = Non-letter and Right = Non-letter If Variable %Letters% Does not Contain "%CharLeft%" AND If Variable %Letters% Does not Contain "%CharRight%" Text Type (Simulate Keystrokes): <ARROW LEFT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c Macro Run: Capitalize Engine // Restore cursor position (nothing to do) Macro Stop End If // Unknown Text Type (Simulate Keystrokes): <ARROW LEFT> Text Box Display: This situation is not handled! Macro Stop ========================= Capitalize Engine: ========================= Variable Set String %Word% from the clipboard contents Variable Set String %WordUpperCase% to "%Word%" Variable Set String %WordLowerCase% to "%Word%" Variable Modify String %WordUpperCase%: Uppercase Variable Modify String %WordLowerCase%: Lowercase If Variable %WordUpperCase% Equals "%Word%" // Change uppercase to lowercase Text Type (Simulate Keystrokes): %WordLowerCase% Else If Variable %WordLowerCase% Equals "%Word%" // Change lowercase to title case Variable Set Integer %WordLength% to the length of variable %Word% Variable Modify String: Copy part of text in %Word% starting at 1 and 1 characters long to %FirstChar% Variable Modify String %FirstChar%: Uppercase Variable Modify String: Copy part of text in %Word% starting at 2 and %WordLength% characters long to %AllButFirstChar% Variable Modify String %AllButFirstChar%: Lowercase Text Type (Simulate Keystrokes): %FirstChar%%AllButFirstChar% Else Text Type (Simulate Keystrokes): %WordUpperCase% End If End If ========================= Main script: ========================= <VARIABLE SET STRING Option="\x00" Destination="%Letters%" Value="abcdefghijklmnopqrstuvwxyz" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="Capture character to left"/> <CLIPBOARD EMPTY/> <TEXT TYPE Action="0" Text="<SHIFT><ARROW LEFT><CONTROL>c"/> <VARIABLE SET STRING Option="\x02" Destination="%CharLeft%" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="We must be at the start of the document/field"/> <IF VARIABLE Variable="%CharLeft%" Condition="\x00" IgnoreCase="FALSE"/> <TEXT TYPE Action="0" Text="<CONTROL><SHIFT><ARROW RIGHT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position" _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<CONTROL><ARROW LEFT>"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Capture character to right"/> <CLIPBOARD EMPTY/> <TEXT TYPE Action="0" Text="<ARROW RIGHT><SHIFT><ARROW RIGHT><CONTROL>c"/> <VARIABLE SET STRING Option="\x02" Destination="%CharRight%" NoEmbeddedVars="FALSE"/> <COMMENT/> <COMMENT Value="We must be at the end of the document/field"/> <IF VARIABLE Variable="%CharRight%" Condition="\x00" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position (nothing to do)" _BACK="0080FFFF"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Left = Non-letter and Right = Alpha"/> <IF VARIABLE Variable="%Letters%" Condition="\x07" Value="%CharLeft%" IgnoreCase="TRUE"/> <AND/> <IF VARIABLE Variable="%Letters%" Condition="\x06" Value="%CharRight%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW LEFT><CONTROL><SHIFT><ARROW RIGHT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position (move left one word)" _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<CONTROL><ARROW LEFT>"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Left = Letter and Right = Non-letter"/> <IF VARIABLE Variable="%Letters%" Condition="\x06" Value="%CharLeft%" IgnoreCase="TRUE"/> <AND/> <IF VARIABLE Variable="%Letters%" Condition="\x07" Value="%CharRight%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW LEFT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position (nothing to do)"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Left = Letter and Right = Letter"/> <IF VARIABLE Variable="%Letters%" Condition="\x06" Value="%CharLeft%" IgnoreCase="TRUE"/> <AND/> <IF VARIABLE Variable="%Letters%" Condition="\x06" Value="%CharRight%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c"/> <VARIABLE SET STRING Option="\x02" Destination="%WordLeft%" NoEmbeddedVars="FALSE"/> <VARIABLE SET INTEGER Option="\x0D" Destination="%Offset%" Text_Variable="%WordLeft%"/> <VARIABLE MODIFY INTEGER Option="\x01" Destination="%Offset%" Value1="%Offset%" Value2="1"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT><CONTROL><ARROW LEFT><SHIFT><CONTROL><ARROW RIGHT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position (from start of word, move right to the initial position within the word)" _BACK="0080FFFF"/> <TEXT TYPE Action="0" Text="<CONTROL><ARROW LEFT>"/> <REPEAT START Start="1" Step="1" Count="%Offset%" Save="FALSE"/> <TEXT TYPE Action="0" Text="<ARROW RIGHT>"/> <END REPEAT/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Left = Non-letter and Right = Non-letter"/> <IF VARIABLE Variable="%Letters%" Condition="\x07" Value="%CharLeft%" IgnoreCase="TRUE"/> <AND/> <IF VARIABLE Variable="%Letters%" Condition="\x07" Value="%CharRight%" IgnoreCase="TRUE"/> <TEXT TYPE Action="0" Text="<ARROW LEFT><CONTROL><SHIFT><ARROW LEFT><CONTROL>c"/> <MACRO RUN Use_ID="FALSE" Name="Capitalize Engine" ID="-1" Wait="TRUE"/> <COMMENT Value="Restore cursor position (nothing to do)" _BACK="0080FFFF"/> <MACRO STOP/> <END IF/> <COMMENT/> <COMMENT Value="Unknown"/> <TEXT TYPE Action="0" Text="<ARROW LEFT>"/> <TEXT BOX DISPLAY Title="This situation is not handled!" Content="{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033{\\fonttbl{\\f0\\fnil\\fcharset0 Tahoma;}{\\f1\\fnil Tahoma;}}\r\n\\viewkind4\\uc1\\pard\\lang4105\\f0\\fs20 L: [%CharLeft%]\r\n\\par R: [%CharRight%]\r\n\\par \\lang1033\\f1\\fs14 \r\n\\par \\lang4105\\f0\\fs20 Ascii L: [%AsciiCharLeft%]\r\n\\par Ascii R: [%AsciiCharRight%]\r\n\\par \\lang1033\\f1\\fs14 \r\n\\par \r\n\\par }\r\n" Left="821" Top="417" Width="395" Height="338" Monitor="0" OnTop="TRUE" Keep_Focus="TRUE" Mode="\x00" Delay="0"/> <MACRO STOP/> ========================= Capitalize Engine: ========================= <VARIABLE SET STRING Option="\x02" Destination="%Word%" NoEmbeddedVars="FALSE"/> <COMMENT/> <VARIABLE SET STRING Option="\x00" Destination="%WordUpperCase%" Value="%Word%" NoEmbeddedVars="FALSE"/> <VARIABLE SET STRING Option="\x00" Destination="%WordLowerCase%" Value="%Word%" NoEmbeddedVars="FALSE"/> <VARIABLE MODIFY STRING Option="\x0B" Destination="%WordUpperCase%"/> <VARIABLE MODIFY STRING Option="\x0C" Destination="%WordLowerCase%"/> <COMMENT/> <IF VARIABLE Variable="%WordUpperCase%" Condition="\x00" Value="%Word%" IgnoreCase="FALSE" _COMMENT="Change uppercase to lowercase"/> <TEXT TYPE Action="0" Text="%WordLowerCase%"/> <ELSE/> <IF VARIABLE Variable="%WordLowerCase%" Condition="\x00" Value="%Word%" IgnoreCase="FALSE" _COMMENT="Change lowercase to title case"/> <VARIABLE SET INTEGER Option="\x0D" Destination="%WordLength%" Text_Variable="%Word%"/> <VARIABLE MODIFY STRING Option="\x09" Destination="%FirstChar%" Variable="%Word%" Start="1" Count="1" NoEmbeddedVars="FALSE"/> <VARIABLE MODIFY STRING Option="\x0B" Destination="%FirstChar%"/> <VARIABLE MODIFY STRING Option="\x09" Destination="%AllButFirstChar%" Variable="%Word%" Start="2" Count="%WordLength%" NoEmbeddedVars="FALSE"/> <VARIABLE MODIFY STRING Option="\x0C" Destination="%AllButFirstChar%"/> <TEXT TYPE Action="0" Text="%FirstChar%%AllButFirstChar%"/> <ELSE/> <TEXT TYPE Action="0" Text="%WordUpperCase%"/> <END IF/> <END IF/> <COMMENT/>
  13. At this point, my only suggestion is put your energies into forcing the macro to reliably give the window focus. Start afresh. Create a new macro, and keep messing with it until you find the steps to give focus to the window under the mouse pointer. Experiment with code excerpts such as these: Mouse Left Click Mouse Left Click Delay: 100 milliseconds Mouse Left Click Mouse Left Button Down Delay: 100 milliseconds Mouse Left Button Up Capture Control from Beneath the Mouse into %ControlUnderMouse% Delay: 100 milliseconds Mouse Click on Control %ControlUnderMouse% <MOUSE LEFT CLICK/> <MOUSE LEFT CLICK/> <DELAY Flags="\x02" Time="100"/> <MOUSE LEFT CLICK/> <MOUSE LEFT BUTTON DOWN/> <DELAY Flags="\x02" Time="100"/> <MOUSE LEFT BUTTON UP/> <CAPTURE CONTROL Option="\x00" Control="%ControlUnderMouse%" UseText="FALSE"/> <DELAY Flags="\x02" Time="100"/> <MOUSE CLICK ON CONTROL Clicks="\x01" Control="%ControlUnderMouse%" Button="\x00" Center="TRUE"/>
  14. Then try this, which may or may not need a delay between steps: Capture Control from Beneath the Mouse into %ControlUnderMouse% Set Focus to %ControlUnderMouse% <CAPTURE CONTROL Option="\x00" Control="%ControlUnderMouse%" UseText="FALSE"/> <SET FOCUS Control="%ControlUnderMouse%"/>
  15. That's what my admittedly untested script is supposed to do. It clicks on whatever object the mouse pointer is hovering over. If the script fails because the object isn't gaining focus after it's clicked on, the first modification I would try is insert a delay between the two statements. Start with 1 second or 0.5 seconds. Through trial and error experimentation, reduce the delay until you've figured out how short it needs to be.
  16. That doesn't sound too hard to do with Macro Express. Do I understand this correctly? You click a mouse button, which causes the mouse to output Ctrl + S or Ctrl + B? If so, the macro might look like this: Mouse Left Click Text Type (Simulate Keystrokes): <CONTROL>b
  17. In many applications, there are hotkeys for switching between different windows, but the hotkeys may not be well documented. Here are a few key combinations to experiment with: F6 Alt + F6 Ctrl + F6 Ctrl + Tab Ctrl + Page Up Ctrl + Page Down I've seen applications that include window switching commands in its menus. For example, in Microsoft Word 2019, the key sequence for getting close to the window switching command is: Alt (or F10) W (View) W (Switch Window) Up and down arrow keys (to select a window) Enter Even if key sequences are impossible like this one, automating them via macros is fairly straightforward.
  18. When I use floating menus (Macro Express 6, Windows 10) I only see tooltips upon hover when the floating menu has focus. If the floating menu is not the active window, then no tooltips.
  19. Try variations of the text you've already inserted in the "IP Address/Hostname" field, but don't include "https://" or "ftp://" or anything similar. For example, when I ping Microsoft's web-based Outlook service, the field reads "outlook.com" but I remember, maybe a year ago, changing it from something else.
  20. This challenge is a little more challenging than the last one. It's actually kind of hard. Macro Express is probably not the ideal tool for tackling this problem, but the fact that it's do-able in Macro Express is testament to the program's versatility. In Microsoft Word, there is a built-in command called "Case Rotate" that changes text from lowercase to title case, from title case to uppercase, and from uppercase to lowercase. The default hotkey is Shift + F3. This hotkey also works in PowerPoint, and in HTML and RTF email messages in Outlook. The challenge: Use Macro Express to create a case-rotate script that changes the case of the current word. Your macro should work in any application or context where you can type and edit text. Because this challenge is not trivial, I'm suggesting the following constraints that I hope will make solutions easier to achieve: 1. The macro acts on a single word to change its case from lowercase to title case to uppercase. If the text is uppercase, the macro changes the case to lowercase. 2. The word should NOT be selected! The macro should transform the word where the insertion point (cursor) is located. 3. The macro should be able to handle punctuation marks that naturally "cling" to words, e.g., commas, periods, question marks, quotation marks, etc. The macro should work equally well for the first word in a document, the last word, or a word in the middle. 4. The insertion point should be in the same location after the macro has changed the case as it was when the macro was activated. For example, if the cursor was between "e" and "x" in "example" when the macro is activated, the cursor should be in the same spot after the macro has run. I hope you find this challenge as fun as I did.
  21. Terry, your last response has led me to the conclusion that I was overthinking this! I tried three different ways to select the contents of a cell, all of which involved Edit mode. After reading your message, I realized there was a fourth way: forget about Edit mode. Simply copy! And with that realization, the only fail-safe needed is to make sure the cell is NOT in Edit mode. (In Edit mode, content must be selected before copying.) Pressing <ESC> exits Edit mode, and does nothing in Ready or End mode. // Cancel "Edit" mode (does nothing if not in Edit mode) Text Type (Simulate Keystrokes): <ESC> // Copy to the clipboard Text Type (Simulate Keystrokes): <CONTROL>c Delay: 40 milliseconds // 30 ms is too short of a delay // We're dealing with dollars and cents, so use a Decimal variable Variable Set Decimal %ClipD% from the clipboard contents // Calculate the correct value (13% less than current value) and round to two decimal places Variable Modify Decimal: %PreTax% = %ClipD% / 1.13 Variable Modify Decimal: Round %PreTax% to 2 decimal places // Output the result Text Type (Simulate Keystrokes): %PreTax% // Press <TAB> to move to the cell to the right, or <ENTER> to move to the cell below Text Type (Simulate Keystrokes): <TAB> <COMMENT Value="Cancel \"Edit\" mode (does nothing if not in Edit mode)"/> <TEXT TYPE Action="0" Text="<ESC>"/> <COMMENT/> <COMMENT Value="Copy to the clipboard"/> <TEXT TYPE Action="0" Text="<CONTROL>c"/> <DELAY Flags="\x02" Time="40" _COMMENT="30 ms is too short of a delay"/> <COMMENT/> <COMMENT Value="We're dealing with dollars and cents, so use a Decimal variable"/> <VARIABLE SET DECIMAL Option="\x02" Destination="%ClipD%"/> <COMMENT/> <COMMENT Value="Calculate the correct value (13% less than current value) and round to two decimal places"/> <VARIABLE MODIFY DECIMAL Option="\x03" Destination="%PreTax%" Value1="%ClipD%" Value2="1.13"/> <VARIABLE MODIFY DECIMAL Option="\x04" Destination="%PreTax%" Places="2"/> <COMMENT/> <COMMENT Value="Output the result"/> <TEXT TYPE Action="0" Text="%PreTax%"/> <COMMENT/> <COMMENT Value="Press <TAB> to move to the cell to the right, or <ENTER> to move to the cell below"/> <TEXT TYPE Action="0" Text="<TAB>"/> Maybe the next challenge will be more challenging!!
  22. Hi Terry, This challenge is not nearly as complex as others that have appeared in this forum, but at the same time, it's not quite as straightforward as it seems. For example, there are many ways to retrieve the contents of a cell so the value can be passed to the macro. I'm aware of three methods. But the methods are not equally reliable. When I tried to "translate" Method 1 into Macro Express code, the script got convoluted. Method 2 failed. Method 3 seems to maximize reliability: So far, it works regardless of the initial state of a cell: whether it has keyboard focus ("Ready mode"), is in "Edit mode", or in "End mode."
  23. Hi Cory, For the sake of this challenge, assume that some cells need to be repaired, and some don't; and that the cells in need of repair are not necessarily contiguous. In other words, the repair cannot be applied to an entire column of cells. The repair must be applied to individual cells based on other criteria, e.g., expenses that were entered into the spreadsheet on certain days, or whatever.
  24. I track my expenses in an Excel spreadsheet. For most expenses, I pay 13% in taxes. For example, if the pre-tax value for an item is $100, I pay a total of $113. I set up my spreadsheet to accept pre-tax values. The spreadsheet uses formulas to calculate the amount of tax I paid on an item, and then sums the two: Pre-tax Tax Total 100.00 13.00 $113.00 10.00 1.30 $11.30 1.00 0.13 $1.13 Unfortunately, I accidentally inputted hundreds of expenses before realizing that I had inserted totals instead of the pre-tax amounts. The challenge: Write a macro to change the value of a cell from the post-tax amount to the pre-tax amount. For example, the macro will change a value of "113" incorrectly entered into in the Pre-Tax column to "100." Assume the cells that you want to correct only contain numbers: no text, and no formulas. This is a real challenge. I actually made this mistake last week. My macro took 10 or 15 minutes to create, and saved hours of tedium to repair. Bonus: Because there might be hundreds of these mistakes in the spreadsheet, anything your solution does to speed up the process of repairing values will earn you brownie points!
  25. I hope you'll post your completed (or almost completed!) script after you're happy with it.
×
×
  • Create New...