Repository: nvaccess/nvda

Issue:
automatically report when AC is plugged in or unplugged
**Reported by blindbhavya on 2014-11-09 13:51**
So, some days ago, I was testing whether a plugpoint worked or not, and therefoe needed to constantly check the battery status, while the sighted person with me's focus was only on the icon.
So, of course the sighted person detected the change faster.
Therefore, it would have been good if NVDA would have automatically reported if AC had been plugged in or unplugged.
This is similar to the ticket about reporting changes in screen orientation.



Discussion:
Comment 1 by jteh on 2014-11-09 22:16
Could be worth doing, but not as important as screen orientation because:
1. You can quickly check the battery status with one key command.
2. A change in screen orientation is clearly and immediately obvious to any user who isn't blind. A change in whether AC is connected is not so obvious even to sighted users unless they're looking at the icon.

I'd love to suggest you could just focus on the power icon in the notification area and it would tell you when the text changes, but unfortunately, it seems Windows doesn't bother to fire appropriate events when it updates, which is irritating.

So it turns out that @tspivey did this work in an add-on called powerNotify, that he wrote as a proof of concept, and then abandoned. He also implemented a beep when the screen is locked. This uses a message window (Like the one in core.py). I propose adding this functionality into core. (It's a minor issue, and I'd be happy to implement it). 

Hi, if possible, can we combine this with screen orientation announcement? I thought there was a ticket somewhere. The reason for proposing this is in order to package them as a single PR, as the window can handle both if told to do so Thanks.

