أمثلة
برامج نصية عاملة تغطي الصيغة ومجالات الدوال المضمَّنة. صفِّها حسب الموضوع أو ابحث في شيفرتها ونصها. تحتاج
البرامج النصية التي تستخدم الدوال المضمَّنة Context* إلى مشغِّل من إيماءة أو مفتاح اختصار. في وحدة
التحكم التشخيصية تُرجع تلك الدوال المضمَّنة قيمها الافتراضية الفارغة.
مرحبًا، وحدة التحكم
أصغر برنامج نصي. تكتب UtilityPrint إلى وحدة التحكم التشخيصية، أو إلى سجل الطباعة عندما لا يُشغَّل
البرنامج النصي من وحدة التحكم.
UtilityPrint("Hello from Input.Observer");
أنواع القيم الخمسة
متغير واحد من كل نوع، يُطبع عبر StringFormat، وهي الطريقة الوحيدة لتحويل قيمة ليست Text إلى Text.
count = 3; // Integer
ratio = 0.75; // Real
name = "Notepad"; // Text
enabled = true; // Bool
w = WindowGetActive(); // Window
UtilityPrint(StringFormat("count={0} ratio={1}", count, ratio)); // count=3 ratio=0.750000
UtilityPrint(StringFormat("name={0} enabled={1}", name, enabled)); // name=Notepad enabled=true
UtilityPrint(StringFormat("window handle={0}", w, ""));
قيمة الصدق لكل نوع
ما تعدّه if صادقًا لكل نوع: الأرقام غير الصفرية، وقيم Text غير الفارغة، والمقابض غير الفارغة.
if (0) UtilityPrint("never");
if (-1) UtilityPrint("-1 is true");
if (0.0) UtilityPrint("never");
if ("") UtilityPrint("never");
if (" ") UtilityPrint("a single space is true");
if ("false") UtilityPrint("the text \"false\" is true -- it's not empty");
if (!WindowFindByTitle("no window has this title zzz")) UtilityPrint("null handle is false");
سلسلة else-if
تصنيف الموضع الأفقي للمؤشر ضمن أثلاث الشاشة الموجودة أسفله.
x = MouseGetCursorX();
y = MouseGetCursorY();
left = DisplayMonitorGetRectXFromPoint(x, y, false);
width = DisplayMonitorGetRectWidthFromPoint(x, y, false);
offset = x - left;
if (offset < width / 3) {
zone = "left";
} else if (offset < width * 2 / 3) {
zone = "center";
} else {
zone = "right";
}
UtilityPrint("Cursor is in the " + zone + " third");
حلقات العد: تصاعديًا وتنازليًا وبخطوات
أجزاء for الثلاثة كلها إسنادات أو تعابير من اختيارك.
sum = 0;
for (i = 1; i <= 100; i = i + 1) sum = sum + i;
UtilityPrint(StringFormat("1..100 = {0}", sum, "")); // 5050
for (i = 5; i > 0; i = i - 1) UtilityPrint(StringFormat("{0}...", i, ""));
for (p = 1; p <= 1024; p = p * 2) UtilityPrint(StringFormat("{0}", p, "")); // powers of two
حلقات متداخلة: جدول الضرب
حلقات for متداخلة تبني سطرًا واحدًا من Text لكل صف.
for (r = 1; r <= 5; r = r + 1) {
line = "";
for (c = 1; c <= 5; c = c + 1) {
line = line + StringFormat("{0}\t", r * c, "");
}
UtilityPrint(line);
}
حلقة while: انتظار نافذة، مع مهلة
يؤدي الشرط عمل «while»، ويحدّه العدّاد بـ 5 ثوانٍ.
ShellRun("notepad.exe");
w = WindowFindByTitle("Notepad");
for (tries = 0; !w && tries < 50; tries = tries + 1) {
UtilityWait(100);
w = WindowFindByTitle("Notepad");
}
if (w) {
WindowCenterToScreen(w);
} else {
UtilityPrint("Notepad didn't appear within 5 seconds");
}
while (true) مع علامة خروج
الخطوة التي تُسند المتغير إلى نفسه (go = go) تصنع حلقة لا تتوقف إلا عندما يمسح جسمها العلامة. ينهيها
أيضًا مفتاح اختصار إيقاف الكل دائمًا.
rolls = 0;
for (go = true; go; go = go) {
rolls = rolls + 1;
if (MathRandom(1, 6) == 6) go = false;
}
UtilityPrint(StringFormat("Rolled a six after {0} tries", rolls, ""));
break وcontinue
عيّن العدّاد إلى ما بعد الحد لتنفيذ break. ضع بقية جسم الحلقة داخل if لتنفيذ continue.
n = StringSplit("keep,,skip-me,keep too,STOP,never reached", ",");
for (i = 0; i < n; i = i + 1) {
part = StringGetSplitPartAt(i);
if (part == "STOP") {
i = n; // break
} else if (part && !StringStartsWith(part, "skip")) { // continue for empty / skip-*
UtilityPrint(part);
}
}
مفاجآت الأولوية
فخّان من فخاخ الأولوية في C، والأقواس الصريحة التي تصلحهما.
flags = 6;
a = flags & 4 == 4; // flags & (4 == 4) -> 6 & true -> 0 (Bool operand)
b = (flags & 4) == 4; // true
x = 5;
c = 0 < x < 10; // (0 < x) < 10 -> true < 10 -> false (Bool vs Integer)
d = x > 0 && x < 10; // true
UtilityPrint(StringFormat("a={0} b={1}", a, b));
UtilityPrint(StringFormat("c={0} d={1}", c, d));
&& و|| تُقيِّمان الطرفين
يُنفَّذ المعاملان دائمًا، وهذا مهم عندما يكون للطرف الأيمن أثر أو يمكن أن يفشل.
StorageSetValue("calls", 0);
// Both sides run even though the left is false; the right side's
// StorageSetValue still happens.
if (false && StorageSetValue("calls", 1)) { }
UtilityPrint(StringFormat("calls = {0}", StorageGetValue("calls"), "")); // calls = 1
// Guard a call that could fail with a nested if, not &&:
text = "no colon here";
idx = StringGetIndexOf(text, ":");
if (idx >= 0) {
UtilityPrint(StringGetSubstring(text, idx + 1, 100));
}
المساواة بين الأنواع
تُقارَن Integer وReal عدديًا. أما كل زوج آخر من نوعين مختلفين فهما ببساطة غير متساويين.
UtilityPrint(StringFormat("5 == 5.0 -> {0}", 5 == 5.0, "")); // true
UtilityPrint(StringFormat("1 == true -> {0}", 1 == true, "")); // false
UtilityPrint(StringFormat("\"5\" == 5 -> {0}", "5" == 5, "")); // false
UtilityPrint(StringFormat("\"a\" == \"A\" -> {0}", "a" == "A", "")); // false (case-sensitive)
w = WindowFindByTitle("zzz no such window");
UtilityPrint(StringFormat("w == 0 -> {0}, !w -> {1}", w == 0, !w)); // false, true
العمليات الحسابية على الأنواع المختلطة ترجع إلى 0
المجموعات التي لا يفهمها العامل تعطي Integer 0 دون خطأ. اطبع القيمة عندما تبدو النتيجة خاطئة.
a = "Total: " + 5; // 0 -- not "Total: 5"
b = true + 1; // 0
c = -"text"; // 0
d = 2.5 & 1; // 0 -- bitwise needs Integers
e = "Total: " + StringFormat("{0}", 5, ""); // "Total: 5"
UtilityPrint(StringFormat("{0} {1}", a, b) + StringFormat(" {0} {1} ", c, d) + e);
التعليقات والعبارات الفارغة والكتل
تعليقات سطرية وكتلية، وفاصلة منقوطة زائدة، وكتلة في المستوى الأعلى (لا تُنشئ نطاقًا).
// line comment
/* block comment
spanning lines */
x = 1;; // the extra ';' is an empty statement
{
y = x + 1; /* blocks group statements... */
}
UtilityPrint(StringFormat("y = {0}", y, "")); // ...but y is still visible here
قسمة Integer مقابل Real، والقسمة على صفر
قسمة الأعداد الصحيحة تقتطع نحو الصفر، ومعامل Real واحد يعطي نتيجة Real، والقسمة على صفر تعطي 0.
a = 7 / 2; // 3
b = 7 / 2.0; // 3.5
c = 7 * 1.0 / 2; // 3.5 -- convert first, then divide
d = -7 / 2; // -3 (toward zero)
e = 5 / 0; // 0, no error
UtilityPrint(StringFormat("{0} {1}", a, b) + StringFormat(" {0} {1}", c, d) + StringFormat(" {0}", e, ""));
باقي القسمة بدون %
n - (n / d) * d هو % في C. مع مقسوم عليه من قوى العدد اثنين، يؤدي القناع العمل نفسه للأرقام غير
السالبة.
n = 17;
d = 5;
rem = n - (n / d) * d; // 2
isEven = (n & 1) == 0; // false
low3 = n & 7; // 17 % 8 == 1
UtilityPrint(StringFormat("17 % 5 = {0}, even = {1}", rem, isEven));
UtilityPrint(StringFormat("17 % 8 = {0}", low3, ""));
التقريب والدوال المضمَّنة الرياضية لقيم Real
تصبح قيمة Integer الممررة حيث تُعلن الدالة المضمَّنة عن Real قيمة Real. يقرّب التقريب الأنصاف بعيدًا عن الصفر.
n = 16;
root = MathSqrt(n); // 4.0 -- n is widened to 16.0
UtilityPrint(StringFormat("round 2.5 -> {0}", MathRound(2.5), "")); // 3
UtilityPrint(StringFormat("round -2.5 -> {0}", MathRound(-2.5), "")); // -3
UtilityPrint(StringFormat("floor -1.5 -> {0}", MathFloor(-1.5), "")); // -2
UtilityPrint(StringFormat("ceil 1.01 -> {0}", MathCeil(1.01), "")); // 2
UtilityPrint(StringFormat("sqrt 16 -> {0}", MathRound(root), "")); // 4
حصر قيمة ضمن نطاق
تأخذ MathClamp (مثل MathMin/MathMax) أيًا من النوعين العدديين وتُرجع القيمة الفائزة كما كانت.
v = 300;
v = MathClamp(v, 0, 255); // 255
dist = MathAbs(-42); // 42 (Integer stays Integer)
UtilityPrint(StringFormat("clamped={0} abs={1}", v, dist));
أرقام عشوائية ورمي عملة
تشمل MathRandom طرفي النطاق كليهما.
die = MathRandom(1, 6);
if (MathRandom(0, 1) == 1) side = "heads"; else side = "tails";
UtilityPrint(StringFormat("die={0}, coin={1}", die, side));
طول خط الإيماءة
يجمع المسافة المستقيمة بين نقاط الإيماءة المتتالية. يصبح مجموع المربعات من نوع Integer قيمة Real في طريقه
إلى MathSqrt.
n = ContextGetPointCount();
total = 0.0;
for (i = 1; i < n; i = i + 1) {
dx = ContextGetPointX(i) - ContextGetPointX(i - 1);
dy = ContextGetPointY(i) - ContextGetPointY(i - 1);
total = total + MathSqrt(dx * dx + dy * dy);
}
UtilityPrint(StringFormat("{0} points, {1} px long", n, MathRound(total)));
تحريك الماوس في دائرة
تحويل الدرجات إلى راديان، والدوال المثلثية على قيم Real، وMathRound للعودة إلى إحداثيات بكسل من نوع
Integer.
cx = MouseGetCursorX();
cy = MouseGetCursorY();
radius = 80.0;
for (deg = 0; deg <= 360; deg = deg + 10) {
rad = deg * MathGetPi() / 180;
MouseMoveTo(cx + MathRound(radius * MathCos(rad)), cy + MathRound(radius * MathSin(rad)));
UtilityWait(15);
}
MouseMoveTo(cx, cy);
تنسيق قيمة Real بدون ست خانات عشرية
غيّر المقياس وقرّب للحصول على نسبة مئوية، أو لتقسيم القيمة إلى جزء صحيح وأجزاء من مئة للحصول على خانتين عشريتين. يعمل مع القيم غير السالبة.
ratio = 2.0 / 3.0;
pct = MathRound(ratio * 100); // 67
value = 3.14159;
cents = MathRound(value * 100); // 314
whole = cents / 100; // 3
frac = cents - whole * 100; // 14
if (frac < 10) fracText = StringFormat("0{0}", frac, ""); else fracText = StringFormat("{0}", frac, "");
UtilityPrint(StringFormat("{0}% and {1}", pct, StringFormat("{0}.", whole, "") + fracText)); // 67% and 3.14
أقنعة العلامات: التعيين والمسح والتبديل والاختبار
عمليات الأقنعة المعتادة الأربع على قيم العلامات الخاصة بك.
BOLD = 0x1;
ITALIC = 0x2;
UNDERLINE = 0x4;
style = BOLD | UNDERLINE; // 0b101 = 5
style = style | ITALIC; // set -> 7
style = style & ~BOLD; // clear -> 6
style = style ^ UNDERLINE; // toggle -> 2
if ((style & ITALIC) != 0) UtilityPrint("italic is on");
if ((style & BOLD) == 0) UtilityPrint("bold is off");
UtilityPrint(StringFormat("style = {0}", style, ""));
قراءة لون البكسل أسفل المؤشر
تفكيك القيمة Integer بالشكل 0xRRGGBB باستخدام الإزاحات والأقنعة.
c = DisplayGetPixelColorFromPoint(MouseGetCursorX(), MouseGetCursorY());
if (c < 0) {
UtilityPrint("The cursor isn't over any monitor");
} else {
r = (c >> 16) & 0xFF;
g = (c >> 8) & 0xFF;
b = c & 0xFF;
UtilityPrint(StringFormat("R={0} G={1}", r, g) + StringFormat(" B={0}", b, ""));
if (r > 200 && g < 80 && b < 80) UtilityPrint("That's red");
}
Integer إلى نص ست عشري
لا توجد دالة مضمَّنة تنسّق القيم الست عشرية، لذا انزع أربع بتات في كل مرة وابحث عن كل رقم في قيمة Text.
digits = "0123456789ABCDEF";
value = 48879;
hex = "";
for (v = value; v > 0; v = v >> 4) {
hex = StringGetSubstring(digits, v & 0xF, 1) + hex;
}
if (!hex) hex = "0";
UtilityPrint("0x" + hex); // 0xBEEF
عدّ البتات المعيَّنة
المرور بالإزاحة عبر البتات الـ 64 كلها وإضافة كل بت منخفض.
v = 0xB6; // 1011 0110
bits = 0;
for (i = 0; i < 64; i = i + 1) {
bits = bits + ((v >> i) & 1);
}
UtilityPrint(StringFormat("0xB6 has {0} bits set", bits, "")); // 5
الحالات الحدية للإزاحة
يحافظ >> على الإشارة، ومقدار الإزاحة خارج النطاق 0–63 يعطي 0.
UtilityPrint(StringFormat("1 << 10 = {0}", 1 << 10, "")); // 1024
UtilityPrint(StringFormat("-16 >> 2 = {0}", -16 >> 2, "")); // -4
UtilityPrint(StringFormat("1 << 64 = {0}", 1 << 64, "")); // 0
UtilityPrint(StringFormat("~0 = {0}", ~0, "")); // -1
تبديل قيمتي Integer
الطريقة العادية تحتاج إلى متغير مؤقت. أما XOR فيبدّل دونه.
a = 12; b = 34;
t = a; a = b; b = t; // with a temporary
a = a ^ b; b = a ^ b; a = a ^ b; // XOR swap back
UtilityPrint(StringFormat("a={0} b={1}", a, b)); // a=12 b=34
بتات حالة المفتاح
تُرجع KeyboardGetKeyState قيمة Win32 الخام: البت الأعلى يعني أن المفتاح مضغوط، والبت الأدنى يعني أنه
مبدَّل. تُجري الدوال المضمَّنة Is* الاختبار نفسه نيابة عنك.
caps = KeyboardGetKeyState(VirtualKey.CapsLock);
shift = KeyboardGetKeyState(VirtualKey.ShiftKey);
UtilityPrint(StringFormat("Caps Lock on: {0}, Shift held: {1}", (caps & 1) != 0, (shift & 0x8000) != 0));
UtilityPrint(StringFormat("same via builtins: {0}, {1}",
KeyboardIsKeyToggled(VirtualKey.CapsLock), KeyboardIsKeyDown(VirtualKey.ShiftKey)));
تسلسلات الهروب في السلاسل النصية ومسارات Windows
ضاعف كل شرطة مائلة عكسية في المسار. \t و\n و\r تسلسلات هروب، وتُحذف أي شرطة مائلة عكسية
أخرى.
good = "C:\\Temp\\report.txt"; // C:\Temp\report.txt
bad = "C:\Temp\new.txt"; // C:<no backslash>Temp<line break>ew.txt
quote = "He said \"stop\"";
tabs = "Name\tValue";
cont = "one logical line, \
written on two";
UtilityPrint(good);
UtilityPrint(bad);
UtilityPrint(quote);
UtilityPrint(tabs);
UtilityPrint(cont);
تنسيق أكثر من قيمتين
لا تملأ StringFormat إلا {0} و{1}. استخدم استدعاءً متداخلًا، أو اربط عدة استدعاءات باستخدام +.
w = WindowGetActive();
x = WindowGetX(w); y = WindowGetY(w);
width = WindowGetWidth(w); height = WindowGetHeight(w);
// nest: the inner call leaves "{0},{1}" for the outer call to fill
a = StringFormat(StringFormat("{0}x{1} at ", width, height) + "{0},{1}", x, y);
// concatenate: each call formats its own piece
b = StringFormat("pos {0},{1}", x, y) + StringFormat(" size {0}x{1}", width, height);
UtilityPrint(a);
UtilityPrint(b);
التقسيم والمرور على الأجزاء
تُرجع StringSplit العدد، وتقرأ StringGetSplitPartAt كل جزء. الأجزاء الواقعة بين محدِّدين متجاورين
فارغة.
n = StringSplit("red,green,,blue", ",");
for (i = 0; i < n; i = i + 1) {
UtilityPrint(StringFormat("{0}: [{1}]", i, StringGetSplitPartAt(i)));
}
// 0: [red] 1: [green] 2: [] 3: [blue]
التقسيمات المتداخلة: أزواج key=value
يحل التقسيم الداخلي محل أجزاء التقسيم الخارجي، لذا أعد تقسيم القائمة الخارجية في بداية كل دورة.
config = "width=800;height=600;title=Main";
n = StringSplit(config, ";");
for (i = 0; i < n; i = i + 1) {
StringSplit(config, ";"); // restore the outer parts...
pair = StringGetSplitPartAt(i); // ...and copy this one out
StringSplit(pair, "="); // now the cache holds key, value
UtilityPrint(StringFormat("{0} -> {1}", StringGetSplitPartAt(0), StringGetSplitPartAt(1)));
}
آخر فهرس: امتداد الملف
لا توجد LastIndexOf، لذا افحص كل موضع واحتفظ بآخر تطابق.
file = "report.final.v2.pdf";
last = -1;
len = StringGetLength(file);
for (i = 0; i < len; i = i + 1) {
if (StringGetSubstring(file, i, 1) == ".") last = i;
}
if (last >= 0) {
ext = StringGetSubstring(file, last + 1, len - last - 1);
base = StringGetSubstring(file, 0, last);
UtilityPrint(StringFormat("base={0} ext={1}", base, ext)); // base=report.final.v2 ext=pdf
}
قراءة رقم كتبه شخص
تقرؤه false بالتنسيق الإقليمي للمستخدم (يكتب المستخدم الألماني 1.234,5). ويجب حينئذ أن تتبع
مجموعات الأرقام ذلك التنسيق: لمستخدم بالعربية (المملكة العربية السعودية) يكون 1,234.5 رقمًا أما 1,5
فلا. وتلتقط StringIsNumber النص الذي ليس رقمًا، والذي كانت StringToNumber وحدها ستحوّله إلى 0.
text = UIShowInputBox("Width in pixels:", "Resize", "800");
if (!StringIsNumber(text, false)) {
UIShowMessageBox("Not a number: " + text, "Resize", "OK", "Warning");
} else {
width = StringToNumber(text, false); // Integer 800, or a Real if they typed a fraction
shown = StringFromNumber(width * 1.5, 1, false); // "1,200.0" in en-US, "1.200,0" in de-DE
UtilityPrint("one and a half times that: " + shown);
}
تشغيل برنامج وانتظار نافذته والعمل عليها
تستطلع WindowWaitFor حتى انقضاء المهلة (60 ثانية كحد أقصى) وتعطي نافذة فارغة إذا لم يتطابق شيء. النمط
تعبير نمطي غير حساس لحالة الأحرف يُطبَّق على العنوان؛ ويتبع عنوان البرنامج لغة العرض في Windows، لذا طابِق
الجزء الذي لا يتغير.
ShellRun("notepad.exe");
w = WindowWaitFor("notepad$", 10000);
if (w) {
WindowSetActive(w);
KeyboardTypeText("Notes for today:\n");
WindowWaitClose(w, 60000); // carries on once the user closes it, or after a minute
UtilityPrint("Notepad is gone");
} else {
UtilityPrint("Notepad didn't open in 10 seconds");
}
استخراج قيمة من نص منسوخ باستخدام تعبير نمطي
صيغة PCRE2، حساسة لحالة الأحرف ما لم يبدأ النمط بـ (?i)، ومدركة لـ Unicode (تطابق \w الأحرف ذات
العلامات). المجموعة 0 هي التطابق كله؛ وتُكتب الشرطة المائلة العكسية في النمط \\ داخل سلسلة نصية في
البرنامج النصي. $1 في نص الاستبدال هي المجموعة 1. تستخدم الدوال المضمَّنة Window*Regex/Shell*Regex
المحرك نفسه، غير حساسة لحالة الأحرف دائمًا.
text = ClipboardGetText();
if (StringRegexMatch(text, "(?i)order\\s*#?(\\d+)")) {
UtilityPrint("order number: " + StringRegexGetGroupAt(1));
} else {
UtilityPrint("no order number on the clipboard");
}
// every run of spaces, tabs and line breaks becomes one space; "#1234" becomes "order 1234"
text = StringRegexReplace(text, "\\s+", " ");
ClipboardSetText(StringRegexReplace(text, "#(\\d+)", "order $1"));
حشو رقم بالأصفار
أضف أحرفًا في البداية حتى تصبح قيمة Text طويلة بما يكفي.
n = 7;
s = StringFormat("{0}", n, "");
for (s = s; StringGetLength(s) < 3; s = s) {
s = "0" + s;
}
UtilityPrint(s); // 007
عكس قيمة Text
امشِ عبر قيمة Text إلى الخلف وحدةَ UTF-16 واحدة في كل مرة. الأحرف الواقعة خارج المستوى متعدد اللغات الأساسي (معظم الرموز التعبيرية) وحدتان وستخرج مقسومة.
text = "Input.Observer";
rev = "";
for (i = StringGetLength(text) - 1; i >= 0; i = i - 1) {
rev = rev + StringGetSubstring(text, i, 1);
}
UtilityPrint(rev); // revresbO.tupnI
عدّ الكلمات في الحافظة
حوّل علامات الجدولة وفواصل الأسطر إلى مسافات، وقسّم عند المسافات، وعُدّ الأجزاء غير الفارغة.
text = ClipboardGetText();
text = StringReplace(text, "\n", " ");
text = StringReplace(text, "\t", " ");
n = StringSplit(text, " ");
words = 0;
for (i = 0; i < n; i = i + 1) {
if (StringTrim(StringGetSplitPartAt(i))) words = words + 1;
}
UtilityPrint(StringFormat("{0} words", words, ""));
مقارنات غير حساسة لحالة الأحرف
حوّل الجانبين إلى أحرف صغيرة، لأن كل عامل ودالة مضمَّنة خاصين بـ Text حساسان لحالة الأحرف.
title = WindowGetTitle(WindowGetActive());
if (StringContains(StringToLower(title), "visual studio")) {
UtilityPrint("In Visual Studio");
}
exe = WindowGetExecutableName(WindowGetActive());
if (StringToLower(exe) == "notepad.exe") UtilityPrint("In Notepad");
ترتيب النص ترتيبي
يقارن < وحدات ترميز UTF-16: يأتي كل حرف ASCII كبير قبل كل حرف صغير.
UtilityPrint(StringFormat("\"apple\" < \"banana\" : {0}", "apple" < "banana", "")); // true
UtilityPrint(StringFormat("\"Zebra\" < \"apple\" : {0}", "Zebra" < "apple", "")); // true
UtilityPrint(StringFormat("\"apple\" < \"Banana\" : {0}", "apple" < "Banana", "")); // false
a = "apple"; b = "Banana";
UtilityPrint(StringFormat("case-folded : {0}", StringToLower(a) < StringToLower(b), "")); // true
ملء قالب ولصقه
تملأ StringReplace العناصر النائبة %NAME%. تُحفظ الحافظة وتُستعاد حول عملية اللصق.
template = "Hi %NAME%,\n\nThanks for the report on %APP%.\n";
text = StringReplace(template, "%NAME%", "Sam");
text = StringReplace(text, "%APP%", ContextGetApplicationName());
ClipboardSave();
ClipboardPasteReplacementText(text);
UtilityWait(150); // let the target app read the clipboard first
ClipboardRestore();
ضم أسطر الحافظة في سطر واحد
قسّم عند \n. تزيل StringTrim أيضًا \r الخاص بنهايات الأسطر في Windows، لذا يعمل هذا سواء انتهت
الأسطر بـ \r\n أو بـ \n وحدها.
n = StringSplit(ClipboardGetText(), "\n");
out = "";
for (i = 0; i < n; i = i + 1) {
part = StringTrim(StringGetSplitPartAt(i));
if (part) {
if (out) out = out + " ";
out = out + part;
}
}
ClipboardSetText(out);
البحث في الويب عن النص المحدد
تنتظر ClipboardCopySelection حتى يكتمل النسخ بدلًا من التخمين. تمنع StringUrlEncode الرموز & و#
والمسافات والأحرف ذات العلامات من إفساد العنوان. رمّز مصطلح البحث فقط، وليس عنوان URL كله أبدًا.
ClipboardSave();
term = StringTrim(ClipboardCopySelection(1000));
ClipboardRestore();
if (term) ShellRun("https://www.bing.com/search?q=" + StringUrlEncode(term));
إيماءة واحدة، عدة خيارات
تأخذ UIShowMenu عنصرًا واحدًا في كل سطر (- وحدها فاصل) وتُرجع فهرس العنصر المختار، بدءًا من 0 مع
تخطي الفواصل، أو -1 عند الإغلاق دون اختيار. تُرجع UIShowInputBox القيمة "" عند الإلغاء.
choice = UIShowMenu("Maximize\nMinimize\n-\nRename window...");
w = ContextGetWindow();
if (choice == 0) WindowMaximize(w);
else if (choice == 1) WindowMinimize(w);
else if (choice == 2) {
title = UIShowInputBox("New title for this window:", "Rename", WindowGetTitle(w));
if (title) WindowSetTitle(w, title);
}
تاريخ اليوم، واسم ملف مختوم بالوقت
تُرجع DateTimeGetNow نصًا بتنسيق ISO 8601. تكتبه DateTimeFormat بطريقة المستخدم، أو كـ FileStamp
يُفرز حسب الوقت وآمن في اسم الملف.
now = DateTimeGetNow();
KeyboardTypeText(DateTimeFormat(now, DateTimeStyle.LongDate));
path = ShellExpandEnvironmentVariables("%USERPROFILE%\\Desktop\\note-") + DateTimeFormat(now, DateTimeStyle.FileStamp) + ".txt";
FileCreate(path, ClipboardGetText());
if (DateTimeGetPart(now, DateTimePart.Hour) >= 17) UtilityPrint("after hours");
الثوابت المسماة مقابل الأرقام الخام
يُترجَم الثابت إلى رقمه، لذا فإن هذه الاستدعاءات متطابقة. الصيغة الست عشرية تطابق وثائق Win32.
KeyboardPressKey(VirtualKey.VolumeMute);
KeyboardPressKey(0xAD); // the same key, as a hex VK code
KeyboardPressKey(173); // and in decimal
UtilityPrint(StringFormat("VirtualKey.A = {0}, MouseButton.Right = {1}", VirtualKey.A, MouseButton.Right));
تبديل التكبير لنافذة الإيماءة
الإجراء الأكثر شيوعًا للإيماءات. ContextGetWindow هي النافذة التي بدأت الإيماءة فوقها.
w = ContextGetWindow();
if (WindowIsMaximized(w)) WindowRestore(w); else WindowMaximize(w);
تثبيت نافذة في المقدمة
تعيّن WindowSetTopmost خاصية «دائمًا في المقدمة» صراحةً، وتقلبها WindowToggleTopmost. تتذكر خاصية
النافذة الحالة التي اختارها هذا البرنامج النصي.
w = ContextGetWindow();
pinned = WindowGetPropertyInteger(w, "io.pinned") == 1;
WindowSetTopmost(w, !pinned);
if (pinned) {
WindowRemoveProp(w, "io.pinned");
} else {
WindowSetPropertyInteger(w, "io.pinned", 1);
ShellShowToast("Pinned on top", WindowGetTitle(w));
}
التنقل بين مستويات شفافية النافذة
يخفّض العتامة تدريجيًا من 255 إلى 105 ثم يعود إلى 255. النافذة غير الطبقية تُبلغ عن 255.
w = ContextGetWindow();
a = WindowGetAlpha(w) - 50;
if (a < 100) a = 255;
WindowSetAlpha(w, a);
محاذاة النافذة النشطة إلى النصف الأيسر من شاشتها
يستخدم منطقة العمل (true) حتى لا تغطي النافذة شريط المهام.
w = WindowGetActive();
cx = WindowGetX(w) + WindowGetWidth(w) / 2;
cy = WindowGetY(w) + WindowGetHeight(w) / 2;
x = DisplayMonitorGetRectXFromPoint(cx, cy, true);
y = DisplayMonitorGetRectYFromPoint(cx, cy, true);
width = DisplayMonitorGetRectWidthFromPoint(cx, cy, true);
height = DisplayMonitorGetRectHeightFromPoint(cx, cy, true);
WindowRestore(w);
WindowMoveTo(w, x, y);
WindowResizeTo(w, width / 2, height);
محاذاة نافذة إلى خلية في شبكة 3×2 أسفل المؤشر
تقسّم الدوال المضمَّنة Region* المستطيل إلى خلايا، وتجد الخلية التي تحتوي على نقطة، وتعطي حدودها.
mx = MouseGetCursorX();
my = MouseGetCursorY();
x = DisplayMonitorGetRectXFromPoint(mx, my, true);
y = DisplayMonitorGetRectYFromPoint(mx, my, true);
w = DisplayMonitorGetRectWidthFromPoint(mx, my, true);
h = DisplayMonitorGetRectHeightFromPoint(mx, my, true);
cell = RegionGetCellIndexAt(x, y, w, h, 3, 2, mx, my);
win = ContextGetWindow();
if (cell >= 0 && win) {
WindowRestore(win);
WindowMoveTo(win, RegionGetX(x, y, w, h, 3, 2, cell), RegionGetY(x, y, w, h, 3, 2, cell));
WindowResizeTo(win, RegionGetWidth(x, y, w, h, 3, 2, cell), RegionGetHeight(x, y, w, h, 3, 2, cell));
}
نقل نافذة إلى الشاشة التالية
الوسيطة الثانية تحرّك الماوس مع النافذة.
WindowSendToNextScreen(ContextGetWindow(), true);
سرد النوافذ المرئية ذات المستوى الأعلى
التعداد ثم الفهرسة، مع تخطي النوافذ المخفية والمحجوبة وغير المعنونة.
n = WindowGetAllTopLevel();
shown = 0;
for (i = 0; i < n; i = i + 1) {
w = WindowGetEnumeratedAt(i);
if (WindowGetVisible(w)) {
if (!WindowIsCloaked(w)) {
title = WindowGetTitle(w);
if (title) {
UtilityPrint(StringFormat("{0} [{1}]", title, WindowGetExecutableName(w)));
shown = shown + 1;
}
}
}
}
UtilityPrint(StringFormat("{0} of {1} windows", shown, n));
تصغير كل نوافذ تطبيق واحد
يطابق الملف التنفيذي بتعبير نمطي غير حساس لحالة الأحرف. لاحظ \\.: وهي \. الخاصة بالتعبير النمطي
مكتوبة داخل سلسلة نصية في البرنامج النصي.
n = WindowFindAllByModuleRegex("notepad\\.exe$");
for (i = 0; i < n; i = i + 1) {
WindowMinimize(WindowGetEnumeratedAt(i));
}
UtilityPrint(StringFormat("Minimized {0} Notepad windows", n, ""));
إغلاق النوافذ حسب نمط العنوان، بعد التأكيد
تعبير نمطي على العناوين، وعدد في الرسالة، وفحص للزر الذي نُقر.
n = WindowFindAllByTitleRegex("^Untitled - ");
if (n > 0) {
answer = UIShowMessageBox(StringFormat("Close {0} untitled window(s)?", n, ""),
"Tidy up", "YesNo", "Question");
if (answer == "Yes") {
for (i = 0; i < n; i = i + 1) WindowClose(WindowGetEnumeratedAt(i));
}
}
تذكّر موضع النافذة واستعادته
تحتفظ خصائص النافذة بقيم Integer على النافذة نفسها، بين مرات التشغيل، حتى تُغلق. الخاصية التي لم تُعيَّن قط تُقرأ 0.
w = ContextGetWindow();
if (WindowGetPropertyInteger(w, "io.saved") == 1) {
WindowMoveTo(w, WindowGetPropertyInteger(w, "io.x"), WindowGetPropertyInteger(w, "io.y"));
WindowRemoveProp(w, "io.saved");
WindowRemoveProp(w, "io.x");
WindowRemoveProp(w, "io.y");
} else {
WindowSetPropertyInteger(w, "io.x", WindowGetX(w));
WindowSetPropertyInteger(w, "io.y", WindowGetY(w));
WindowSetPropertyInteger(w, "io.saved", 1);
WindowCenterToScreen(w);
}
فحص عناصر التحكم التابعة للنافذة
تستخدم العناصر التابعة ذاكرة التخزين المؤقت للنوافذ نفسها التي يستخدمها تعداد المستوى الأعلى.
w = ContextGetWindow();
n = WindowGetAllChildren(w, true);
for (i = 0; i < n; i = i + 1) {
c = WindowGetEnumeratedAt(i);
UtilityPrint(StringFormat("{0}: {1}", WindowGetClassName(c), WindowGetTitle(c)));
}
من العملية إلى النافذة
عدّد معرّفات العمليات حسب اسم الملف التنفيذي، ثم ابحث عن نافذة كل منها.
n = ShellEnumerateProcessIdsByExeRegex("^explorer\\.exe$");
for (i = 0; i < n; i = i + 1) {
pid = ShellGetEnumeratedProcessIdAt(i);
w = WindowFromProcessId(pid);
UtilityPrint(StringFormat("pid {0}: {1}", pid, WindowGetTitle(w)));
}
وصف ما يوجد أسفل المؤشر
عنصر التحكم أسفل نقطة، ونافذته ذات المستوى الأعلى، والنقطة محوّلة إلى إحداثيات منطقة العميل.
x = MouseGetCursorX();
y = MouseGetCursorY();
control = WindowControlFromPoint(x, y);
top = WindowGetRoot(control);
UtilityPrint(StringFormat("control class: {0}; window: {1}", WindowGetClassName(control), WindowGetTitle(top)));
UtilityPrint(StringFormat("client point: {0},{1}",
WindowMapScreenPointToClientX(top, x, y), WindowMapScreenPointToClientY(top, x, y)));
إخفاء نافذة في منطقة الإعلامات
التصغير إلى منطقة الإعلامات. تعيد TrayRestoreAllWindows() كل النوافذ.
TrayMinimizeWindow(ContextGetWindow());
كل ما يعرفه سياق المشغِّل
اربط هذا بإيماءة لترى ما يمكن لبرنامجها النصي قراءته.
UtilityPrint(StringFormat("action={0} gesture={1}", ContextGetActionName(), ContextGetGestureName()));
UtilityPrint(StringFormat("app={0} window={1}", ContextGetApplicationName(), WindowGetTitle(ContextGetWindow())));
UtilityPrint(StringFormat("box x={0} y={1}", ContextGetBoundingBoxX(), ContextGetBoundingBoxY())
+ StringFormat(" w={0} h={1}", ContextGetBoundingBoxWidth(), ContextGetBoundingBoxHeight()));
UtilityPrint(StringFormat("points={0} button={1}", ContextGetPointCount(), ContextGetStrokeButton()));
في أي اتجاه سار الخط؟
قارن النقطتين الأولى والأخيرة واختر المحور الغالب.
n = ContextGetPointCount();
if (n > 1) {
dx = ContextGetPointX(n - 1) - ContextGetPointX(0);
dy = ContextGetPointY(n - 1) - ContextGetPointY(0);
if (MathAbs(dx) > MathAbs(dy)) {
if (dx > 0) dir = "right"; else dir = "left";
} else {
if (dy > 0) dir = "down"; else dir = "up";
}
UtilityPrint("The stroke went " + dir);
}
التفرع حسب زر الخط
تُرجع ContextGetStrokeButton قيمة MouseButton.*، أو -1 خارج مشغِّل الإيماءة أو زر الماوس.
b = ContextGetStrokeButton();
if (b == MouseButton.Secondary) {
WindowMinimize(ContextGetWindow());
} else if (b == MouseButton.Middle) {
WindowClose(ContextGetWindow());
} else if (b == -1) {
UtilityPrint("Not triggered by a mouse button");
}
لقطة شاشة للمنطقة التي أحطتها بدائرة
يحفظ المربع المحيط بالإيماءة كملف PNG في «الصور».
path = ShellExpandEnvironmentVariables("%USERPROFILE%\\Pictures\\gesture-capture.png");
ok = CaptureSaveRegion(path, ContextGetBoundingBoxX(), ContextGetBoundingBoxY(),
ContextGetBoundingBoxWidth(), ContextGetBoundingBoxHeight());
if (ok) ShellShowToast("Captured", path);
تمرير رسم غير متعرَّف عليه
إذا رُسمت إيماءة فوق تطبيق رسم، فأعد تشغيل الخط إلى التطبيق كسحب عادي.
if (StringToLower(ContextGetApplicationName()) == "mspaint.exe") {
ContextRelayGesture();
}
النقر في مكان ما، ثم إعادة المؤشر
احفظ موضع المؤشر في متغيرات، وانقر، ثم عُد.
x = MouseGetCursorX();
y = MouseGetCursorY();
MouseClick(20, 20, MouseButton.Primary);
UtilityWait(50);
MouseMoveTo(x, y);
النقر على نقطة داخل نافذة
تبقى إحداثيات منطقة العميل صحيحة أينما نُقلت النافذة.
w = WindowFindByTitle("Calculator");
if (w) {
WindowSetActive(w);
MouseClickAtClientPoint(w, 40, 60, MouseButton.Primary);
}
سحب ببرنامج نصي
اضغط، وحرّك على خطوات، ثم حرّر. الدوال المضمَّنة المنفصلة للضغط والتحريك والتحرير موجودة لهذا الغرض.
x = MouseGetCursorX();
y = MouseGetCursorY();
MouseButtonDown(MouseButton.Primary);
for (i = 1; i <= 20; i = i + 1) {
MouseMoveTo(x + i * 10, y);
UtilityWait(10);
}
MouseButtonUp(MouseButton.Primary);
التمرير بالدرجات
درجة واحدة من عجلة الماوس تساوي 120. القيمة السالبة تمرّر لأسفل أو لليسار.
MouseScrollVertical(-3 * 120); // three notches down
MouseScrollHorizontal(120); // one notch right
حصر المؤشر داخل نافذة لمدة 5 ثوانٍ
تُطبَّق MouseLockToRect على مستوى النظام كله حتى MouseUnlock، لذا استخدمهما معًا دائمًا.
w = ContextGetWindow();
MouseLockToRect(WindowGetX(w), WindowGetY(w), WindowGetWidth(w), WindowGetHeight(w));
UtilityWait(5000);
MouseUnlock();
تركيبات المفاتيح
بادئات مفاتيح التعديل ^ Ctrl و+ Shift و% Alt و@ Win، ثم مفتاح واحد.
KeyboardPressKeyCombo("^c"); // Ctrl+C
KeyboardPressKeyCombo("^+{ESC}"); // Ctrl+Shift+Esc
KeyboardPressKeyCombo("@{LEFT}"); // Win+Left
KeyboardPressKeyCombo("%{F4}"); // Alt+F4
كتابة توقيع
تكتب KeyboardTypeText الأحرف. أرسل Enter كتركيبة مفاتيح بين الأسطر، حتى يرى كل تطبيق ضغطة حقيقية على
المفتاح Enter.
KeyboardTypeText("Best regards,");
KeyboardPressKeyCombo("{ENTER}");
KeyboardTypeText("Sam");
النقر مع Shift
اضغط مفتاحًا باستمرار حول إجراء للماوس، وحرّره في البرنامج النصي نفسه. المفتاح الذي يُترك مضغوطًا يبقى مضغوطًا.
KeyboardKeyDown(VirtualKey.ShiftKey);
MouseClick(MouseGetCursorX(), MouseGetCursorY(), MouseButton.Primary);
KeyboardKeyUp(VirtualKey.ShiftKey);
مفاتيح الوسائط
أرسل مفاتيح الوسائط ومستوى الصوت بأسمائها في VirtualKey.
KeyboardPressKey(VirtualKey.MediaPlayPause);
UtilityWait(200);
KeyboardPressKey(VirtualKey.MediaNextTrack);
تغيير السلوك أثناء الضغط على Ctrl
افحص الحالة الحية لمفتاح لتعطي إيماءة واحدة معنيين.
w = ContextGetWindow();
if (KeyboardIsKeyDown(VirtualKey.ControlKey)) {
WindowClose(w);
} else {
WindowMinimize(w);
}
تحويل النص المحدد إلى أحرف كبيرة
انسخ التحديد، وغيّره، والصقه مرة أخرى، واستعد ما كان في الحافظة من قبل.
ClipboardSave();
ClipboardClear();
KeyboardPressKeyCombo("^c");
UtilityWait(100);
text = ClipboardGetText();
if (text) {
ClipboardPasteReplacementText(StringToUpper(text));
UtilityWait(100);
}
ClipboardRestore();
البحث في الويب عن التحديد
انسخ التحديد وافتح عنوان URL للبحث. تصبح المسافات +. لترميز كل الأحرف الأخرى أيضًا، استخدم
StringUrlEncode، كما يفعل البحث في الويب عن النص المحدد.
ClipboardSave();
KeyboardPressKeyCombo("^c");
UtilityWait(100);
q = StringTrim(ClipboardGetText());
ClipboardRestore();
if (q) {
ShellRun("https://www.bing.com/search?q=" + StringReplace(q, " ", "+"));
}
حفظ صورة منسوخة في ملف
يكتب صورة الحافظة إلى القرص ويُبلغ عن النتيجة.
path = ShellExpandEnvironmentVariables("%USERPROFILE%\\Desktop\\clipboard.png");
if (ClipboardSaveImage(path)) ShellShowToast("Saved", path);
else UtilityPrint("No image on the clipboard");
الإلحاق بملف سجل
يُنشئ الملف مع ترويسة في المرة الأولى، ثم يُلحق سطرًا واحدًا في كل تشغيل.
log = ShellExpandEnvironmentVariables("%TEMP%\\input-observer-gestures.log");
if (!FileExists(log)) FileCreate(log, "gesture\tapplication\n");
FileAppendText(log, StringFormat("{0}\t{1}\n", ContextGetGestureName(), ContextGetApplicationName()));
قراءة ملف وعدّ أسطره
تُرجع FileReadText الملف كله كقيمة Text، تُقسَّم بعد ذلك عند \n.
path = "C:\\Windows\\System32\\drivers\\etc\\hosts";
text = FileReadText(path);
n = StringSplit(text, "\n");
comments = 0;
for (i = 0; i < n; i = i + 1) {
if (StringStartsWith(StringTrim(StringGetSplitPartAt(i)), "#")) comments = comments + 1;
}
UtilityPrint(StringFormat("{0} lines, {1} comments", n, comments));
UtilityPrint(StringFormat("{0} bytes, modified {1}", FileGetSize(path), FileGetModifiedDate(path)));
عدّ أنواع الملفات في مجلد
يعدّد محتويات مجلد دون الدخول إلى المجلدات الفرعية ويعدّ التطابقات دون حساسية لحالة الأحرف.
folder = ShellExpandEnvironmentVariables("%USERPROFILE%\\Downloads");
n = FolderEnumerateAll(folder, false);
pdf = 0; zip = 0;
for (i = 0; i < n; i = i + 1) {
p = StringToLower(FolderGetEnumeratedPathAt(i));
if (StringEndsWith(p, ".pdf")) pdf = pdf + 1;
else if (StringEndsWith(p, ".zip")) zip = zip + 1;
}
UtilityPrint(StringFormat("{0} PDFs, {1} ZIPs", pdf, zip) + StringFormat(" of {0} entries", n, ""));
نسخ ملف احتياطيًا قبل تحريره
انسخ مع الكتابة فوق الملف الموجود، ثم استبدل المحتوى.
path = ShellExpandEnvironmentVariables("%USERPROFILE%\\notes.txt");
if (FileExists(path)) {
FileCopy(path, path + ".bak", true);
FileEditText(path, StringToUpper(FileReadText(path)));
}
مراقبة مجلد
ادمج علامات FileNotify باستخدام |. البرنامج النصي للمراقبة قيمة Text، لذا تُهرَّب علامات الاقتباس
الداخلية فيه. ويقرأ ما حدث عبر ContextGetWatch*.
FolderWatchCreate("downloads",
ShellExpandEnvironmentVariables("%USERPROFILE%\\Downloads"),
false,
FileNotify.FileName | FileNotify.LastWrite,
"UtilityPrint(ContextGetWatchAction() + \": \" + ContextGetWatchPath());");
// later: FolderWatchDelete("downloads");
مؤقت متكرر يعدّ
للبرنامج النصي للمؤقت متغيراته الخاصة، لذا تنقل Storage العدد بين مرات الإطلاق. يُطلَق 5 مرات، بفاصل ثانية بين كل مرة.
StorageSetValue("ticks", 0);
TimerCreate("counter", 1000, 1000, 5,
"t = StorageGetValue(\"ticks\") + 1; StorageSetValue(\"ticks\", t); UtilityPrint(StringFormat(\"tick {0}\", t, \"\"));");
برنامج نصي للمؤقت من مقتطف، بلا تهريب
احتفظ بالبرنامج النصي الطويل للمؤقت في مقتطف ومرّر نصه، فلا تكون هناك علامات اقتباس متداخلة تحتاج إلى تهريب.
// Fires once, 10 minutes from now (repeat count 1).
TimerCreate("stretch-reminder", 600000, 1000, 1, SnippetGetScript("Stretch reminder"));
سرد المؤقتات وإيقافها
عدّد المؤقتات المسماة، واحذف أحدها أو كلها.
n = TimerEnumerateAll();
for (i = 0; i < n; i = i + 1) UtilityPrint(TimerGetEnumeratedNameAt(i));
TimerDelete("counter");
// TimerDeleteAll();
مفتاح تبديل يبقى بين مرات التشغيل
تُرجع StorageGetValue لمفتاح لم يُعيَّن قط القيمة Integer 0، وهي قيمة كاذبة، لذا يشغّل التشغيل الأول
الوضع. تبقى القيمة حتى يُنهي Input.Observer عمله؛ أما الدوال المضمَّنة Persistent فتحتفظ بالقيمة عبر
مرات إعادة التشغيل.
on = !StorageGetValue("quietMode");
StorageSetValue("quietMode", on);
MultimediaSetMute(AudioEndpoint.Playback, on);
if (on) ShellShowToast("Quiet mode", "On"); else ShellShowToast("Quiet mode", "Off");
عدّاد يبقى بعد إعادة التشغيل
تحتفظ الدوال المضمَّنة Storage*Persistent* بالقيم في storage.toml بجوار التكوين، لذا تبقى موجودة بعد
إعادة تشغيل Input.Observer. نص عادي غير مشفّر أبدًا: لا تحتفظ بكلمات المرور فيه. لا يمكن الاحتفاظ بقيم
Window؛ فالمقبض لا يعني شيئًا بعد إعادة التشغيل. إذا كان storage.toml موجودًا لكن تعذّرت قراءته عند
بدء تشغيل Input.Observer، فإن StorageSetPersistentValue تُرجع false: لا يُحتفظ بالقيمة إلا حتى خروج
Input.Observer، ولا يُحفظ شيء حتى بدء التشغيل التالي.
n = StorageGetPersistentValue("gestures.used") + 1; // 0 the first time ever
StorageSetPersistentValue("gestures.used", n);
UtilityPrint(StringFormat("{0} gestures since this counter started", n, ""));
قائمة محفوظة في Storage
لا توجد مصفوفات، لكن المفاتيح المرقّمة المبنية باستخدام StringFormat تعمل مثلها.
count = StorageGetValue("recent.count");
StorageSetValue(StringFormat("recent.{0}", count, ""), WindowGetTitle(ContextGetWindow()));
StorageSetValue("recent.count", count + 1);
for (i = 0; i <= count; i = i + 1) {
UtilityPrint(StorageGetValue(StringFormat("recent.{0}", i, "")));
}
السماح لإجراء واحد فقط بتشغيل مقطع في كل مرة
يمنع القفل المسمى تشغيلين متداخلين من التشابك. افحص النتيجة مقابل LockResult، وحرّر القفل عند الانتهاء.
r = UtilityLockAcquire("clipboard-work", 5);
if (r == LockResult.Acquired) {
ClipboardSave();
// ...work that must not overlap another run...
ClipboardRestore();
UtilityLockRelease("clipboard-work");
} else {
UtilityPrint("Another action is busy with the clipboard");
}
طرح سؤال
الأزرار والأيقونة أسماء من نوع Text. النتيجة هي اسم الزر الذي نُقر.
answer = UIShowMessageBox("Save the layout before closing?", "Input.Observer", "YesNoCancel", "Question");
if (answer == "Yes") {
UtilityPrint("saving");
} else if (answer == "No") {
UtilityPrint("discarding");
} else {
UtilityPrint("cancelled");
}
رفع مستوى الصوت مع عرض على الشاشة
مستوى الصوت قيمة Real من 0.0 إلى 1.0. تأخذ الدالة UIShowDisplayMessage عدد 19 وسيطة موضعية.
v = MathMin(MultimediaGetVolume(AudioEndpoint.Playback) + 0.05, 1.0);
MultimediaSetVolume(AudioEndpoint.Playback, v);
UIShowDisplayMessage(
"Volume", StringFormat("{0}%", MathRound(v * 100), ""),
1200, // durationMs
0.9, // opacity (Real)
Location.BottomCenter, // or a "x,y" Text point
"Segoe UI", 14, true, false, // title font, size, bold, italic
"Segoe UI", 12, false, false, // message font, size, bold, italic
"#1F1F1F", "#F7F7F5", // fore / back color: name, #RRGGBB or "R,G,B"
12, // padding
false, // usePrimaryScreen
TextAlign.Center, TextAlign.Center);
رسالة عرض تتحدث مباشرة
احتفظ بمعرّف الجلسة ومرّره إلى UIUpdateDisplayMessage مع الوسيطات الـ 19 نفسها.
id = UIShowDisplayMessage("Working", "0%", 10000, 0.95, Location.TopRight,
"Segoe UI", 12, true, false, "Segoe UI", 11, false, false,
"black", "255,255,255", 10, true, TextAlign.Left, TextAlign.Left);
for (p = 0; p <= 100; p = p + 20) {
UIUpdateDisplayMessage(id, "Working", StringFormat("{0}%", p, ""), 10000, 0.95, Location.TopRight,
"Segoe UI", 12, true, false, "Segoe UI", 11, false, false,
"black", "255,255,255", 10, true, TextAlign.Left, TextAlign.Left);
UtilityWait(400);
}
UICloseDisplayMessage(id);
إعلام Windows
عنوان ورسالة، يُعرضان كإعلام منبثق.
ShellShowToast("Input.Observer", StringFormat("Profile: {0}", GestureProfileGetActiveId(), ""));
تبديل كتم الميكروفون
نقطة النهاية Capture هي جهاز التسجيل الافتراضي.
MultimediaToggleMute(AudioEndpoint.Capture);
if (MultimediaGetMute(AudioEndpoint.Capture)) ShellShowToast("Microphone", "Muted");
else ShellShowToast("Microphone", "Live");
تشغيل صوت
ملفات WAV وMP3 من مسار.
MultimediaPlayWavFile("C:\\Windows\\Media\\chimes.wav");
تشغيل تطبيق أو التبديل إليه
ينشّط التطبيق إذا كان قيد التشغيل بالفعل، وإلا يبدأ تشغيله.
ShellRunOrActivate("notepad.exe");
تشغيل برنامج بفعل ونمط نافذة
الفعل ثابت من ShellVerb أو أي فعل كقيمة Text. نمط النافذة ثابت من WindowStyle.
ShellRunProgram("notepad.exe", "C:\\Temp\\todo.txt", ShellVerb.Open, WindowStyle.Maximized, false);
ShellRunProgram("C:\\Temp\\report.pdf", "", "print", WindowStyle.Hidden, false); // Text verb
التشغيل وانتظار الخروج
عند تعيين waitForExit إلى true، يُحظَر مؤشر ترابط البرنامج النصي حتى يُغلق البرنامج. يستمر تدفق
الإدخال في أثناء ذلك. يؤدي إيقاف كل الإجراءات إلى إنهاء الانتظار: يظل البرنامج قيد التشغيل ويُرجع
الاستدعاء false.
ShellRunProgram("notepad.exe", "", ShellVerb.Open, WindowStyle.Normal, true);
ShellShowToast("Notepad", "was closed");
توسيع متغيرات البيئة
يبني مسارًا يعمل على جهاز كل مستخدم.
UtilityPrint(ShellExpandEnvironmentVariables("%APPDATA%\\Input.Observer"));
UtilityPrint(ShellExpandEnvironmentVariables("%COMPUTERNAME% / %USERNAME%"));
التسليم إلى AutoHotkey
يشغّل تعليمات AutoHotkey البرمجية خارج العملية ويُرجع رمز خروجها، أو -1 إذا لم يُكوَّن AutoHotkey.
rc = AutoHotkeyExecuteScript("SoundBeep 750, 200");
if (rc == -1) UtilityPrint("AutoHotkey isn't set up");
سرد الشاشات
الاسم، والحدود الكاملة، ومنطقة العمل، وDPI لكل شاشة، حسب الفهرس.
n = DisplayMonitorEnumeratedAll();
for (i = 0; i < n; i = i + 1) {
UtilityPrint(StringFormat("#{0} {1}", i, DisplayMonitorGetEnumeratedFriendlyNameAt(i)));
UtilityPrint(StringFormat(" bounds {0} x {1}", DisplayMonitorGetEnumeratedWidthAt(i, false), DisplayMonitorGetEnumeratedHeightAt(i, false))
+ StringFormat(", work area {0} x {1}", DisplayMonitorGetEnumeratedWidthAt(i, true), DisplayMonitorGetEnumeratedHeightAt(i, true))
+ StringFormat(", {0} dpi", DisplayMonitorGetEnumeratedDpiAt(i), ""));
}
إرسال نافذة إلى شاشة محددة
حسب الفهرس من التعداد، مع الرجوع إلى الشاشة التالية عندما لا تكون تلك الشاشة موجودة.
w = ContextGetWindow();
if (DisplayMonitorEnumeratedAll() > 1) {
WindowSendToMonitorIndex(w, 1, false);
} else {
WindowSendToNextScreen(w, false);
}
الانتقال إلى ملف تعريف الإيماءات التالي
ابحث عن فهرس ملف التعريف النشط، وأضف واحدًا، ثم عُد إلى البداية باستخدام نمط باقي القسمة.
n = GestureProfileEnumerateAll();
if (n > 0) {
active = GestureProfileGetActiveId();
next = 0;
for (i = 0; i < n; i = i + 1) {
if (GestureProfileGetEnumeratedIdAt(i) == active) next = i + 1;
}
next = next - (next / n) * n; // next % n
GestureProfileSwitch(GestureProfileGetEnumeratedIdAt(next));
ShellShowToast("Gesture profile", GestureProfileGetEnumeratedNameAt(next));
}
حالة المحرك
اقرأ ما إذا كان المحرك معطّلًا أو في الوضع الآمن، ثم أوقفه مؤقتًا. أعد تمكينه من قائمة منطقة الإعلامات.
UtilityPrint(StringFormat("disabled={0} safeMode={1}", EngineIsDisabled(), EngineIsSafeMode()));
if (!EngineIsDisabled()) {
EngineDisable();
ShellShowToast("Input.Observer", "Paused. Re-enable it from the tray menu.");
}
تمرير السحب التالي بالزر الأيمن
يتخطى التقاط الإيماءة مرة واحدة، فيذهب السحب التالي بالزر الأيمن إلى التطبيق.
EngineDisableNextGesture();
المقتطفات كدوال قابلة لإعادة الاستخدام
مرّر الوسيطات والنتائج عبر Storage. يعمل المقتطف حتى اكتماله قبل السطر التالي.
// Snippet "Tile window" reads tile.index and positions ContextGetWindow() accordingly.
StorageSetValue("tile.index", 2);
SnippetExecuteScript("Tile window");
UtilityPrint(StringFormat("snippet reported: {0}", StorageGetValue("tile.result"), ""));
التواصل مع مكوّن إضافي
يرسل أمرًا من نوع Text إلى مكوّن إضافي متصل وينتظر رده من نوع Text حتى انقضاء المهلة.
reply = PluginSendMessage("MyRenderer", "theme dark", 2);
UtilityPrint("Plugin replied: " + reply);
طرح سؤال على جهاز تسلسلي
افتح المنفذ، واكتب سطرًا، وانتظر الرد لمدة تصل إلى ثانيتين، ثم أغلق المنفذ. التماثل وبتات التوقف ثوابت.
if (SerialOpenPort("COM3", 9600, SerialParity.None, 8, SerialStopBits.One, "\n")) {
SerialWriteTextLine("COM3", "PING", 9600);
reply = SerialGetTextLine("COM3", 2, 9600);
SerialClosePort("COM3");
if (reply) UtilityPrint("Device: " + reply); else UtilityPrint("No reply");
}
ربط أزرار جهاز تسلسلي بمفاتيح الوسائط
يشغّل المراقب برنامجه النصي لكل سطر مستلم. ContextGetSerialTextLine هو السطر.
SerialMonitorCreate("pad", "COM3", 115200, SerialParity.None, 8, SerialStopBits.One, "\n",
"line = StringTrim(ContextGetSerialTextLine()); if (line == \"B1\") KeyboardPressKey(VirtualKey.MediaPlayPause); else if (line == \"B2\") KeyboardPressKey(VirtualKey.MediaNextTrack);");
سرد منافذ COM
المنافذ الموجودة الآن، مثل المنفذ الذي حصلت عليه لوحة Arduino للتو عند توصيلها. راجع الأجهزة التسلسلية وArduino.
n = SerialEnumeratePorts();
if (n == 0) UtilityPrint("No COM ports. Is the board plugged in?");
for (i = 0; i < n; i = i + 1) {
UtilityPrint(SerialGetEnumeratedPortAt(i));
}
إبقاء منفذ Arduino مفتوحًا وإرسال الأوامر إليه
افتح المنفذ مرة واحدة، حتى لا تفوت اللوحةَ التي يُعاد تشغيلها عند فتح منفذها أي أوامر، ثم أرسل سطرًا واقرأ الرد.
// Load global event: open the port once, at the sketch's speed. An Uno or Nano
// restarts every time its port opens, so a port opened per command would lose
// the command while the board boots.
if (!SerialOpenPort("COM4", 115200, SerialParity.None, 8, SerialStopBits.One, "")) {
UtilityPrint("COM4 isn't available: unplugged, or open in the Arduino IDE's Serial Monitor?");
}
// Any gesture or hotkey: send a command line and read the board's reply.
// (The sketch reads a line with Serial.readStringUntil('\n') and answers OK.)
if (SerialWriteTextLine("COM4", "LED 255 0 0", 115200)) {
reply = SerialGetTextLine("COM4", 1, 115200);
if (reply != "OK") UtilityPrint(StringFormat("Board said: {0}", reply, ""));
}
تحويل مقبض Arduino إلى عنصر تحكم في مستوى الصوت
تصبح قراءة مقياس الجهد من 0 إلى 1023 في كل سطر مستوى صوت التشغيل.
// Arduino side: a potentiometer on A0, one reading per line.
// void setup() { Serial.begin(115200); }
// void loop() { Serial.println(analogRead(A0)); delay(50); }
// Empty text as the terminator means CR LF, which Serial.println sends.
SerialMonitorCreate("knob", "COM4", 115200, SerialParity.None, 8, SerialStopBits.One, "",
"line = ContextGetSerialTextLine(); if (StringIsNumber(line, true)) MultimediaSetVolume(AudioEndpoint.Playback, StringToNumber(line, true) / 1023.0);");