aboutsummaryrefslogtreecommitdiffstats
path: root/win-mouse.js
diff options
context:
space:
mode:
authoranekos2011-03-28 06:08:20 +0900
committeranekos2011-03-28 17:17:44 +0900
commit1d1c54834706f1e8a0146e2a0efee57ab991ff8f (patch)
treee100b2c8e2389b3b16a626b7aa359d9ecc87af82 /win-mouse.js
parent56a19251a97a715ff0612e15a9a9f8c9a6b99bef (diff)
downloadvimperator-plugins-1d1c54834706f1e8a0146e2a0efee57ab991ff8f.tar.bz2
MS Windows 用のマウス操作プラグイン
Diffstat (limited to 'win-mouse.js')
-rw-r--r--win-mouse.js276
1 files changed, 276 insertions, 0 deletions
diff --git a/win-mouse.js b/win-mouse.js
new file mode 100644
index 0000000..8ea9438
--- /dev/null
+++ b/win-mouse.js
@@ -0,0 +1,276 @@
+/* NEW BSD LICENSE {{{
+Copyright (c) 2011, anekos.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ 3. The names of the authors may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
+
+
+###################################################################################
+# http://sourceforge.jp/projects/opensource/wiki/licenses%2Fnew_BSD_license #
+# に参考になる日本語訳がありますが、有効なのは上記英文となります。 #
+###################################################################################
+
+}}} */
+
+// INFO {{{
+let INFO =
+<>
+ <plugin name="Win Cursor" version="1.0.0"
+ href="http://vimpr.github.com/"
+ summary="Cursor control plugin for MS Windows"
+ lang="en-US"
+ xmlns="http://vimperator.org/namespaces/liberator">
+ <author email="anekos@snca.net">anekos</author>
+ <license>New BSD License</license>
+ <project name="Vimperator" minVersion="3.0"/>
+ <p></p>
+ <item>
+ <tags>:cursor</tags>
+ <spec>:cursor <oa>-relative</oa> <oa>x</oa> <oa>y</oa></spec>
+ <description>
+ <p>
+ Move cursor to specified (x, y) position.
+ If not given position, display current cursor position.
+ </p>
+ </description>
+ </item>
+ </plugin>
+</>;
+// }}}
+
+(function () {
+
+ // ctypes {{{
+ Components.utils.import("resource://gre/modules/ctypes.jsm");
+ // }}}
+
+ // 定数 {{{
+ const INPUT_MOUSE = 0;
+ const MOUSEEVENTF_MOVE = 0x0001; /* mouse move */
+ const MOUSEEVENTF_LEFTDOWN = 0x0002; /* left button down */
+ const MOUSEEVENTF_LEFTUP = 0x0004; /* left button up */
+ const MOUSEEVENTF_RIGHTDOWN = 0x0008; /* right button down */
+ const MOUSEEVENTF_RIGHTUP = 0x0010; /* right button up */
+ const MOUSEEVENTF_MIDDLEDOWN = 0x0020; /* middle button down */
+ const MOUSEEVENTF_MIDDLEUP = 0x0040; /* middle button up */
+ const MOUSEEVENTF_XDOWN = 0x0080; /* x button down */
+ const MOUSEEVENTF_XUP = 0x0100; /* x button down */
+ const MOUSEEVENTF_WHEEL = 0x0800; /* wheel button rolled */
+ // #if (_WIN32_WINNT >= 0x0600)
+ // #define MOUSEEVENTF_HWHEEL 0x01000 /* hwheel button rolled */
+ // #endif
+ // #if(WINVER >= 0x0600)
+ // #define MOUSEEVENTF_MOVE_NOCOALESCE 0x2000 /* do not coalesce mouse moves */
+ // #endif /* WINVER >= 0x0600 */
+ const MOUSEEVENTF_VIRTUALDESK = 0x4000; /* map to entire virtual desktop */
+ const MOUSEEVENTF_ABSOLUTE = 0x8000; /* absolute move */
+ // }}}
+
+ // 構造体 {{{
+ const MouseInput =
+ new ctypes.StructType(
+ 'MouseInput',
+ [
+ {type: ctypes.uint32_t},
+ {dx: ctypes.int32_t},
+ {dy: ctypes.int32_t},
+ {mouseData: ctypes.uint32_t},
+ {flags: ctypes.uint32_t},
+ {time: ctypes.uint32_t},
+ {extraInfo: ctypes.uint32_t.ptr},
+ ]
+ );
+
+ const CursorPosition =
+ new ctypes.StructType(
+ 'CursorPosition',
+ [
+ {x: ctypes.uint32_t},
+ {y: ctypes.uint32_t},
+ ]
+ );
+ // }}}
+
+ // {{{ WinAPI
+ const User32 = ctypes.open("user32.dll");
+ const GetCursorPos =
+ User32.declare(
+ "GetCursorPos",
+ ctypes.winapi_abi,
+ ctypes.int32_t,
+ CursorPosition.ptr
+ );
+ const SetCursorPos =
+ User32.declare(
+ "SetCursorPos",
+ ctypes.winapi_abi,
+ ctypes.int32_t,
+ ctypes.int32_t,
+ ctypes.int32_t
+ );
+ const SendInput =
+ User32.declare(
+ "SendInput",
+ ctypes.winapi_abi,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ new ctypes.ArrayType(MouseInput, 2).ptr,
+ ctypes.uint32_t
+ );
+ // }}}
+
+ // Functions {{{
+ const ClickInput = new new ctypes.ArrayType(MouseInput, 2);
+
+ function buttonNameToClickValues (name) {
+ if (typeof name != 'string')
+ return;
+ switch (name.trim().toLowerCase()) {
+ case 'left':
+ return [MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP];
+ case 'right':
+ return [MOUSEEVENTF_RIGHTDOWN, MOUSEEVENTF_RIGHTUP];
+ case 'middle':
+ case 'center':
+ return [MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP];
+ }
+ }
+
+ const API = __context__.API = {
+ get position () {
+ let pos = new CursorPosition(0, 0);
+ GetCursorPos(pos.address());
+ return pos;
+ },
+
+ move: function (x, y, relative) {
+ if (relative) {
+ let pos = API.position;
+ SetCursorPos(pos.x + x, pos.y + y);
+ } else {
+ SetCursorPos(x, y);
+ }
+ },
+
+ click: function (name) {
+ let vs = buttonNameToClickValues(name || 'left');
+ if (!vs)
+ throw 'Unknown button name';
+ [ClickInput[0].flags, ClickInput[1].flags] = vs;
+ SendInput(2, ClickInput.address(), MouseInput.size);
+ }
+ };
+ // }}}
+
+ // Define mappings {{{
+ const D = function (v, p) (v * (p > 0 ? p : 10));
+ [
+ [['<A-h>'], 'left', -1, 0],
+ [['<A-l>'], 'right', 1, 0],
+ [['<A-k>'], 'up', 0, -1],
+ [['<A-j>'], 'down', 0, 1],
+ ].forEach(function ([keys, name, dx, dy]) {
+ mappings.addUserMap(
+ [modes.NORMAL],
+ keys,
+ 'Move cursor to' + name,
+ function (count) API.move(D(dx, count), D(dy, count), true),
+ {count: true}
+ );
+ });
+
+ mappings.addUserMap(
+ [modes.NORMAL],
+ ['<A-n>'],
+ 'Click (Left button)',
+ function () API.click('left')
+ );
+
+ mappings.addUserMap(
+ [modes.NORMAL],
+ ['<A-m>'],
+ 'Click (Right button)',
+ function () API.click('right')
+ );
+ // }}}
+
+ // Define commands {{{
+ function displayCurrent () {
+ let pos = API.position;
+ return liberator.echo(<>Position: {pos.x}, {pos.y}</>);
+ }
+
+ commands.addUserCommand(
+ ['mouse'],
+ 'Mouse control',
+ function () {
+ displayCurrent();
+ },
+ {
+ subCommands: [
+ new Command(
+ ['click'],
+ 'Click',
+ function (args) {
+ for (let [, button] in Iterator(args))
+ API.click(button);
+ },
+ {
+ bang: true,
+ completer: function (context, args) {
+ context.title = ['Button'];
+ context.completions = [[it, it] for ([, it] in Iterator('left right middle'.split(' ')))];
+ }
+ }
+ ),
+ new Command(
+ ['cursor'],
+ 'Move cursor',
+ function (args) {
+ let [x, y] = args.map(function (it) parseInt(it));
+
+ if (args.length <= 0)
+ return displayCurrent();
+
+ if (args.length == 1)
+ y = x;
+
+ API.move(x, y, args['-relative']);
+ },
+ {
+ bang: true,
+ options: [
+ [['-relative'], commands.OPTION_NOARG]
+ ],
+ }
+ )
+ ]
+ },
+ true
+ );
+ // }}}
+
+})();
+
+// vim:sw=2 ts=2 et si fdm=marker:
+