I am trying to write a sort of driver using python for windows 8. I will be receiving touch coordinates via serial which I then want to use to make it appear as though someone touched those coordinates on the screen (emulate a touch).
My first question is:
Is a touch event in Windows 8 different from just a mouse click at the area? (I know they revamped everything for touch events but am unsure of what that involved -- possibly like an area of effect thing to make it more touch screen friendly?)
Secondly:
If so, is there a library for python to emulate a 'touch' at a coordinate instead of a 'click'?
UPDATE:
Using ctypes and the page linked in the comments, I have created this:
from ctypes import *
#Constants
#For touchMask
TOUCH_MASK_NONE= 0x00000000 #Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
#For touchFlag
TOUCH_FLAG_NONE= 0x00000000
#For pointerType
PT_POINTER= 0x00000001#All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000#Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
#Structs Needed
class POINT(Structure):
_fields_=[("x", c_long),
("y", c_long)]
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_int32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",c_uint32),
("hwndTarget",c_uint32),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",c_uint32),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",c_uint32),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class RECT(Structure):
_fields_=[("left",c_long),
("top",c_long),
("right",c_long),
("bottom",c_long)]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
#Initialize Touch Injection
pointerInfo=POINTER_INFO(pointerType=PT_TOUCH,
pointerId=0,
ptPixelLocation=POINT(950,540))
touchInfo=POINTER_TOUCH_INFO(pointerInfo=pointerInfo,
touchFlags=TOUCH_FLAG_NONE,
touchMask=TOUCH_MASK_ALL,
rcContact=RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation=90,
pressure=32000)
if (windll.user32.InitializeTouchInjection(1,1) != 0):
print "Initialized Touch Injection"
#Press Down
touchInfo.pointerInfo.pointerFlags=(POINTER_FLAG_DOWN|
POINTER_FLAG_INRANGE|
POINTER_FLAG_INCONTACT)
if (windll.user32.InjectTouchInput(1, byref(touchInfo))==0):
print "Failed with Error: "+ FormatError()
else:
print "Touch Down Succeeded!"
#Pull Up
touchInfo.pointerInfo.pointerFlags=POINTER_FLAG_UP
if (windll.user32.InjectTouchInput(1,byref(touchInfo))==0):
print "Failed with Error: "+FormatError()
else:
print "Pull Up Succeeded!"
Fails everytime with error about the input parameters.
I've gone through every reference and can't find a type that seems incorrect. Does anyone see something obvious?
Thanks
Thanks to Eryksum and Xyroid, I was able to get it working. Thanks for putting up with my C-type / Windows ignorance. Here is the final script with the touch emulation packaged as a function (extra constants as well):
from ctypes import *
from ctypes.wintypes import *
#Constants
#For touchMask
TOUCH_MASK_NONE= 0x00000000 #Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
#For touchFlag
TOUCH_FLAG_NONE= 0x00000000
#For pointerType
PT_POINTER= 0x00000001#All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000#Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
#Structs Needed
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_uint32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",HANDLE),
("hwndTarget",HWND),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",DWORD),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",DWORD),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
#Initialize Pointer and Touch info
pointerInfo=POINTER_INFO(pointerType=PT_TOUCH,
pointerId=0,
ptPixelLocation=POINT(950,540))
touchInfo=POINTER_TOUCH_INFO(pointerInfo=pointerInfo,
touchFlags=TOUCH_FLAG_NONE,
touchMask=TOUCH_MASK_ALL,
rcContact=RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation=90,
pressure=32000)
def makeTouch(x,y,fingerRadius):
touchInfo.pointerInfo.ptPixelLocation.x=x
touchInfo.pointerInfo.ptPixelLocation.y=y
touchInfo.rcContact.left=x-fingerRadius
touchInfo.rcContact.right=x+fingerRadius
touchInfo.rcContact.top=y-fingerRadius
touchInfo.rcContact.bottom=y+fingerRadius
#Initialize Touch Injection
if (windll.user32.InitializeTouchInjection(1,1) != 0):
print "Initialized Touch Injection"
#Press Down
touchInfo.pointerInfo.pointerFlags=(POINTER_FLAG_DOWN|
POINTER_FLAG_INRANGE|
POINTER_FLAG_INCONTACT)
if (windll.user32.InjectTouchInput(1, byref(touchInfo))==0):
print "Failed with Error: "+ FormatError()
else:
print "Touch Down Succeeded!"
#Pull Up
touchInfo.pointerInfo.pointerFlags=POINTER_FLAG_UP
if (windll.user32.InjectTouchInput(1,byref(touchInfo))==0):
print "Failed with Error: "+FormatError()
else:
print "Pull Up Succeeded!"
return
#Ex:
#makeTouch(950,270,5)
For future multitouch travelers, the above example needs some significant massaging to create multiple touch events with a proper lifetime.
This includes maintaining persistent POINTER_TOUCH_INFO arrays, setting their ID's appropriately, and properly calling DOWN, UPDATE, and UP events as needed.
Hopefully this addition to the example script will save others time:
from ctypes import *
from ctypes.wintypes import *
# Constants
# For touchMask
TOUCH_MASK_NONE= 0x00000000 # Default
TOUCH_MASK_CONTACTAREA= 0x00000001
TOUCH_MASK_ORIENTATION= 0x00000002
TOUCH_MASK_PRESSURE= 0x00000004
TOUCH_MASK_ALL= 0x00000007
# For touchFlag
TOUCH_FLAG_NONE= 0x00000000
# For pointerType
PT_POINTER= 0x00000001 # All
PT_TOUCH= 0x00000002
PT_PEN= 0x00000003
PT_MOUSE= 0x00000004
#For pointerFlags
POINTER_FLAG_NONE= 0x00000000 # Default
POINTER_FLAG_NEW= 0x00000001
POINTER_FLAG_INRANGE= 0x00000002
POINTER_FLAG_INCONTACT= 0x00000004
POINTER_FLAG_FIRSTBUTTON= 0x00000010
POINTER_FLAG_SECONDBUTTON=0x00000020
POINTER_FLAG_THIRDBUTTON= 0x00000040
POINTER_FLAG_FOURTHBUTTON=0x00000080
POINTER_FLAG_FIFTHBUTTON= 0x00000100
POINTER_FLAG_PRIMARY= 0x00002000
POINTER_FLAG_CONFIDENCE= 0x00004000
POINTER_FLAG_CANCELED= 0x00008000
POINTER_FLAG_DOWN= 0x00010000
POINTER_FLAG_UPDATE= 0x00020000
POINTER_FLAG_UP= 0x00040000
POINTER_FLAG_WHEEL= 0x00080000
POINTER_FLAG_HWHEEL= 0x00100000
POINTER_FLAG_CAPTURECHANGED=0x00200000
# Structs Needed
class POINTER_INFO(Structure):
_fields_=[("pointerType",c_uint32),
("pointerId",c_uint32),
("frameId",c_uint32),
("pointerFlags",c_int),
("sourceDevice",HANDLE),
("hwndTarget",HWND),
("ptPixelLocation",POINT),
("ptHimetricLocation",POINT),
("ptPixelLocationRaw",POINT),
("ptHimetricLocationRaw",POINT),
("dwTime",DWORD),
("historyCount",c_uint32),
("inputData",c_int32),
("dwKeyStates",DWORD),
("PerformanceCount",c_uint64),
("ButtonChangeType",c_int)
]
class POINTER_TOUCH_INFO(Structure):
_fields_=[("pointerInfo",POINTER_INFO),
("touchFlags",c_int),
("touchMask",c_int),
("rcContact", RECT),
("rcContactRaw",RECT),
("orientation", c_uint32),
("pressure", c_uint32)]
# Initialize Pointer and Touch info
def initialize(maxtouches=10, dwmode=1):
global touches
touches = (POINTER_TOUCH_INFO * maxtouches)()
for ind in range(maxtouches):
pointerInfo=POINTER_INFO(pointerType = PT_TOUCH,
pointerId = ind,
ptPixelLocation = POINT(950,540),
pointerFlags = POINTER_FLAG_NEW)
touchInfo=POINTER_TOUCH_INFO(pointerInfo = pointerInfo,
touchFlags = TOUCH_FLAG_NONE,
touchMask = TOUCH_MASK_ALL,
rcContact = RECT(pointerInfo.ptPixelLocation.x-5,
pointerInfo.ptPixelLocation.y-5,
pointerInfo.ptPixelLocation.x+5,
pointerInfo.ptPixelLocation.y+5),
orientation = 90,
pressure = 32000)
touches[ind] = touchInfo
if (windll.user32.InitializeTouchInjection(len(touches), 1) != 0):
print("Initialized Touch Injection")
ids_to_update = 0
currently_down = None
def updateTouchInfo(id, down, x = 0, y = 0, fingerRadius=1, orientation = 90, pressure = 32000):
global currently_down, ids_to_update
if currently_down == None or len(currently_down) != len(touches):
currently_down = [False] * len(touches)
if down:
touches[id].pointerInfo.pointerFlags = (((POINTER_FLAG_DOWN) if not currently_down[id] else POINTER_FLAG_UPDATE)|
POINTER_FLAG_INRANGE |
POINTER_FLAG_INCONTACT)
touches[id].orientation = orientation
touches[id].pressure = pressure
touches[id].pointerInfo.ptPixelLocation.x = x
touches[id].pointerInfo.ptPixelLocation.y = y
touches[id].rcContact.left = x - fingerRadius
touches[id].rcContact.right = x + fingerRadius
touches[id].rcContact.top = y - fingerRadius
touches[id].rcContact.bottom = y + fingerRadius
else:
touches[id].pointerInfo.pointerFlags = POINTER_FLAG_UP #if currently_down[id] else POINTER_FLAG_UPDATE #if currently_down[id] else POINTER_FLAG_UPDATE
ids_to_update += 1 if down or currently_down[id] else 0
currently_down[id] = down
def applyTouches():
global ids_to_update
if ids_to_update > 0:
if (windll.user32.InjectTouchInput(int(ids_to_update), byref(touches[0])) == 0):
print("Failed trying to update", ids_to_update, "points with Error:", FormatError())
ids_to_update = 0
# Use like:
#import multitouch # Call once
#multitouch.initialize() # Call once
#for i in range(10): # Call every frame
# if i < len(keypoints):
# multitouch.updateTouchInfo(i, True,
# int(keypoints[i].pt[0] * 3),
# int(keypoints[i].pt[1] * 3),
# int(keypoints[i].size / 2))
# else:
# multitouch.updateTouchInfo(i, False)
#multitouch.applyTouches()
Related
I was following a tutorial for creating a new Gstreamer plugin in Python. The following example, took from here https://mathieuduponchelle.github.io/2018-02-01-Python-Elements.html , raises a Segmentation error (core dumped) at the end of its (correct) execution when running the gst-inspect-1.0 audiotestsrc_py.
If you remove the code __gproperties__ it seems to be fine. I am using Python 3.6 and Gstreamer 1.14.5.
Code:
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstBase', '1.0')
gi.require_version('GstAudio', '1.0')
from gi.repository import Gst, GLib, GObject, GstBase, GstAudio
import numpy as np
OCAPS = Gst.Caps.from_string (
'audio/x-raw, format=F32LE, layout=interleaved, rate=44100, channels=2')
SAMPLESPERBUFFER = 1024
DEFAULT_FREQ = 440
DEFAULT_VOLUME = 0.8
DEFAULT_MUTE = False
DEFAULT_IS_LIVE = False
class AudioTestSrc(GstBase.BaseSrc):
__gstmetadata__ = ('CustomSrc','Src', \
'Custom test src element', 'Mathieu Duponchelle')
__gproperties__ = {
"freq": (int,
"Frequency",
"Frequency of test signal",
1,
GLib.MAXINT,
DEFAULT_FREQ,
GObject.ParamFlags.READWRITE
),
"volume": (float,
"Volume",
"Volume of test signal",
0.0,
1.0,
DEFAULT_VOLUME,
GObject.ParamFlags.READWRITE
),
"mute": (bool,
"Mute",
"Mute the test signal",
DEFAULT_MUTE,
GObject.ParamFlags.READWRITE
),
"is-live": (bool,
"Is live",
"Whether to act as a live source",
DEFAULT_IS_LIVE,
GObject.ParamFlags.READWRITE
),
}
__gsttemplates__ = Gst.PadTemplate.new("src",
Gst.PadDirection.SRC,
Gst.PadPresence.ALWAYS,
OCAPS)
def __init__(self):
GstBase.BaseSrc.__init__(self)
self.info = GstAudio.AudioInfo()
self.freq = DEFAULT_FREQ
self.volume = DEFAULT_VOLUME
self.mute = DEFAULT_MUTE
self.set_live(DEFAULT_IS_LIVE)
self.set_format(Gst.Format.TIME)
def do_set_caps(self, caps):
self.info.from_caps(caps)
self.set_blocksize(self.info.bpf * SAMPLESPERBUFFER)
return True
def do_get_property(self, prop):
if prop.name == 'freq':
return self.freq
elif prop.name == 'volume':
return self.volume
elif prop.name == 'mute':
return self.mute
elif prop.name == 'is-live':
return self.is_live
else:
raise AttributeError('unknown property %s' % prop.name)
def do_set_property(self, prop, value):
if prop.name == 'freq':
self.freq = value
elif prop.name == 'volume':
self.volume = value
elif prop.name == 'mute':
self.mute = value
elif prop.name == 'is-live':
self.set_live(value)
else:
raise AttributeError('unknown property %s' % prop.name)
def do_start (self):
self.next_sample = 0
self.next_byte = 0
self.next_time = 0
self.accumulator = 0
self.generate_samples_per_buffer = SAMPLESPERBUFFER
return True
def do_gst_base_src_query(self, query):
if query.type == Gst.QueryType.LATENCY:
latency = Gst.util_uint64_scale_int(self.generate_samples_per_buffer,
Gst.SECOND, self.info.rate)
is_live = self.is_live
query.set_latency(is_live, latency, Gst.CLOCK_TIME_NONE)
res = True
else:
res = GstBase.BaseSrc.do_query(self, query)
return res
def do_get_times(self, buf):
end = 0
start = 0
if self.is_live:
ts = buf.pts
if ts != Gst.CLOCK_TIME_NONE:
duration = buf.duration
if duration != Gst.CLOCK_TIME_NONE:
end = ts + duration
start = ts
else:
start = Gst.CLOCK_TIME_NONE
end = Gst.CLOCK_TIME_NONE
return start, end
def do_create(self, offset, length):
if length == -1:
samples = SAMPLESPERBUFFER
else:
samples = int(length / self.info.bpf)
self.generate_samples_per_buffer = samples
bytes_ = samples * self.info.bpf
next_sample = self.next_sample + samples
next_byte = self.next_byte + bytes_
next_time = Gst.util_uint64_scale_int(next_sample, Gst.SECOND, self.info.rate)
if not self.mute:
r = np.repeat(
np.arange(self.accumulator, self.accumulator + samples),
self.info.channels)
data = ((np.sin(2 * np.pi * r * self.freq / self.info.rate) * self.volume)
.astype(np.float32))
else:
data = [0] * bytes_
buf = Gst.Buffer.new_wrapped(bytes(data))
buf.offset = self.next_sample
buf.offset_end = next_sample
buf.pts = self.next_time
buf.duration = next_time - self.next_time
self.next_time = next_time
self.next_sample = next_sample
self.next_byte = next_byte
self.accumulator += samples
self.accumulator %= self.info.rate / self.freq
return (Gst.FlowReturn.OK, buf)
__gstelementfactory__ = ("audiotestsrc_py", Gst.Rank.NONE, AudioTestSrc)
Output:
Factory Details:
Rank none (0)
Long-name CustomSrc
Klass Src
Description Custom test src element
Author Mathieu Duponchelle
Plugin Details:
Name python
Description loader for plugins written in python
Filename /usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstpython.cpython-36m-x86_64-linux-gnu.so
Version 1.14.5
License LGPL
Source module gst-python
Binary package GStreamer GObject Introspection overrides for Python
Origin URL http://gstreamer.freedesktop.org
GObject
+----GInitiallyUnowned
+----GstObject
+----GstElement
+----GstBaseSrc
+----audiotestsrc_py+AudioTestSrc
Pad Templates:
SRC template: 'src'
Availability: Always
Capabilities:
audio/x-raw
format: F32LE
layout: interleaved
rate: 44100
channels: 2
Element has no clocking capabilities.
Element has no URI handling capabilities.
Pads:
SRC: 'src'
Pad Template: 'src'
Element Properties:
name : The name of the object
flags: readable, writable
String. Default: "audiotestsrc_py+audiotestsrc0"
parent : The parent of the object
flags: readable, writable
Object of type "GstObject"
blocksize : Size in bytes to read per buffer (-1 = default)
flags: readable, writable
Unsigned Integer. Range: 0 - 4294967295 Default: 4096
num-buffers : Number of buffers to output before sending EOS (-1 = unlimited)
flags: readable, writable
Integer. Range: -1 - 2147483647 Default: -1
typefind : Run typefind before negotiating (deprecated, non-functional)
flags: readable, writable, deprecated
Boolean. Default: false
do-timestamp : Apply current stream time to buffers
flags: readable, writable
Boolean. Default: false
freq : Frequency of test signal
flags: readable, writable
Integer. Range: 1 - 2147483647 Default: 440
is-live : Whether to act as a live source
sys:1: Warning: g_object_get_property: assertion 'G_IS_OBJECT (object)' failed
flags: readable, writable
Boolean. Default: false
mute : Mute the test signal
flags: readable, writable
Boolean. Default: false
volume : Volume of test signal
flags: readable, writable
Double. Range: 0 - 1 Default: 0
Segmentation fault (core dumped)
I'm using Python3.5.1 serial module. When I open a port it fails with OS Error 22 (Windows Error 87) which signals failure to configure port, one of the arguments in OPEN system call were incorrect, or malformed.
My code uses loops over serial settings - that sends bad packets to the device until the device responds with a (readable) error message (so I know that my serial port is configured correctly). Yes, I should just know the device's settings but this isn't a prefect world.
import serial
import time
baud_rate = [50,75,110,134,150,200,300600,1200,1800,2400,4800,9600,19200,38400,57600,115200]
parity = [serial.PARITY_ODD,serial.PARITY_EVEN,serial.PARITY_NONE]
stop_bits = [serial.STOPBITS_TWO, serial.STOPBITS_ONE]
bytesize = [serial.SEVENBITS,serial.EIGHTBITS]
timeout = 5000
for b in baud_rate:
for p in parity:
for s in stop_bits:
for bs in bytesize:
ser = serial.Serial(port='COM3',baudrate=b,parity=p,stopbits=s,bytesize=bs)
try:
if ser.isOpen():
ser.write(b'TEST')
ser.reset_output_buffer()
time.sleep(1)
out = ser.read(3)
if out[0] == 64 and out[1] == 67 and out[2] == 32:
print("dumping settings")
print(ser.get_settings())
else:
ser.close()
except SerialException:
print("Serial Exception occured.")
pass
The problem happens under windows 7 x64 service pack 1. The python version is 3.5. The cmd.exe instance is ran as administrator.
I'm very sure COM3 exists when I run the script
import serial.tools.list_ports
ports = list(serial.tools.list_ports.comports())
for p in ports:
print(p)
I receive the output:
>python list_serial.py
COM3 - Prolific USB-to-Serial Comm Port (COM3)
So I believe the port URL/URI (idfk) is correct.
Full Error Text:
Traceback (most recent call last):
File "serial_reader.py", line 13, in <module>
ser = serial.Serial(port='COM3',baudrate=b,parity=p,stopbits=s,bytesize=bs)
File "C:\Users\FA1\AppData\Local\Programs\Python\Python35-32\lib\site-packages\serial\serialwin32.py", line 31, in __init__
SerialBase.__init__(self, *args, **kwargs)
File "C:\Users\FA1\AppData\Local\Programs\Python\Python35-32\lib\site-packages\serial\serialutil.py", line 180, in __init__
self.open()
File "C:\Users\FA1\AppData\Local\Programs\Python\Python35-32\lib\site-packages\serial\serialwin32.py", line 78, in open
self._reconfigure_port()
File "C:\Users\FA1\AppData\Local\Programs\Python\Python35-32\lib\site-packages\serial\serialwin32.py", line 220, in _reconfigure_port
raise SerialException("Cannot configure port, something went wrong. Original message: %r" % ctypes.WinError())
serial.serialutil.SerialException: Cannot configure port, something went wrong. Original message: OSError(22, 'The parameter is incorrect.', None, 87)
I've ensured the driver is properly installed, but I receive this error with 2 different serial converters. So I believe the issue isn't hardware or driver related.
You say that you "should just know the device's settings but this isn't a prefect world". But Windows does allow querying communications device properties via GetCommProperties. pySerial doesn't appear to support this, but you can use ctypes to call this function directly.
The following defines a get_comm_properties function to query the settable properties of a comm port. It accepts either an existing device handle (e.g. the _handle attribute of a pySerial port) or a DOS device name such as COM1 or WinAPI device name such as \\.\COM1.
import collections
import ctypes
from ctypes import wintypes
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 3
INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
ERROR_FILE_NOT_FOUND = 0x0002
class COMMPROP(ctypes.Structure):
_fields_= (('wPacketLength', wintypes.WORD),
('wPacketVersion', wintypes.WORD),
('dwServiceMask', wintypes.DWORD),
('dwReserved1', wintypes.DWORD),
('dwMaxTxQueue', wintypes.DWORD),
('dwMaxRxQueue', wintypes.DWORD),
('dwMaxBaud', wintypes.DWORD),
('dwProvSubType', wintypes.DWORD),
('dwProvCapabilities', wintypes.DWORD),
('dwSettableParams', wintypes.DWORD),
('dwSettableBaud', wintypes.DWORD),
('wSettableData', wintypes.WORD),
('wSettableStopParity', wintypes.WORD),
('dwCurrentTxQueue', wintypes.DWORD),
('dwCurrentRxQueue', wintypes.DWORD),
('dwProvSpec1', wintypes.DWORD),
('dwProvSpec2', wintypes.DWORD),
('wcProvChar', wintypes.WCHAR * 1))
class _CONST:
COMMPROP_INITIALIZED = 0xE73CF52E
SP_SERIALCOMM = 0x00000001
BAUD_USER = 0x10000000 # programmable baud rate
DATABITS_16X = 0x0020 # hardware wide data path
PROV_SUBTYPE = collections.OrderedDict([
('UNSPECIFIED', 0x00000000),
('RS232', 0x00000001),
('PARALLELPORT', 0x00000002),
('RS422', 0x00000003),
('RS423', 0x00000004),
('RS449', 0x00000005),
('MODEM', 0x00000006),
('FAX', 0x00000021),
('SCANNER', 0x00000022),
('NETWORK_BRIDGE', 0x00000100),
('LAT', 0x00000101),
('TCPIP_TELNET', 0x00000102),
('X25', 0x00000103),
])
PROV_CAPABILITIES = collections.OrderedDict([
('DTRDSR', 0x0001), # data-terminal-ready / data-set-ready
('RTSCTS', 0x0002), # request-to-send / clear-to-send
('RLSD', 0x0004), # receive-line-signal-detect
('PARITY_CHECK', 0x0008),
('XONXOFF', 0x0010), # XON/XOFF flow control
('SETXCHAR', 0x0020), # settable XON/XOFF
('TOTALTIMEOUTS', 0x0040), # total (elapsed) time-outs
('INTTIMEOUTS', 0x0080), # interval time-outs
('SPECIALCHARS', 0x0100),
('16BITMODE', 0x0200),
])
SETTABLE_PARAMS = collections.OrderedDict([
('PARITY', 0x0001),
('BAUD', 0x0002),
('DATABITS', 0x0004),
('STOPBITS', 0x0008),
('HANDSHAKING', 0x0010), # flow control
('PARITY_CHECK', 0x0020),
('RLSD', 0x0040), # receive-line-signal-detect
])
SETTABLE_BAUD = collections.OrderedDict([
(75, 0x00000001),
(110, 0x00000002),
(134.5, 0x00000004),
(150, 0x00000008),
(300, 0x00000010),
(600, 0x00000020),
(1200, 0x00000040),
(1800, 0x00000080),
(2400, 0x00000100),
(4800, 0x00000200),
(7200, 0x00000400),
(9600, 0x00000800),
(14400, 0x00001000),
(19200, 0x00002000),
(38400, 0x00004000),
(56000, 0x00008000),
(57600, 0x00040000),
(115200, 0x00020000),
(128000, 0x00010000),
])
SETTABLE_DATA = collections.OrderedDict([
(5, 0x0001), # 5 data bits
(6, 0x0002), # 6 data bits
(7, 0x0004), # 7 data bits
(8, 0x0008), # 8 data bits
(16, 0x0010), # 16 data bits
])
SETTABLE_STOP = collections.OrderedDict([
(1, 0x0001), # 1 stop bit
(1.5, 0x0002), # 1.5 stop bits
(2, 0x0004), # 2 stop bits
])
SETTABLE_PARITY = collections.OrderedDict([
('NONE', 0x0100), # no parity
('ODD', 0x0200), # odd parity
('EVEN', 0x0400), # even parity
('MARK', 0x0800), # mark parity
('SPACE', 0x1000), # space parity
])
#property
def max_baud(self):
s = self.dwMaxBaud
m = self._CONST.SETTABLE_BAUD
if s == self._CONST.BAUD_USER:
return 0
else:
return m[s]
#property
def prov_subtype(self):
s = self.dwProvSubType
m = self._CONST.PROV_SUBTYPE
return [x for x, c in m.items() if c & s]
#property
def prov_capabilities(self):
s = self.dwProvCapabilities
m = self._CONST.PROV_CAPABILITIES
return [x for x, c in m.items() if c & s]
#property
def settable_params(self):
s = self.dwSettableParams
m = self._CONST.SETTABLE_PARAMS
return [x for x, c in m.items() if c & s]
#property
def settable_baud(self):
s = self.dwSettableBaud
m = self._CONST.SETTABLE_BAUD
return [x for x, c in m.items() if c & s]
#property
def user_settable_baud(self):
return bool(self.dwSettableBaud & self._CONST.BAUD_USER)
#property
def settable_data(self):
s = self.wSettableData
m = self._CONST.SETTABLE_DATA
return [x for x, c in m.items() if c & s]
#property
def wide_settable_data(self):
return bool(self.wSettableData & self._CONST.DATABITS_16X)
#property
def settable_stop(self):
s = self.wSettableStopParity
m = self._CONST.SETTABLE_STOP
return [x for x, c in m.items() if c & s]
#property
def settable_parity(self):
s = self.wSettableStopParity
m = self._CONST.SETTABLE_PARITY
return [x for x, c in m.items() if c & s]
LPCOMMPROP = ctypes.POINTER(COMMPROP)
class SECURITY_ATTRIBUTES(ctypes.Structure):
_fields_ = (('nLength', wintypes.DWORD),
('lpSecurityDescriptor', wintypes.LPVOID),
('bInheritHandle', wintypes.BOOL))
LPSECURITY_ATTRIBUTES = ctypes.POINTER(SECURITY_ATTRIBUTES)
kernel32.CreateFileW.restype = wintypes.HANDLE
kernel32.CreateFileW.argtypes = (
wintypes.LPCWSTR, # _In_ lpFileName
wintypes.DWORD, # _In_ dwDesiredAccess
wintypes.DWORD, # _In_ dwShareMode
LPSECURITY_ATTRIBUTES, # _In_opt_ lpSecurityAttributes
wintypes.DWORD, # _In_ dwCreationDisposition
wintypes.DWORD, # _In_ dwFlagsAndAttributes
wintypes.HANDLE) # _In_opt_ hTemplateFile
kernel32.CloseHandle.argtypes = (wintypes.HANDLE,)
kernel32.GetCommProperties.argtypes = (
wintypes.HANDLE, # _In_ hFile
LPCOMMPROP) # _Out_ lpCommProp
def get_comm_properties(handle_or_port):
if isinstance(handle_or_port, str):
handle = kernel32.CreateFileW(
handle_or_port,
GENERIC_READ | GENERIC_WRITE,
0, # exclusive access
None, # default security
OPEN_EXISTING,
0,
None)
if handle == INVALID_HANDLE_VALUE:
raise ctypes.WinError(ctypes.get_last_error())
close_handle = True
else:
handle = handle_or_port
close_handle = False
try:
prop = COMMPROP()
if not kernel32.GetCommProperties(handle, ctypes.byref(prop)):
raise ctypes.WinError(ctypes.get_last_error())
finally:
if close_handle:
kernel32.CloseHandle(handle)
return prop
Example:
if __name__ == '__main__':
for i in range(1, 10):
port = r'\\.\COM%d' % i
try:
prop = get_comm_properties(port)
except WindowsError as e:
if e.winerror == ERROR_FILE_NOT_FOUND:
continue
print('%s properties' % port)
x = prop.dwMaxTxQueue if prop.dwMaxTxQueue else 'no limit'
print('\tMax output buffer size: %s' % x)
x = prop.dwMaxRxQueue if prop.dwMaxRxQueue else 'no limit'
print('\tMax input buffer size: %s' % x)
x = prop.dwCurrentTxQueue if prop.dwCurrentTxQueue else 'unavailable'
print('\tCurrent output buffer size: %s' % x)
x = prop.dwCurrentRxQueue if prop.dwCurrentRxQueue else 'unavailable'
print('\tCurrent input buffer size: %s' % x)
x = prop.max_baud if prop.max_baud else 'user programmable'
print('\tMax baud rate: %s' % x)
print('\tProvider subtypes:\n\t\t%s' %
'\n\t\t'.join(prop.prov_subtype))
print('\tProvider capabilities:\n\t\t%s' %
'\n\t\t'.join(prop.prov_capabilities))
print('\tSettable parameters:\n\t\t%s' %
'\n\t\t'.join(prop.settable_params))
print('\tSettable baud rates:\n\t\t%s' %
'\n\t\t'.join([str(x) for x in prop.settable_baud]))
print('\tSettable user baud rates: %s' %
prop.user_settable_baud)
print('\tSettable data bits:\n\t\t%s' %
'\n\t\t'.join([str(x) for x in prop.settable_data]))
print('\tSettable wide data bits: %s' %
prop.wide_settable_data)
print('\tSettable stop bits:\n\t\t%s' %
'\n\t\t'.join([str(x) for x in prop.settable_stop]))
print('\tSettable parity:\n\t\t%s' %
'\n\t\t'.join(prop.settable_parity))
Output:
\\.\COM1 properties
Max output buffer size: no limit
Max input buffer size: no limit
Current output buffer size: unavailable
Current input buffer size: 4096
Max baud rate: user programmable
Provider subtypes:
RS232
RS422
RS449
FAX
LAT
X25
Provider capabilities:
DTRDSR
RTSCTS
RLSD
PARITY_CHECK
XONXOFF
SETXCHAR
TOTALTIMEOUTS
INTTIMEOUTS
Settable parameters:
PARITY
BAUD
DATABITS
STOPBITS
HANDSHAKING
PARITY_CHECK
RLSD
Settable baud rates:
75
110
134.5
150
300
600
1200
1800
2400
4800
7200
9600
14400
19200
38400
56000
57600
115200
Settable user baud rates: True
Settable data bits:
5
6
7
8
Settable wide data bits: False
Settable stop bits:
1
1.5
2
Settable parity:
NONE
ODD
EVEN
MARK
SPACE
Baud rates <100 are treated as configuration errors in Windows 7. So starting the loop on 50,75 baud will both yield errors. 110 baud does not return an error.
I have 3 files lcdtest.py, lcd.py and alarmfunctionr.py.
I am trying to control the attached lcd display on my raspberry pi with the lcdtest.py script.
!/usr/bin/env python
import paho.mqtt.client as paho
import globals
import time
from alarmfunctionsr import SendToLCD
from lcd import noDisplay
from lcd import message
globals.init()
SendToLCD(12, "test lcd" ,1) #Test
time.sleep(5)
lcd.message("test with message")
time.sleep(5)
noDisplay
The import from alarmfunctionsr seem to work ok but i get an cannot import name error when i try the same for the lcd script.
lcd.py:
#!/usr/bin/python
#
# based on code from lrvick and LiquidCrystal
# lrvic - https://github.com/lrvick/raspi-hd44780/blob/master/hd44780.py
# LiquidCrystal - https://github.com/arduino/Arduino/blob/master/libraries/LiquidCrystal/LiquidCrystal.cpp
#
from time import sleep
class CharLCD(object):
# commands
LCD_CLEARDISPLAY = 0x01
LCD_RETURNHOME = 0x02
LCD_ENTRYMODESET = 0x04
LCD_DISPLAYCONTROL = 0x08
LCD_CURSORSHIFT = 0x10
LCD_FUNCTIONSET = 0x20
LCD_SETCGRAMADDR = 0x40
LCD_SETDDRAMADDR = 0x80
# flags for display entry mode
LCD_ENTRYRIGHT = 0x00
LCD_ENTRYLEFT = 0x02
LCD_ENTRYSHIFTINCREMENT = 0x01
LCD_ENTRYSHIFTDECREMENT = 0x00
# flags for display on/off control
LCD_DISPLAYON = 0x04
LCD_DISPLAYOFF = 0x00
LCD_CURSORON = 0x02
LCD_CURSOROFF = 0x00
LCD_BLINKON = 0x01
LCD_BLINKOFF = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
# flags for display/cursor shift
LCD_DISPLAYMOVE = 0x08
LCD_CURSORMOVE = 0x00
LCD_MOVERIGHT = 0x04
LCD_MOVELEFT = 0x00
# flags for function set
LCD_8BITMODE = 0x10
LCD_4BITMODE = 0x00
LCD_2LINE = 0x08
LCD_1LINE = 0x00
LCD_5x10DOTS = 0x04
LCD_5x8DOTS = 0x00
def __init__(self, pin_rs=25, pin_e=24, pins_db=[23, 17, 27, 22], GPIO=None):
# Emulate the old behavior of using RPi.GPIO if we haven't been given
# an explicit GPIO interface to use
if not GPIO:
import RPi.GPIO as GPIO
GPIO.setwarnings(False)
self.GPIO = GPIO
self.pin_rs = pin_rs
self.pin_e = pin_e
self.pins_db = pins_db
self.GPIO.setmode(GPIO.BCM)
self.GPIO.setup(self.pin_e, GPIO.OUT)
self.GPIO.setup(self.pin_rs, GPIO.OUT)
for pin in self.pins_db:
self.GPIO.setup(pin, GPIO.OUT)
self.write4bits(0x33) # initialization
self.write4bits(0x32) # initialization
self.write4bits(0x28) # 2 line 5x7 matrix
self.write4bits(0x0C) # turn cursor off 0x0E to enable cursor
self.write4bits(0x06) # shift cursor right
self.displaycontrol = self.LCD_DISPLAYON | self.LCD_CURSOROFF | self.LCD_BLINKOFF
self.displayfunction = self.LCD_4BITMODE | self.LCD_1LINE | self.LCD_5x8DOTS
self.displayfunction |= self.LCD_2LINE
# Initialize to default text direction (for romance languages)
self.displaymode = self.LCD_ENTRYLEFT | self.LCD_ENTRYSHIFTDECREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode) # set the entry mode
self.clear()
def begin(self, cols, lines):
if (lines > 1):
self.numlines = lines
self.displayfunction |= self.LCD_2LINE
def home(self):
self.write4bits(self.LCD_RETURNHOME) # set cursor position to zero
self.delayMicroseconds(3000) # this command takes a long time!
def clear(self):
self.write4bits(self.LCD_CLEARDISPLAY) # command to clear display
self.delayMicroseconds(3000) # 3000 microsecond sleep, clearing the display takes a long time
def setCursor(self, col, row):
self.row_offsets = [0x00, 0x40, 0x14, 0x54]
self.write4bits(self.LCD_SETDDRAMADDR | (col + self.row_offsets[row]))
def noDisplay(self):
""" Turn the display off (quickly) """
self.displaycontrol &= ~self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def display(self):
""" Turn the display on (quickly) """
self.displaycontrol |= self.LCD_DISPLAYON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noCursor(self):
""" Turns the underline cursor off """
self.displaycontrol &= ~self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def cursor(self):
""" Turns the underline cursor on """
self.displaycontrol |= self.LCD_CURSORON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def noBlink(self):
""" Turn the blinking cursor off """
self.displaycontrol &= ~self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def blink(self):
""" Turn the blinking cursor on """
self.displaycontrol |= self.LCD_BLINKON
self.write4bits(self.LCD_DISPLAYCONTROL | self.displaycontrol)
def DisplayLeft(self):
""" These commands scroll the display without changing the RAM """
self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVELEFT)
def scrollDisplayRight(self):
""" These commands scroll the display without changing the RAM """
self.write4bits(self.LCD_CURSORSHIFT | self.LCD_DISPLAYMOVE | self.LCD_MOVERIGHT)
def leftToRight(self):
""" This is for text that flows Left to Right """
self.displaymode |= self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def rightToLeft(self):
""" This is for text that flows Right to Left """
self.displaymode &= ~self.LCD_ENTRYLEFT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def autoscroll(self):
""" This will 'right justify' text from the cursor """
self.displaymode |= self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def noAutoscroll(self):
""" This will 'left justify' text from the cursor """
self.displaymode &= ~self.LCD_ENTRYSHIFTINCREMENT
self.write4bits(self.LCD_ENTRYMODESET | self.displaymode)
def write4bits(self, bits, char_mode=False):
""" Send command to LCD """
self.delayMicroseconds(1000) # 1000 microsecond sleep
bits = bin(bits)[2:].zfill(8)
self.GPIO.output(self.pin_rs, char_mode)
for pin in self.pins_db:
self.GPIO.output(pin, False)
for i in range(4):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i], True)
self.pulseEnable()
for pin in self.pins_db:
self.GPIO.output(pin, False)
for i in range(4, 8):
if bits[i] == "1":
self.GPIO.output(self.pins_db[::-1][i-4], True)
self.pulseEnable()
def delayMicroseconds(self, microseconds):
seconds = microseconds / float(1000000) # divide microseconds by 1 million for seconds
sleep(seconds)
def pulseEnable(self):
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, True)
self.delayMicroseconds(1) # 1 microsecond pause - enable pulse must be > 450ns
self.GPIO.output(self.pin_e, False)
self.delayMicroseconds(1) # commands need > 37us to settle
def message(self, text):
""" Send string to LCD. Newline wraps to second line"""
for char in text:
if char == '\n':
self.write4bits(0xC0) # next line
else:
self.write4bits(ord(char), True)
def DisplayLCD(msg):
lcd = CharLCD()
lcd.clear()
x=msg.find("**")
if x>0:
line1=msg[0:x]
line2=msg[x+2:len(msg)]
else:
line1=msg
line2=""
lcd.message(line1+"\n"+line2)
alarmfunctionsr.py:
#!/usr/bin/env python
"""
import globals
import urllib2
import smtplib
import serial
import time
import sys
import thread
import RPi.GPIO as GPIO
import os, glob, time, operator
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from time import sleep
def find_all(a_str, sub):
start = 0
cnt=0
while True:
start = a_str.find(sub, start)
if start == -1:
return cnt
start += len(sub)
cnt=cnt+1
def isNumber(x):
# Test whether the contents of a string is a number
try:
val = int(x)
except ValueError:
return False
return True
def get_latest_photo(files):
lt = operator.lt
if not files:
return None
now = time.time()
latest = files[0], now - os.path.getctime(files[0])
for f in files[1:]:
age = now - os.path.getctime(f)
if lt(age, latest[1]):
latest = f, age
return latest[0]
def UpdateHostThread(function,opcode):
try:
thread.start_new_thread(UpdateHostThread, (function,opcode, ) )
except:
print "Error: unable to start thread"
def UpdateHost(function,opcode):
# Sends data to the server
script_path = "https://www.privateeyepi.com/alarmhostr.php?u="+globals.user+"&p="+globals.password+"&function="+str(function)
i=0
for x in opcode:
script_path=script_path+"&opcode"+str(i)+"="+str(opcode[i])
i=i+1
if globals.PrintToScreen: print "Host Update: "+script_path
try:
rt=urllib2.urlopen(script_path)
except urllib2.HTTPError:
if globals.PrintToScreen: print "HTTP Error"
return False
time.sleep(.2)
temp=rt.read()
if globals.PrintToScreen: print temp
l = find_all(temp,"/n");
RecordSet = temp.split(',')
c=[]
y=0
c.append([])
for x in RecordSet:
if x=="/n":
y=y+1
if y < l:
c.append([])
else:
if isNumber(x):
c[y].append(int(x))
else:
c[y].append(x)
rt=ProcessActions(c)
if rt==False:
return(False)
else:
return(c)
def ProcessActions(ActionList):
FalseInd=True
for x in ActionList:
if x[0]=="/EMAIL":
SendEmailAlertFromRule(x[1], x[2],0)
x.remove
if x[0]=="/SEMAIL":
SendEmailAlert(x[1])
x.remove
if x[0]=="/CHIME":
StartChimeThread()
x.remove
if x[0]=="/rn588":
exit()
if x[0]=="/FALSE":
FalseInd=False
if x[0]=="/SIREN":
StartSirenThread(x[2])
x.remove
if x[0]=="/PHOTO":
SendEmailAlertFromRule(x[1], x[2],1)
x.remove
if x[0]=="/RELAYON":
SwitchRelay(1)
x.remove
if x[0]=="/RELAYOFF":
SwitchRelay(0)
x.remove
if x[0]=="/WRELAYON":
SwitchRFRelay(1)
x.remove
if x[0]=="/WRELAYOFF":
SwitchRFRelay(0)
x.remove
return(FalseInd)
def StartSirenThread(Zone):
try:
thread.start_new_thread(Siren, (Zone, ) )
except:
print "Error: unable to start thread"
def SwitchRelay(onoff):
GPIO.setmode(GPIO.BOARD)
GPIO.setup(globals.RelayPin, GPIO.OUT)
GPIO.output(globals.RelayPin,onoff)
def SwitchRFRelay(onoff):
# declare to variables, holding the com port we wish to talk to and the speed
port = '/dev/ttyAMA0'
baud = 9600
# open a serial connection using the variables above
ser = serial.Serial(port=port, baudrate=baud)
# wait for a moment before doing anything else
sleep(0.2)
for i in range(0,3):
if (onoff==True):
ser.write('a{}RELAYAON-'.format(globals.WRelayPin))
else:
ser.write('a{}RELAYAOFF'.format(globals.WRelayPin))
time.sleep(2)
ser.close
def SendToLCD(GPIOnumber, Location, status):
import paho.mqtt.client as paho
if status==0:
ActionStr="_"
topic="alarm_activity"
else:
if status==1:
ActionStr="_"
topic="alarm_activity"
else:
topic="temperature"
if status==2:
ActionStr=str(GPIOnumber)+","+Location
else:
ActionStr="Undefined"
#client = mosquitto.Mosquitto('privateeyepi')
client = paho.Client()
client.connect(globals.lcd_ip)
if status <= 1:
if globals.PrintToScreen:
print str(Location)+"**"+str(ActionStr)
client.publish(topic, str(Location)+"**"+str(ActionStr))
else:
if globals.PrintToScreen:
print str(ActionStr)
client.publish(topic, ActionStr)
client.disconnect()
def Siren(Zone):
GPIO.setmode(GPIO.BOARD)
if globals.UseSiren == True:
GPIO.setup(globals.SirenGPIOPin, GPIO.OUT) #Siren pin setup
else:
return
if globals.SirenDelay>0:
globals.SirenStartTime = time.time()
while time.time() < globals.SirenStartTime + globals.SirenDelay:
if globals.BeepDuringDelay:
GPIO.output(globals.SirenGPIOPin,True)
time.sleep(1)
GPIO.output(globals.SirenGPIOPin,False)
time.sleep(4)
GPIO.output(globals.SirenGPIOPin,True)
globals.SirenStartTime = time.time()
if globals.PrintToScreen: print "Siren Activated"
while time.time() < globals.SirenStartTime + globals.SirenTimeout:
time.sleep(5)
if CheckForSirenDeactivation(Zone) == True:
break
GPIO.output(globals.SirenGPIOPin,False)
if globals.PrintToScreen: print "Siren Deactivated"
def CheckForSirenDeactivation(Zone):
# Routine to fetch the location and zone descriptions from the server
RecordSet = GetDataFromHost(16,[Zone])
if globals.PrintToScreen: print RecordSet
ZoneStatus=RecordSet[0][0]
if ZoneStatus=="FALSE":
return (True)
def StartChimeThread():
try:
thread.start_new_thread(SoundChime, ())
except:
print "Error: unable to start thread"
def SoundChime():
if globals.ChimeDuration>0:
GPIO.setmode(GPIO.BOARD)
GPIO.setup(globals.ChimeGPIOPin, GPIO.OUT) #Siren pin setup
GPIO.output(globals.ChimeGPIOPin,True)
time.sleep(globals.ChimeDuration)
GPIO.output(globals.ChimeGPIOPin,False)
def GetDataFromHost(function,opcode):
# Request data and receive reply (request/reply) from the server
script_path = "https://www.privateeyepi.com/alarmhostr.php?u="+globals.user+"&p="+globals.password+"&function="+str(function)
i=0
for x in opcode:
script_path=script_path+"&opcode"+str(i)+"="+str(opcode[i])
i=i+1
if globals.PrintToScreen: print script_path
try:
rt = urllib2.urlopen(script_path)
except urllib2.HTTPError:
return False
temp=rt.read()
if globals.PrintToScreen: print temp
l = find_all(temp,"/n");
RecordSet = temp.split(',')
c=[]
y=0
c.append([])
for x in RecordSet:
if x=="/n":
y=y+1
if y < l:
c.append([])
else:
if isNumber(x):
c[y].append(int(x))
else:
c[y].append(x)
rt=ProcessActions(c)
if rt==False:
return(False)
else:
return(c)
return(c)
def BuildMessage(SensorNumber):
# Routine to fetch the location and zone descriptions from the server
RecordSet = GetDataFromHost(6,[SensorNumber])
if globals.PrintToScreen: print RecordSet
if RecordSet==False:
return
zonedesc=RecordSet[0][0]
locationdesc = RecordSet[0][1]
messagestr="This is an automated email from your house alarm system. Alarm activated for Zone: "+zonedesc+" ("+locationdesc+")"
return messagestr
def BuildMessageFromRule(SensorNumber, smartruleid):
RecordSet = GetDataFromHost(7,[smartruleid, SensorNumber])
if RecordSet==False:
return
numrows = len(RecordSet)
messagestr="This is an automated email from PrivateEyePi. Rule triggered for Zone(s): "+RecordSet[0][3]+", Location: "+RecordSet[0][4]+" and for rule "
for i in range(0,numrows,1):
if RecordSet[i][0]==1:
messagestr=messagestr+"Alarm Activated"
if RecordSet[i][0]==2:
messagestr=messagestr+"Alarm Deactivated"
if RecordSet[i][0]==3:
messagestr=messagestr+"Circuit Open"
if RecordSet[i][0]==4:
messagestr=messagestr+"Circuit Closed"
if RecordSet[i][0]==5:
messagestr=messagestr+"Open for " + str(RecordSet[i][1]) + " Minutes"
if RecordSet[i][0]==6:
messagestr=messagestr+"Closed for " + str(RecordSet[i][1]) + " Minutes"
if RecordSet[i][0]==7:
messagestr=messagestr+"Where sensor value (" + str(RecordSet[i][5]) + ") is between " + str(RecordSet[i][1]) + " " + str(RecordSet[i][2])
if RecordSet[i][0]==8:
messagestr=messagestr+"Tamper"
if RecordSet[i][0]==9:
messagestr=messagestr+"Day Of Week is between " + str(RecordSet[i][1]) + " and " + str(RecordSet[i][2])
if RecordSet[i][0]==10:
messagestr=messagestr+"Hour Of Day is between " + str(RecordSet[i][1]) + " and " + str(RecordSet[i][2])
if RecordSet[i][0]==11:
messagestr=messagestr+"Where secondary sensor value (" + str(RecordSet[i][6]) + ") is between " + str(RecordSet[i][1]) + " " + str(RecordSet[i][2])
if i<numrows-1:
messagestr=messagestr + " AND "
return messagestr
def SendEmailAlertFromRule(ruleid, SensorNumber, photo):
try:
thread.start_new_thread(SendEmailAlertThread, (SensorNumber, ruleid, True, photo, ) )
except:
print "Error: unable to start thread"
def SendEmailAlert(SensorNumber):
try:
thread.start_new_thread(SendEmailAlertThread, (SensorNumber,0 , False, False) )
except:
print "Error: unable to start thread"
def SendEmailAlertThread(SensorNumber, smartruleid, ruleind, photo):
# Get the email addresses that you configured on the server
RecordSet = GetDataFromHost(5,[0])
if RecordSet==False:
return
numrows = len(RecordSet)
if globals.smtp_server=="":
return
if ruleind:
msgtext = BuildMessageFromRule(SensorNumber, smartruleid)
else:
msgtext = BuildMessage(SensorNumber)
for i in range(numrows):
# Define email addresses to use
addr_to = RecordSet[i][0]
addr_from = globals.smtp_user #Or change to another valid email recognized under your account by your ISP
# Construct email
if (photo==1):
files = 0
files = glob.glob(globals.photopath)
latestphoto = get_latest_photo(files)
msg = MIMEMultipart()
else:
msg = MIMEText(msgtext)
msg['To'] = addr_to
msg['From'] = addr_from
msg['Subject'] = 'Alarm Notification' #Configure to whatever subject line you want
#attach photo
if (photo==1):
msg.preamble = 'Multipart message.\n'
part = MIMEText(msgtext)
msg.attach(part)
part = MIMEApplication(open(latestphoto,"rb").read())
part.add_header('Content-Disposition', 'attachment', filename=latestphoto)
msg.attach(part)
# Send the message via an SMTP server
#Option 1 - No Encryption
if globals.email_type==1:
s = smtplib.SMTP(globals.smtp_server)
elif globals.email_type==2:
#Option 2 - SSL
s = smtplib.SMTP_SSL(globals.smtp_server, 465)
elif globals.email_type==3:
#Option 3 - TLS
s = smtplib.SMTP(globals.smtp_server,587)
s.ehlo()
s.starttls()
s.ehlo()
else:
s = smtplib.SMTP(globals.smtp_server)
s.login(globals.smtp_user,globals.smtp_pass)
s.sendmail(addr_from, addr_to, msg.as_string())
s.quit()
if globals.PrintToScreen: print msg;
def SendCustomEmail(msgText, msgSubject):
# Get the email addresses that you configured on the server
RecordSet = GetDataFromHost(5,[0])
if RecordSet==False:
return
numrows = len(RecordSet)
if globals.smtp_server=="":
return
for i in range(numrows):
# Define email addresses to use
addr_to = RecordSet[i][0]
addr_from = globals.smtp_user #Or change to another valid email recognized under your account by your ISP
# Construct email
msg = MIMEText(msgText)
msg['To'] = addr_to
msg['From'] = addr_from
msg['Subject'] = msgSubject #Configure to whatever subject line you want
# Send the message via an SMTP server
#Option 1 - No Encryption
if globals.email_type==1:
s = smtplib.SMTP(globals.smtp_server)
elif globals.email_type==2:
#Option 2 - SSL
s = smtplib.SMTP_SSL(globals.smtp_server, 465)
elif globals.email_type==3:
#Option 3 - TLS
s = smtplib.SMTP(globals.smtp_server,587)
s.ehlo()
s.starttls()
s.ehlo()
else:
s = smtplib.SMTP(globals.smtp_server)
s.login(globals.smtp_user,globals.smtp_pass)
s.sendmail(addr_from, addr_to, msg.as_string())
s.quit()
if globals.PrintToScreen: print msg;
Your lcd.py module doesn't define any functions (or other top-level objects) named noDisplay or message, only a class named CharLCD and a function named DisplayLCD. So, when you try to import something that doesn't exist, of course you get an ImportError.
It's true that the CharLCD class has methods named noDisplay and message, but that doesn't mean you can just import them as top-level functions. (And, even if you could, you can't call them that way; you need a CharLCD object to call its methods.)
I suspect you need to read a basic tutorial on classes, like the Classes chapter in the official tutorial.
Meanwhile, I think the code you want is:
from lcd import CharLCD
# ...
char_lcd = CharLCD()
char_lcd.message("test with message")
time.sleep(5)
char_lcd.noDisplay()
(Also note the () in the last line. You need those parentheses to call a function or method; without them, you're just referring to the function or method itself, as a value, which has no more effect than just writing 2 on a line by itself.)
I've written a simple (test) script to list files in a selected directory. Not using FindFirstFile;
only native API.
When I execute the script and watch, Win32API monitor tells me STATUS_SUCCESS.
My File Information buffer is c_buffer(1024), not using a Unicode buffer to see the raw data.
So after call NtQueryDirectoryFile all is ok.
When I write c_buffer in raw mode to console to see the files in the directory, the output is not structured.
I created a FILE_DIRECTORY_INFORMATION structure but either it does not work Windows 7 X86 or there's a problem in my code.
My Question:
Please tell me which FILE_DIRECTORY_INFORMATION structure use on Windows 7 X86 or any variants
from ctypes import *
hFile = windll.kernel32.CreateFileW("C:\\a",0x80000000,0,0,3,0x02000000,0)
class Info(Union):
_fields_ = [('STATUS',c_long),
('Pointer',c_ulong),]
class io_stat(Structure):
_fields_ = [('Stat',Info),
('Information',c_ulong),]
class FILE_OBJECT(Structure):
_fields_ = [('Next',c_ulong),
('FileIndex',c_ulong),
('ctime',c_longlong),
('lat',c_longlong),
('wtime',c_longlong),
('ch',c_longlong),
('Endogfile',c_longlong),
('allo',c_longlong),
('Fileattr',c_ulong),
('Filenalen',c_ulong),
('Filename',c_wchar * 2),]
b = io_stat()
a = c_buffer(1024)
windll.ntdll.NtQueryDirectoryFile(hFile,0,0,0,byref(b),byref(a),sizeof(a), 1,0,None,0)
print(a.raw)
Not optimized.
NtQueryDirectoryFile should be called in a loop until it returns STATUS_NO_MORE_FILES. If either the returned status is STATUS_BUFFER_OVERFLOW or the status is successful (non-negative) with the status block Information as 0, then double the buffer size and try again. For each successful pass, copy the FILE_DIRECTORY_INFORMATION records out of the buffer. Each record has to be sized to include the FileName. You've reached the end when the Next field is 0.
The following example subclasses FILE_DIRECTORY_INFORMATION as a DirEntry class that has a listbuf class method to list the records in a queried buffer. It skips the "." and ".." entries. It uses this class in an ntlistdir function that lists the DirEntry records for a given directory via NtQueryDirectoryFile. It supports passing an open file descriptor as the path argument, which is like how os.listdir works on POSIX systems.
ctypes definitions
import os
import msvcrt
import ctypes
from ctypes import wintypes
ntdll = ctypes.WinDLL('ntdll')
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
def NtError(status):
err = ntdll.RtlNtStatusToDosError(status)
return ctypes.WinError(err)
NTSTATUS = wintypes.LONG
STATUS_BUFFER_OVERFLOW = NTSTATUS(0x80000005).value
STATUS_NO_MORE_FILES = NTSTATUS(0x80000006).value
STATUS_INFO_LENGTH_MISMATCH = NTSTATUS(0xC0000004).value
ERROR_DIRECTORY = 0x010B
INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
GENERIC_READ = 0x80000000
FILE_SHARE_READ = 1
OPEN_EXISTING = 3
FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
FILE_ATTRIBUTE_DIRECTORY = 0x0010
FILE_INFORMATION_CLASS = wintypes.ULONG
FileDirectoryInformation = 1
FileBasicInformation = 4
LPSECURITY_ATTRIBUTES = wintypes.LPVOID
PIO_APC_ROUTINE = wintypes.LPVOID
ULONG_PTR = wintypes.WPARAM
class UNICODE_STRING(ctypes.Structure):
_fields_ = (('Length', wintypes.USHORT),
('MaximumLength', wintypes.USHORT),
('Buffer', wintypes.LPWSTR))
PUNICODE_STRING = ctypes.POINTER(UNICODE_STRING)
class IO_STATUS_BLOCK(ctypes.Structure):
class _STATUS(ctypes.Union):
_fields_ = (('Status', NTSTATUS),
('Pointer', wintypes.LPVOID))
_anonymous_ = '_Status',
_fields_ = (('_Status', _STATUS),
('Information', ULONG_PTR))
PIO_STATUS_BLOCK = ctypes.POINTER(IO_STATUS_BLOCK)
ntdll.NtQueryInformationFile.restype = NTSTATUS
ntdll.NtQueryInformationFile.argtypes = (
wintypes.HANDLE, # In FileHandle
PIO_STATUS_BLOCK, # Out IoStatusBlock
wintypes.LPVOID, # Out FileInformation
wintypes.ULONG, # In Length
FILE_INFORMATION_CLASS) # In FileInformationClass
ntdll.NtQueryDirectoryFile.restype = NTSTATUS
ntdll.NtQueryDirectoryFile.argtypes = (
wintypes.HANDLE, # In FileHandle
wintypes.HANDLE, # In_opt Event
PIO_APC_ROUTINE, # In_opt ApcRoutine
wintypes.LPVOID, # In_opt ApcContext
PIO_STATUS_BLOCK, # Out IoStatusBlock
wintypes.LPVOID, # Out FileInformation
wintypes.ULONG, # In Length
FILE_INFORMATION_CLASS, # In FileInformationClass
wintypes.BOOLEAN, # In ReturnSingleEntry
PUNICODE_STRING, # In_opt FileName
wintypes.BOOLEAN) # In RestartScan
kernel32.CreateFileW.restype = wintypes.HANDLE
kernel32.CreateFileW.argtypes = (
wintypes.LPCWSTR, # In lpFileName
wintypes.DWORD, # In dwDesiredAccess
wintypes.DWORD, # In dwShareMode
LPSECURITY_ATTRIBUTES, # In_opt lpSecurityAttributes
wintypes.DWORD, # In dwCreationDisposition
wintypes.DWORD, # In dwFlagsAndAttributes
wintypes.HANDLE) # In_opt hTemplateFile
class FILE_BASIC_INFORMATION(ctypes.Structure):
_fields_ = (('CreationTime', wintypes.LARGE_INTEGER),
('LastAccessTime', wintypes.LARGE_INTEGER),
('LastWriteTime', wintypes.LARGE_INTEGER),
('ChangeTime', wintypes.LARGE_INTEGER),
('FileAttributes', wintypes.ULONG))
class FILE_DIRECTORY_INFORMATION(ctypes.Structure):
_fields_ = (('_Next', wintypes.ULONG),
('FileIndex', wintypes.ULONG),
('CreationTime', wintypes.LARGE_INTEGER),
('LastAccessTime', wintypes.LARGE_INTEGER),
('LastWriteTime', wintypes.LARGE_INTEGER),
('ChangeTime', wintypes.LARGE_INTEGER),
('EndOfFile', wintypes.LARGE_INTEGER),
('AllocationSize', wintypes.LARGE_INTEGER),
('FileAttributes', wintypes.ULONG),
('FileNameLength', wintypes.ULONG),
('_FileName', wintypes.WCHAR * 1))
#property
def FileName(self):
addr = ctypes.addressof(self) + type(self)._FileName.offset
size = self.FileNameLength // ctypes.sizeof(wintypes.WCHAR)
return (wintypes.WCHAR * size).from_address(addr).value
DirEntry and ntlistdir
class DirEntry(FILE_DIRECTORY_INFORMATION):
def __repr__(self):
return '<{} {!r}>'.format(self.__class__.__name__, self.FileName)
#classmethod
def listbuf(cls, buf):
result = []
base_size = ctypes.sizeof(cls) - ctypes.sizeof(wintypes.WCHAR)
offset = 0
while True:
fdi = cls.from_buffer(buf, offset)
if fdi.FileNameLength and fdi.FileName not in ('.', '..'):
cfdi = cls()
size = base_size + fdi.FileNameLength
ctypes.resize(cfdi, size)
ctypes.memmove(ctypes.byref(cfdi), ctypes.byref(fdi), size)
result.append(cfdi)
if fdi._Next:
offset += fdi._Next
else:
break
return result
def isdir(path):
if not isinstance(path, int):
return os.path.isdir(path)
try:
hFile = msvcrt.get_osfhandle(path)
except IOError:
return False
iosb = IO_STATUS_BLOCK()
info = FILE_BASIC_INFORMATION()
status = ntdll.NtQueryInformationFile(hFile, ctypes.byref(iosb),
ctypes.byref(info), ctypes.sizeof(info),
FileBasicInformation)
return bool(status >= 0 and info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
def ntlistdir(path=None):
result = []
if path is None:
path = os.getcwd()
if isinstance(path, int):
close = False
fd = path
hFile = msvcrt.get_osfhandle(fd)
else:
close = True
hFile = kernel32.CreateFileW(path, GENERIC_READ, FILE_SHARE_READ,
None, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, None)
if hFile == INVALID_HANDLE_VALUE:
raise ctypes.WinError(ctypes.get_last_error())
fd = msvcrt.open_osfhandle(hFile, os.O_RDONLY)
try:
if not isdir(fd):
raise ctypes.WinError(ERROR_DIRECTORY)
iosb = IO_STATUS_BLOCK()
info = (ctypes.c_char * 4096)()
while True:
status = ntdll.NtQueryDirectoryFile(hFile, None, None, None,
ctypes.byref(iosb), ctypes.byref(info),
ctypes.sizeof(info), FileDirectoryInformation,
False, None, False)
if (status == STATUS_BUFFER_OVERFLOW or
iosb.Information == 0 and status >= 0):
info = (ctypes.c_char * (ctypes.sizeof(info) * 2))()
elif status == STATUS_NO_MORE_FILES:
break
elif status >= 0:
sublist = DirEntry.listbuf(info)
result.extend(sublist)
else:
raise NtError(status)
finally:
if close:
os.close(fd)
return result
Example
if __name__ == '__main__':
import sys
for entry in ntlistdir(sys.exec_prefix):
print(entry)
Output:
<DirEntry 'DLLs'>
<DirEntry 'include'>
<DirEntry 'Lib'>
<DirEntry 'libs'>
<DirEntry 'LICENSE.txt'>
<DirEntry 'NEWS.txt'>
<DirEntry 'python.exe'>
<DirEntry 'python.pdb'>
<DirEntry 'python3.dll'>
<DirEntry 'python36.dll'>
<DirEntry 'python36.pdb'>
<DirEntry 'python36_d.dll'>
<DirEntry 'python36_d.pdb'>
<DirEntry 'python3_d.dll'>
<DirEntry 'pythonw.exe'>
<DirEntry 'pythonw.pdb'>
<DirEntry 'pythonw_d.exe'>
<DirEntry 'pythonw_d.pdb'>
<DirEntry 'python_d.exe'>
<DirEntry 'python_d.pdb'>
<DirEntry 'Scripts'>
<DirEntry 'tcl'>
<DirEntry 'Tools'>
<DirEntry 'vcruntime140.dll'>
After searching for several hours i´m wondering if its possible to simulate a keydown press on the keyboard. For example I want my program to hold the x key down for five seconds so when I run it in notepad it would look like to see something like this: xxxxxxxxxxxxx. I tried around with different pieces of code on the internet, the best thing I could find so far is this:
import ctypes
import time
user32 = ctypes.windll.user32
inputhex = raw_input("Please enter your desired key's code (HEX): ")
keycode = int(inputhex, 16)
time.sleep(1)
#VOID keybd_event(BYTE bVk, BYTE bScan, DWORD dwFlags, PTR dwExtraInfo);
user32.keybd_event(keycode,0,2,0) #is the code for KEYDOWN
time.sleep(5)
#user32.keybd_event(keycode,0,0,0) #is the code for KEYDUP[/code]
The Sendkey module doesn't solve my problem either becuase it only allows you to send a single keypress and not a hold key down event. I know about autoit, used it in the past, but I just really want to know if this is possible with python and how.
P.S. i'm using python for windows
This code should get you started. ctypes is used heavily. At the bottom, you will see example code.
import ctypes
LONG = ctypes.c_long
DWORD = ctypes.c_ulong
ULONG_PTR = ctypes.POINTER(DWORD)
WORD = ctypes.c_ushort
class MOUSEINPUT(ctypes.Structure):
_fields_ = (('dx', LONG),
('dy', LONG),
('mouseData', DWORD),
('dwFlags', DWORD),
('time', DWORD),
('dwExtraInfo', ULONG_PTR))
class KEYBDINPUT(ctypes.Structure):
_fields_ = (('wVk', WORD),
('wScan', WORD),
('dwFlags', DWORD),
('time', DWORD),
('dwExtraInfo', ULONG_PTR))
class HARDWAREINPUT(ctypes.Structure):
_fields_ = (('uMsg', DWORD),
('wParamL', WORD),
('wParamH', WORD))
class _INPUTunion(ctypes.Union):
_fields_ = (('mi', MOUSEINPUT),
('ki', KEYBDINPUT),
('hi', HARDWAREINPUT))
class INPUT(ctypes.Structure):
_fields_ = (('type', DWORD),
('union', _INPUTunion))
def SendInput(*inputs):
nInputs = len(inputs)
LPINPUT = INPUT * nInputs
pInputs = LPINPUT(*inputs)
cbSize = ctypes.c_int(ctypes.sizeof(INPUT))
return ctypes.windll.user32.SendInput(nInputs, pInputs, cbSize)
INPUT_MOUSE = 0
INPUT_KEYBOARD = 1
INPUT_HARDWARE = 2
def Input(structure):
if isinstance(structure, MOUSEINPUT):
return INPUT(INPUT_MOUSE, _INPUTunion(mi=structure))
if isinstance(structure, KEYBDINPUT):
return INPUT(INPUT_KEYBOARD, _INPUTunion(ki=structure))
if isinstance(structure, HARDWAREINPUT):
return INPUT(INPUT_HARDWARE, _INPUTunion(hi=structure))
raise TypeError('Cannot create INPUT structure!')
WHEEL_DELTA = 120
XBUTTON1 = 0x0001
XBUTTON2 = 0x0002
MOUSEEVENTF_ABSOLUTE = 0x8000
MOUSEEVENTF_HWHEEL = 0x01000
MOUSEEVENTF_MOVE = 0x0001
MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000
MOUSEEVENTF_LEFTDOWN = 0x0002
MOUSEEVENTF_LEFTUP = 0x0004
MOUSEEVENTF_RIGHTDOWN = 0x0008
MOUSEEVENTF_RIGHTUP = 0x0010
MOUSEEVENTF_MIDDLEDOWN = 0x0020
MOUSEEVENTF_MIDDLEUP = 0x0040
MOUSEEVENTF_VIRTUALDESK = 0x4000
MOUSEEVENTF_WHEEL = 0x0800
MOUSEEVENTF_XDOWN = 0x0080
MOUSEEVENTF_XUP = 0x0100
def MouseInput(flags, x, y, data):
return MOUSEINPUT(x, y, data, flags, 0, None)
VK_LBUTTON = 0x01 # Left mouse button
VK_RBUTTON = 0x02 # Right mouse button
VK_CANCEL = 0x03 # Control-break processing
VK_MBUTTON = 0x04 # Middle mouse button (three-button mouse)
VK_XBUTTON1 = 0x05 # X1 mouse button
VK_XBUTTON2 = 0x06 # X2 mouse button
VK_BACK = 0x08 # BACKSPACE key
VK_TAB = 0x09 # TAB key
VK_CLEAR = 0x0C # CLEAR key
VK_RETURN = 0x0D # ENTER key
VK_SHIFT = 0x10 # SHIFT key
VK_CONTROL = 0x11 # CTRL key
VK_MENU = 0x12 # ALT key
VK_PAUSE = 0x13 # PAUSE key
VK_CAPITAL = 0x14 # CAPS LOCK key
VK_KANA = 0x15 # IME Kana mode
VK_HANGUL = 0x15 # IME Hangul mode
VK_JUNJA = 0x17 # IME Junja mode
VK_FINAL = 0x18 # IME final mode
VK_HANJA = 0x19 # IME Hanja mode
VK_KANJI = 0x19 # IME Kanji mode
VK_ESCAPE = 0x1B # ESC key
VK_CONVERT = 0x1C # IME convert
VK_NONCONVERT = 0x1D # IME nonconvert
VK_ACCEPT = 0x1E # IME accept
VK_MODECHANGE = 0x1F # IME mode change request
VK_SPACE = 0x20 # SPACEBAR
VK_PRIOR = 0x21 # PAGE UP key
VK_NEXT = 0x22 # PAGE DOWN key
VK_END = 0x23 # END key
VK_HOME = 0x24 # HOME key
VK_LEFT = 0x25 # LEFT ARROW key
VK_UP = 0x26 # UP ARROW key
VK_RIGHT = 0x27 # RIGHT ARROW key
VK_DOWN = 0x28 # DOWN ARROW key
VK_SELECT = 0x29 # SELECT key
VK_PRINT = 0x2A # PRINT key
VK_EXECUTE = 0x2B # EXECUTE key
VK_SNAPSHOT = 0x2C # PRINT SCREEN key
VK_INSERT = 0x2D # INS key
VK_DELETE = 0x2E # DEL key
VK_HELP = 0x2F # HELP key
VK_LWIN = 0x5B # Left Windows key (Natural keyboard)
VK_RWIN = 0x5C # Right Windows key (Natural keyboard)
VK_APPS = 0x5D # Applications key (Natural keyboard)
VK_SLEEP = 0x5F # Computer Sleep key
VK_NUMPAD0 = 0x60 # Numeric keypad 0 key
VK_NUMPAD1 = 0x61 # Numeric keypad 1 key
VK_NUMPAD2 = 0x62 # Numeric keypad 2 key
VK_NUMPAD3 = 0x63 # Numeric keypad 3 key
VK_NUMPAD4 = 0x64 # Numeric keypad 4 key
VK_NUMPAD5 = 0x65 # Numeric keypad 5 key
VK_NUMPAD6 = 0x66 # Numeric keypad 6 key
VK_NUMPAD7 = 0x67 # Numeric keypad 7 key
VK_NUMPAD8 = 0x68 # Numeric keypad 8 key
VK_NUMPAD9 = 0x69 # Numeric keypad 9 key
VK_MULTIPLY = 0x6A # Multiply key
VK_ADD = 0x6B # Add key
VK_SEPARATOR = 0x6C # Separator key
VK_SUBTRACT = 0x6D # Subtract key
VK_DECIMAL = 0x6E # Decimal key
VK_DIVIDE = 0x6F # Divide key
VK_F1 = 0x70 # F1 key
VK_F2 = 0x71 # F2 key
VK_F3 = 0x72 # F3 key
VK_F4 = 0x73 # F4 key
VK_F5 = 0x74 # F5 key
VK_F6 = 0x75 # F6 key
VK_F7 = 0x76 # F7 key
VK_F8 = 0x77 # F8 key
VK_F9 = 0x78 # F9 key
VK_F10 = 0x79 # F10 key
VK_F11 = 0x7A # F11 key
VK_F12 = 0x7B # F12 key
VK_F13 = 0x7C # F13 key
VK_F14 = 0x7D # F14 key
VK_F15 = 0x7E # F15 key
VK_F16 = 0x7F # F16 key
VK_F17 = 0x80 # F17 key
VK_F18 = 0x81 # F18 key
VK_F19 = 0x82 # F19 key
VK_F20 = 0x83 # F20 key
VK_F21 = 0x84 # F21 key
VK_F22 = 0x85 # F22 key
VK_F23 = 0x86 # F23 key
VK_F24 = 0x87 # F24 key
VK_NUMLOCK = 0x90 # NUM LOCK key
VK_SCROLL = 0x91 # SCROLL LOCK key
VK_LSHIFT = 0xA0 # Left SHIFT key
VK_RSHIFT = 0xA1 # Right SHIFT key
VK_LCONTROL = 0xA2 # Left CONTROL key
VK_RCONTROL = 0xA3 # Right CONTROL key
VK_LMENU = 0xA4 # Left MENU key
VK_RMENU = 0xA5 # Right MENU key
VK_BROWSER_BACK = 0xA6 # Browser Back key
VK_BROWSER_FORWARD = 0xA7 # Browser Forward key
VK_BROWSER_REFRESH = 0xA8 # Browser Refresh key
VK_BROWSER_STOP = 0xA9 # Browser Stop key
VK_BROWSER_SEARCH = 0xAA # Browser Search key
VK_BROWSER_FAVORITES = 0xAB # Browser Favorites key
VK_BROWSER_HOME = 0xAC # Browser Start and Home key
VK_VOLUME_MUTE = 0xAD # Volume Mute key
VK_VOLUME_DOWN = 0xAE # Volume Down key
VK_VOLUME_UP = 0xAF # Volume Up key
VK_MEDIA_NEXT_TRACK = 0xB0 # Next Track key
VK_MEDIA_PREV_TRACK = 0xB1 # Previous Track key
VK_MEDIA_STOP = 0xB2 # Stop Media key
VK_MEDIA_PLAY_PAUSE = 0xB3 # Play/Pause Media key
VK_LAUNCH_MAIL = 0xB4 # Start Mail key
VK_LAUNCH_MEDIA_SELECT = 0xB5 # Select Media key
VK_LAUNCH_APP1 = 0xB6 # Start Application 1 key
VK_LAUNCH_APP2 = 0xB7 # Start Application 2 key
VK_OEM_1 = 0xBA # Used for miscellaneous characters; it can vary by keyboard.
# For the US standard keyboard, the ';:' key
VK_OEM_PLUS = 0xBB # For any country/region, the '+' key
VK_OEM_COMMA = 0xBC # For any country/region, the ',' key
VK_OEM_MINUS = 0xBD # For any country/region, the '-' key
VK_OEM_PERIOD = 0xBE # For any country/region, the '.' key
VK_OEM_2 = 0xBF # Used for miscellaneous characters; it can vary by keyboard.
# For the US standard keyboard, the '/?' key
VK_OEM_3 = 0xC0 # Used for miscellaneous characters; it can vary by keyboard.
# For the US standard keyboard, the '`~' key
VK_OEM_4 = 0xDB # Used for miscellaneous characters; it can vary by keyboard.
# For the US standard keyboard, the '[{' key
VK_OEM_5 = 0xDC # Used for miscellaneous characters; it can vary by keyboard.
# For the US standard keyboard, the '\|' key
VK_OEM_6 = 0xDD # Used for miscellaneous characters; it can vary by keyboard.
# For the US standard keyboard, the ']}' key
VK_OEM_7 = 0xDE # Used for miscellaneous characters; it can vary by keyboard.
# For the US standard keyboard, the 'single-quote/double-quote' key
VK_OEM_8 = 0xDF # Used for miscellaneous characters; it can vary by keyboard.
VK_OEM_102 = 0xE2 # Either the angle bracket key or the backslash key on the RT 102-key keyboard
VK_PROCESSKEY = 0xE5 # IME PROCESS key
VK_PACKET = 0xE7 # Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP
VK_ATTN = 0xF6 # Attn key
VK_CRSEL = 0xF7 # CrSel key
VK_EXSEL = 0xF8 # ExSel key
VK_EREOF = 0xF9 # Erase EOF key
VK_PLAY = 0xFA # Play key
VK_ZOOM = 0xFB # Zoom key
VK_PA1 = 0xFD # PA1 key
VK_OEM_CLEAR = 0xFE # Clear key
KEYEVENTF_EXTENDEDKEY = 0x0001
KEYEVENTF_KEYUP = 0x0002
KEYEVENTF_SCANCODE = 0x0008
KEYEVENTF_UNICODE = 0x0004
KEY_0 = 0x30
KEY_1 = 0x31
KEY_2 = 0x32
KEY_3 = 0x33
KEY_4 = 0x34
KEY_5 = 0x35
KEY_6 = 0x36
KEY_7 = 0x37
KEY_8 = 0x38
KEY_9 = 0x39
KEY_A = 0x41
KEY_B = 0x42
KEY_C = 0x43
KEY_D = 0x44
KEY_E = 0x45
KEY_F = 0x46
KEY_G = 0x47
KEY_H = 0x48
KEY_I = 0x49
KEY_J = 0x4A
KEY_K = 0x4B
KEY_L = 0x4C
KEY_M = 0x4D
KEY_N = 0x4E
KEY_O = 0x4F
KEY_P = 0x50
KEY_Q = 0x51
KEY_R = 0x52
KEY_S = 0x53
KEY_T = 0x54
KEY_U = 0x55
KEY_V = 0x56
KEY_W = 0x57
KEY_X = 0x58
KEY_Y = 0x59
KEY_Z = 0x5A
def KeybdInput(code, flags):
return KEYBDINPUT(code, code, flags, 0, None)
def HardwareInput(message, parameter):
return HARDWAREINPUT(message & 0xFFFFFFFF,
parameter & 0xFFFF,
parameter >> 16 & 0xFFFF)
def Mouse(flags, x=0, y=0, data=0):
return Input(MouseInput(flags, x, y, data))
def Keyboard(code, flags=0):
return Input(KeybdInput(code, flags))
def Hardware(message, parameter=0):
return Input(HardwareInput(message, parameter))
################################################################################
import string
UPPER = frozenset('~!##$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?')
LOWER = frozenset("`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./")
ORDER = string.ascii_letters + string.digits + ' \b\r\t'
ALTER = dict(zip('!##$%^&*()', '1234567890'))
OTHER = {'`': VK_OEM_3,
'~': VK_OEM_3,
'-': VK_OEM_MINUS,
'_': VK_OEM_MINUS,
'=': VK_OEM_PLUS,
'+': VK_OEM_PLUS,
'[': VK_OEM_4,
'{': VK_OEM_4,
']': VK_OEM_6,
'}': VK_OEM_6,
'\\': VK_OEM_5,
'|': VK_OEM_5,
';': VK_OEM_1,
':': VK_OEM_1,
"'": VK_OEM_7,
'"': VK_OEM_7,
',': VK_OEM_COMMA,
'<': VK_OEM_COMMA,
'.': VK_OEM_PERIOD,
'>': VK_OEM_PERIOD,
'/': VK_OEM_2,
'?': VK_OEM_2}
def keyboard_stream(string):
mode = False
for character in string.replace('\r\n', '\r').replace('\n', '\r'):
if mode and character in LOWER or not mode and character in UPPER:
yield Keyboard(VK_SHIFT, mode and KEYEVENTF_KEYUP)
mode = not mode
character = ALTER.get(character, character)
if character in ORDER:
code = ord(character.upper())
elif character in OTHER:
code = OTHER[character]
else:
continue
#Or, to abort on unavailable character
#raise ValueError('String is not understood!')
yield Keyboard(code)
yield Keyboard(code, KEYEVENTF_KEYUP)
if mode:
yield Keyboard(VK_SHIFT, KEYEVENTF_KEYUP)
################################################################################
import time, sys
def main():
time.sleep(5)
for event in keyboard_stream('o2E^uXh#:SHn&HQ+t]YF'):
SendInput(event)
time.sleep(0.1)
##if __name__ == '__main__':
## main()
def switch_program():
SendInput(Keyboard(VK_MENU), Keyboard(VK_TAB))
time.sleep(0.2)
SendInput(Keyboard(VK_TAB, KEYEVENTF_KEYUP),
Keyboard(VK_MENU, KEYEVENTF_KEYUP))
time.sleep(0.2)
def select_line():
SendInput(Keyboard(VK_SHIFT, KEYEVENTF_EXTENDEDKEY),
Keyboard(VK_END, KEYEVENTF_EXTENDEDKEY))
time.sleep(0.2)
SendInput(Keyboard(VK_SHIFT, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP),
Keyboard(VK_END, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP))
time.sleep(0.2)
def copy_line():
SendInput(Keyboard(VK_CONTROL), Keyboard(KEY_C))
time.sleep(0.2)
SendInput(Keyboard(VK_CONTROL, KEYEVENTF_KEYUP),
Keyboard(KEY_C, KEYEVENTF_KEYUP))
time.sleep(0.2)
def next_line():
SendInput(Keyboard(VK_HOME), Keyboard(VK_DOWN))
time.sleep(0.2)
SendInput(Keyboard(VK_HOME, KEYEVENTF_KEYUP),
Keyboard(VK_DOWN, KEYEVENTF_KEYUP))
time.sleep(0.2)
def prepare_text():
# Open Text
SendInput(Keyboard(KEY_M))
time.sleep(0.2)
SendInput(Keyboard(KEY_M, KEYEVENTF_KEYUP))
time.sleep(0.2)
# Goto Area
SendInput(Keyboard(VK_TAB))
time.sleep(0.2)
SendInput(Keyboard(VK_TAB, KEYEVENTF_KEYUP))
time.sleep(0.2)
# Paste Message
SendInput(Keyboard(VK_CONTROL), Keyboard(KEY_V))
time.sleep(0.2)
SendInput(Keyboard(VK_CONTROL, KEYEVENTF_KEYUP),
Keyboard(KEY_V, KEYEVENTF_KEYUP))
time.sleep(0.2)
# Goto Button
SendInput(Keyboard(VK_TAB))
time.sleep(0.2)
SendInput(Keyboard(VK_TAB, KEYEVENTF_KEYUP))
time.sleep(0.2)
def send_one_message():
select_line()
copy_line()
next_line()
switch_program()
prepare_text()
# Send Message
SendInput(Keyboard(VK_RETURN))
time.sleep(0.2)
SendInput(Keyboard(VK_RETURN, KEYEVENTF_KEYUP))
time.sleep(10)
switch_program()
def send_messages(total):
time.sleep(10)
for _ in range(total):
send_one_message()
If you're using Python for Windows then there's a very good chance that you have the win32api module, which handles hooking into the API for you...
import win32api
import win32con
win32api.keybd_event(win32con.SHIFT_PRESSED, 0,win32con.KEYEVENTF_EXTENDEDKEY, 0)
Does that help? (p.s. you should install IPython if, at all possible, it's massively helpful for experimenting)
I know that this question is really old, but I found a nice library: PyUserInput.
I am not sure how to download it in windows(I haven't downloaded libraries for windows for a long time). In Linux is easy just download pip(if you haven't):sudo apt-get install pip and then sudo pip install pyuserinput.
And then the code is realy simple:
#imports the library
from pykeyboard import PyKeyboard
#import the sleep function
from time import sleep
#initialize the keyboard simulator
keyboard = PyKeyboard()
#presses the key
keyboard.press_key('x')
#waits five seconds before releasing the key
sleep(5)
#releases the key
keyboard.release_key('x')
You can use pynput library which is easy to use.
from pynput.keyboard import Key, Listener, Controller as keyboard_controller
keyboard = keyboard_controller()
keyboard.type("Please enter your desired key's code (HEX): ")
You can also simulate mouse even with this library.
I've modified the Noctis answer to work with Unicode characters.
"Simple unicode keyboard automation for windows"
https://gist.github.com/ubershmekel/4b414a66037feaea595b5f4e78220aad
The above link has a gist, this is the code from that gist today:
# coding: utf-8
"""
Simple unicode keyboard automation for windows
Based off of http://stackoverflow.com/questions/11906925/python-simulate-keydown
"""
import ctypes
import time
import sys
LONG = ctypes.c_long
DWORD = ctypes.c_ulong
ULONG_PTR = ctypes.POINTER(DWORD)
WORD = ctypes.c_ushort
INPUT_MOUSE = 0
INPUT_KEYBOARD = 1
INPUT_HARDWARE = 2
KEYEVENTF_EXTENDEDKEY = 0x0001
KEYEVENTF_KEYUP = 0x0002
KEYEVENTF_SCANCODE = 0x0008
KEYEVENTF_UNICODE = 0x0004
class MOUSEINPUT(ctypes.Structure):
_fields_ = (('dx', LONG),
('dy', LONG),
('mouseData', DWORD),
('dwFlags', DWORD),
('time', DWORD),
('dwExtraInfo', ULONG_PTR))
class KEYBDINPUT(ctypes.Structure):
_fields_ = (('wVk', WORD),
('wScan', WORD),
('dwFlags', DWORD),
('time', DWORD),
('dwExtraInfo', ULONG_PTR))
class HARDWAREINPUT(ctypes.Structure):
_fields_ = (('uMsg', DWORD),
('wParamL', WORD),
('wParamH', WORD))
class _INPUTunion(ctypes.Union):
_fields_ = (('mi', MOUSEINPUT),
('ki', KEYBDINPUT),
('hi', HARDWAREINPUT))
class INPUT(ctypes.Structure):
_fields_ = (('type', DWORD),
('union', _INPUTunion))
def send_input(*inputs):
nInputs = len(inputs)
LPINPUT = INPUT * nInputs
pInputs = LPINPUT(*inputs)
cbSize = ctypes.c_int(ctypes.sizeof(INPUT))
return ctypes.windll.user32.SendInput(nInputs, pInputs, cbSize)
def input_structure(structure):
if isinstance(structure, MOUSEINPUT):
return INPUT(INPUT_MOUSE, _INPUTunion(mi=structure))
if isinstance(structure, KEYBDINPUT):
return INPUT(INPUT_KEYBOARD, _INPUTunion(ki=structure))
if isinstance(structure, HARDWAREINPUT):
return INPUT(INPUT_HARDWARE, _INPUTunion(hi=structure))
raise TypeError('Cannot create INPUT structure!')
def keyboard_input(code, flags):
return KEYBDINPUT(0, code, flags, 0, None)
def keyboard_event(code, flags=KEYEVENTF_UNICODE):
return input_structure(keyboard_input(code, flags))
def press(character):
code = ord(character)
send_input(keyboard_event(code))
send_input(keyboard_event(code, KEYEVENTF_KEYUP))
def main():
time.sleep(3)
for char in u'O\nשש2E6UXoשש2E^uXh#:SHn&HQ':
press(char)
time.sleep(0.5)
if __name__ == '__main__':
main()