From: derekriemer [mailto:notifications@github.com] 
Sent: Monday, August 29, 2016 7:59 PM
To: nvaccess/nvda
Subject: Re: [nvaccess/nvda] automatically report when AC is plugged in or unplugged (#4612)

So it turns out that @tspivey https://github.com/tspivey  did this work in an add-on called powerNotify, that he wrote as a proof of concept, and then abandoned. He also implemented a beep when the screen is locked. This uses a message window (Like the one in core.py). I propose adding this functionality into core. (It's a minor issue, and I'd be happy to implement it). 

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub https://github.com/nvaccess/nvda/issues/4612#issuecomment-243319470 , or mute the thread https://github.com/notifications/unsubscribe-auth/AHgLkIJ3KSOzeby-D0QO2ZCX1LBhNLWIks5qk5yAgaJpZM4JwGXN .Image removed by sender.

Hi joseph: 
Do you have code to do this? If so, feel free to send it to me (Or I can send you tilers code) and we could merge them.

Hi, will comment on screen orientation ticket (the code is part of Enhanced Touch Gestures). Thanks.

From: derekriemer [mailto:notifications@github.com] 
Sent: Monday, August 29, 2016 8:07 PM
To: nvaccess/nvda
Cc: Joseph Lee; Comment
Subject: Re: [nvaccess/nvda] automatically report when AC is plugged in or unplugged (#4612)

Hi joseph: 
Do you have code to do this? If so, feel free to send it to me (Or I can send you tilers code) and we could merge them.

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/nvaccess/nvda/issues/4612#issuecomment-243320401 , or mute the thread https://github.com/notifications/unsubscribe-auth/AHgLkIwf31rvNfbGxNEMkbhTj0addACqks5qk55RgaJpZM4JwGXN .Image removed by sender.

Hi,

@derekriemer and I have agreed to combine this and #4574 into a single PR package, using code from Tyler's implementation. Thanks.


Resolving patch:
diff --git a/source/core.py b/source/core.py
--- a/source/core.py
+++ b/source/core.py
@@ -1,6 +1,7 @@
 # -*- coding: UTF-8 -*-
 #core.py
 #A part of NonVisual Desktop Access (NVDA)
+#Copyright (C) 2006-2017 NV Access Limited, Aleksey Sadovoy, Christopher Toth, Joseph Lee, Peter Vágner, Derek Riemer, Babbage B.V.
 #Copyright (C) 2006-2016 NV Access Limited, Aleksey Sadovoy, Christopher Toth, Joseph Lee, Peter Vágner, Babbage B.V.
 #This file is covered by the GNU General Public License.
 #See the file COPYING for more details.
@@ -262,6 +263,77 @@ def onEndSession(evt):
 	import windowUtils
 	class MessageWindow(windowUtils.CustomWindow):
 		className = u"wxWindowClassNR"
+		#Just define these constants here, so we don't have to import win32con
+		WM_POWERBROADCAST = 0x218
+		WM_DISPLAYCHANGE = 0x7e
+		PBT_APMPOWERSTATUSCHANGE = 0xA
+		UNKNOWN_BATTERY_STATUS = 0xFF
+		AC_ONLINE = 0X1
+		NO_SYSTEM_BATTERY = 0X80
+		#States for screen orientation
+		ORIENTATION_NOT_INITIALIZED = 0
+		ORIENTATION_PORTRAIT = 1
+		ORIENTATION_LANDSCAPE = 2
+
+		def __init__(self, windowName=None):
+			super(MessageWindow, self).__init__(windowName)
+			self.oldBatteryStatus = None
+			self.orientationStateCache = self.ORIENTATION_NOT_INITIALIZED
+			self.orientationCoordsCache = (0,0)
+			self.handlePowerStatusChange()
+
+		def windowProc(self, hwnd, msg, wParam, lParam):
+			if msg == self.WM_POWERBROADCAST and wParam == self.PBT_APMPOWERSTATUSCHANGE:
+				self.handlePowerStatusChange()
+			elif msg == self.WM_DISPLAYCHANGE:
+				self.handleScreenOrientationChange(lParam)
+
+		def handleScreenOrientationChange(self, lParam):
+			import ui
+			import winUser
+			# Resolution detection comes from an article found at https://msdn.microsoft.com/en-us/library/ms812142.aspx.
+			#The low word is the width and hiword is height.
+			width = winUser.LOWORD(lParam)
+			height = winUser.HIWORD(lParam)
+			self.orientationCoordsCache = (width,height)
+			if width > height:
+				# If the height and width are the same, it's actually a screen flip, and we do want to alert of those!
+				if self.orientationStateCache == self.ORIENTATION_LANDSCAPE and self.orientationCoordsCache != (width,height):
+					return
+				#Translators: The screen is oriented so that it is wider than it is tall.
+				ui.message(_("Landscape" ))
+				self.orientationStateCache = self.ORIENTATION_LANDSCAPE
+			else:
+				if self.orientationStateCache == self.ORIENTATION_PORTRAIT and self.orientationCoordsCache != (width,height):
+					return
+				#Translators: The screen is oriented in such a way that the height is taller than it is wide.
+				ui.message(_("Portrait"))
+				self.orientationStateCache = self.ORIENTATION_PORTRAIT
+
+		def handlePowerStatusChange(self):
+			#Mostly taken from script_say_battery_status, but modified.
+			import ui
+			import winKernel
+			sps = winKernel.SYSTEM_POWER_STATUS()
+			if not winKernel.GetSystemPowerStatus(sps) or sps.BatteryFlag is self.UNKNOWN_BATTERY_STATUS:
+				return
+			if sps.BatteryFlag & self.NO_SYSTEM_BATTERY:
+				return
+			if self.oldBatteryStatus is None:
+				#Just initializing the cache, do not report anything.
+				self.oldBatteryStatus = sps.ACLineStatus
+				return
+			if sps.ACLineStatus == self.oldBatteryStatus:
+				#Sometimes, this double fires. This also fires when the battery level decreases by 3%.
+				return
+			self.oldBatteryStatus = sps.ACLineStatus
+			if sps.ACLineStatus & self.AC_ONLINE:
+				#Translators: Reported when the battery is plugged in, and now is charging.
+				ui.message(_("Charging battery. %d percent") % sps.BatteryLifePercent)
+			else:
+				#Translators: Reported when the battery is no longer plugged in, and now is not charging.
+				ui.message(_("Not charging battery. %d percent") %sps.BatteryLifePercent)
+
 	messageWindow = MessageWindow(unicode(versionInfo.name))
 
 	# initialize wxpython localization support


Test patch: