Phạm Tiên Sinh

Developer blog

Subscribe to RSS feed

PHNScript

Download:
Download link

Features:
- Hotkeys only set when Warcraft III is on, auto detect chat and lobby suspend.
- Doesn't affect shopping keys with "Replace real keys" disabled.
- Invoker & Meepo hotkeys.
- Quick messaging hotkeys.
- Key remapping.
- Inventory hotkeys.
- Auto-cast hotkeys.
- Crow fast transfer hotkeys.
- And more ...

Change logs:

v0.5:
-remake interface
-fix Invoker's Alacrity not working properly in Window Mode
-fix problem "patrol" hotkey under Custom Keys never enabled
Plans: butcher & kunka hotkey bigsmile, improve invoker hotkeys further more, self cast, auto resize war in window mode
Known issues: advanced features (like: Invoker, Custom Keys, Autocast) are not working if UAC is on.

v0.4:
- new chat & lobby suspend system (thanks to yayuhhz)
- windows mouse capture
- add crow hotkeys

v0.3:
- fix meepo to use Aghanim
- remake interface
- remove Shope Toggle, it's now replaced by "replace real keys" feature. If "replace real keys" is check, it will trigger both num key and real key, so shop will not be blocked any more.
- remove some unnecessary options
- no longer need to reload the whole script to apply changes.

v0.2:
- fix interface problem, enable checboxes will disables hotkeys when unchecked
- added replace real keys option for inventory
- remove VK(VK) as this is buggy
- change invoker's ghostwalk default invoke+use to V only instead of Ctrl+V

v0.1:
- fixed bugz with inteface
- remaded vk converter
- improved roshan notification
- improved garena autojoiner
- improved Invoker Alacrity skill: now Z key makes Alacrity cast on self.


Screenshots:





PS:
- The script is a combination from many sources, many thanks to AucT with his AHT, Warkey++ for the idea of "fully replace keys", Crisgon DTK for the ideas of Invoker & Meepo.
- The script is for non-commercial purpose, no ads included, I don't have any profit from this. I just want to share a tool with features that many hotkeys developers don't dare to add. Please feel free to use, no hostile or harsh comment is allowed, ok?

Threads in WP7

When talking about performance issue, a couple of concepts about threads need to be investigated.

There are three kinds of threads in WP7:

  • One UI thread
  • One Render Thread
  • Many worker threads: user threads and media decoding threads.
  • The UI thread is the most important thread, it is responsible for reading uers’ inputs, drawing UI Elements and calling event handlers. Because of its high importance, it is necessary to keep UI thread free from heavy processing. If the UI thread is blocked due to some heavy tasks, our UI is also blocked and not responsive to users’ interaction.

    “WP7 devices have a separate GPU which is optimized for handling graphics operations such as displaying, scaling, rotating, and 3D. Silverlight on WP7 has the ability to use that GPU, which can greatly increase graphics performance. It does this by allowing a “snapshot” of a visual, called a Bitmap Cache, to be handed over to the GPU for manipulation.”

    Since then, to control and manage the GPU, there is a thread called render thread (sometimes it is also called compositor thread). It makes of the GPU to manipulate animations, including opacity, transform and projection animations. All action performed by this thread is GPU accelerated. It is recommended to leverage render thread to alleviate UI thread. However, our animations are not always processed by the render thread. If OpacityMask or non-rectangular Clip is applided or texture size is greater than 2000x2000 pixels, animations will be processed by UI thread instead.

    Rendered thread only work with elements that are bitmap cached. Attach the following code in the constructor of the start page to be able to see what UI Elements are cached:

    Application.Current.Host.Settings.EnableCacheVisualization = true;

    With cache visualization enabled, elements that are cached will be colored in blue and have some transparency. The more elements are cached, the more fill rate (fill rate is the number of screens per second, 1 screen is 480x800 pixels) our GPU has to process. There will be a visible degradation if the number of screen per second exceed 2. Therefore leveraging GPU does not mean bitmap caching every element on the screen. When our application starts suffering from low fps, it is necessary to choose what elements to cache. Elements that changes visually too often may invalidate the cache that is processing by GPU, therefore they do not require CPU acceleration, and thus we do not need to cache those.

    The last thread to be mentioned is worker thread. I will not talk about the media decoding thread as it is pretty straight forward as its name is. I want explain more about the BackgroundWorker thread which is much more important in optimizing performance. So what is a background worker thread? “The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.”

    The following example illustrates how to use background worker:

                ProgressBar progressBar1 = new ProgressBar();
                LayoutRoot.Children.Add(progressBar1);
    
                BackgroundWorker bw = new BackgroundWorker();
                bw.WorkerReportsProgress = true;
    
                // DoWorkEventHandler is executed on a seperate thread
                DoWorkEventHandler dwEH = null;
                dwEH = (o, e) => {
                    int input = (int) e.Argument;
                    //a long running operation
                    for (int i = 1; i < 11; i++) {
                        Thread.Sleep(input);
                        bw.ReportProgress(i * 10);
                    }
                    e.Result = "Background Worker completed successfully";
                };
                bw.DoWork += dwEH;
    
                // reported progress value is passed to here
                ProgressChangedEventHandler pcEH = null;
                pcEH = (o, e) => {
                    progressBar1.Value = e.ProgressPercentage;
                };
                bw.ProgressChanged += pcEH;
    
                // Things to do after DoWork finish
                RunWorkerCompletedEventHandler rwcEH = null;
                rwcEH = (o, e) => {
                    MessageBox.Show((string) e.Result);
                    // unregister event handlers to make sure memory
                    // allocated can be released properly
                    bw.DoWork -= dwEH;
                    bw.ProgressChanged -= pcEH;
                    bw.RunWorkerCompleted -= rwcEH;
                };
                bw.RunWorkerCompleted += rwcEH;
    
                bw.RunWorkerAsync(1000);
    

    Windows Phone 7 NavigatedTo Optimization

    I have seen in MSDN forum for WP7 someone complained about his transition effect between pages lost when he put more codes in NavigatedTo event.

    This is pretty obvious as the processor needs time to complete the task of:

  • finalization in Unloaded and NavigatedFrom of the page that is navigated from
  • initialization in Loaded and NavigatedTo of the page that is navigated to
  • The transition effect is started almost at the same time with those events. Therefore if there are heavy jobs during those events, UI thread is blocked and of course the effect are lost. I have a couple of tips to alleviate the issue.

    Firstly when the page is navigated to, instead of doing initialization in the OnNavigatedTo override, always register and trigger the Loaded Event and put initialization codes inside. Loaded event ensures the first frame without the heavy load components to be loaded first. Heavier job should be done later after lighter UI components are loaded.

    This tip is adopted from “Creating High Performing Silverlight Applications for Windows Phone” White Paper written by Shane Guillet (http://blogs.msdn.com/b/rohantha/archive/2010/09/09/optimizing-silverlight-applications-for-windows-phone-7.aspx).

    using System;
    using System.Windows.Navigation;
    using Microsoft.Phone.Controls;
    
    public partial class MainPage : PhoneApplicationPage {
        private bool _onNavigatedToCalled = false;
        public MainPage() {
            InitializeComponent();
            Loaded += new RoutedEventHandler(View_Loaded);
        }
        protected override void OnNavigatedTo(NavigationEventArgs e) {
            _onNavigatedToCalled = true;
        }
        void View_Loaded (object sender, EventArgs e) {
            if (_onNavigatedToCalled) {
                _onNavigatedToCalled = false;
                Dispatcher.BeginInvoke(() => {
                   // spin off the heavy lifting here
                });
            }
        }
    }
    

    In Shane’s white paper, he uses LayoutUpdated event. However after a test I found that Loaded event occurs even later than LayoutUpdated event and therefore, in my opinion, it is even better.

    Additionally, performance can be further improved by using a background thread. However, since other threads different from the UI thread cannot update UI elements, the compiler will notify the “Invalid cross-thread” error when we want to update the UI. To fix this, we can put the lines that try to update the UI into the Dispatcher.BeginInvoke. Basically, what the Dispatcher. BeginInvoke does is update the UI thread asynchronously and, therefore, it solves the issue.

    using System;
    using System.ComponentModel;
    using System.Windows.Navigation;
    using Microsoft.Phone.Controls;
    
    public partial class MainPage : PhoneApplicationPage {
        private bool _onNavigatedToCalled = false;
        public MainPage() {
            InitializeComponent();
            Loaded += new RoutedEventHandler(View_Loaded);
        }
        protected override void OnNavigatedTo(NavigationEventArgs e) {
            _onNavigatedToCalled = true;
        }
        void View_Loaded(object sender, EventArgs e) {
            if (_onNavigatedToCalled) {
                _onNavigatedToCalled = false;
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += (o, args) => {
                    // spin off the heavy lifting here
                    Dispatcher.BeginInvoke(() => {
                        // update UI thread
                    });
                };
                bw.RunWorkerCompleted += (o, args) => {
                    // code to do after heavy job done
                };
                bw.RunWorkerAsync();
            }
        }
    }
    

    Using delegate and Lambda Expression, the syntax can be shortened a bit to improve readability. The final code is:

    using System;
    using System.Windows.Navigation;
    using Microsoft.Phone.Controls;
    
    public partial class MainPage : PhoneApplicationPage {
    
        public MainPage() {
            InitializeComponent();
        }
    
        protected override void OnNavigatedTo(NavigationEventArgs e) {
            RoutedEventHandler LoadedEventHandler = null;
            LoadedEventHandler = delegate {
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork += (o, args) => {
                    // spin off the heavy lifting here
                    Dispatcher.BeginInvoke(() => {
                        // update UI thread
                    });
                };
                bw.RunWorkerCompleted += (o, args) => {
                    // code to do after heavy job done
                };
                bw.RunWorkerAsync();
                Loaded -= LoadedEventHandler;
            }
            Loaded += LoadedEventHandler;
        }
    }
    

    Using this technique, we further avoid the use of _onNavigatedToCalled flag variable and at the same time deregister the event handler from the event. This prevents the event handler to be called unnecessarily in next fires of the event.

    How to clone (or deep copy) objects in Silverlight 4

    I didn’t often need this functionality however in the situation when it came in necessary to have an object to deep copied, I found that it is better and more convenient to have an object-deep-copier rather than to copy each attribute invidually. After a bit googling, I tried to subclass the ICloneable interface, but unfortunately it was obsoleted in the Silverlight 4 APIs. I was a little bit frustrated about this, but later thanks to this post http://blog.vascooliveira.com/how-to-duplicate-entity-framework-objects/ I came up with another solution.

    The answer is underlying in using Data Contract Serializer. Basically what to do is using WriteObject() function of Data Contract Serializer to serialize an instance of a type into an XML stream, then we use ReadObject() to load it from the XML stream.

    /// <summary>
    /// Provides a method for performing a deep copy of an object.
    /// Binary Serialization is used to perform the copy.
    /// </summary>
    public static class ObjectCopier {
        /// <summary>
        /// Perform a deep Copy of the object.
        /// </summary>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>The copied object.</returns>
        public static T Clone<T>(this T source) {
            DataContractSerializer dcSer = new DataContractSerializer(source.GetType());
            MemoryStream memoryStream = new MemoryStream();
            dcSer.WriteObject(memoryStream, source);
            memoryStream.Position = 0;
            T newObject = (T)dcSer.ReadObject(memoryStream);
            return newObject;
        }
    }
    

    A small note to be noticed, in order to mark an object type as Data Contract, we use the keyword [DataContract] before declaring it, and to mark an attribute as Data Member to instruct what attributes to be serialized, we apply [DataMember] keyword to those attributes.

    namespace TestApplication {
        public partial class MainPage : PhoneApplicationPage{
            public MainPage() {
                InitializeComponent();
                Place a = new Place() { x = 1, y = 2};
                Place b = a.Clone();
                Debug.WriteLine("a.x = " + a.x + " ------- a.y = " + a.y + " ");
                Debug.WriteLine("b.x = " + b.x + " ------- b.y = " + b.y + " ");
            }
        }
    
        [DataContract]
        public class Place {
            [DataMember]
            public int x = 0;
    
            public int y = 0;
        }
    }
    

    As x is not marked as Data Member, it is not included to the XML stream when the object a is serialized and, as a result, when object b is cloned from object a, attribute x is not copied.

    And thus the debug output is:

    a.x = 1 ------- a.y = 2
    b.x = 1 ------- b.y = 0
    

    Pinta - Paint.NET clone for linux

    Pinta is a drawing/editing program modeled after Paint.NET. Its goal is to provide a simplified alternative to GIMP for casual users. It currently supports most basic drawing tools, unlimited layers, unlimited undo history, and a wide array of image adjustments and effects.

    Install Pinta in Ubuntu Lucid/Karmic

    Open the terminal and run the following commands

    sudo add-apt-repository ppa:moonlight-team/pinta

    sudo apt-get update

    sudo aptitude install pinta

    Easy tip to enable smooth font in Wine

    How to install MS Office 2007 under Ubuntu 9.10

    How to make firefox compatible with old version addons

    * Type about:config into Firefox's address bar and click the "I'll be careful, I promise!" button.
    * Right-click anywhere. Choose New>Boolean. Make the name of your new config value extensions.checkCompatibility and set it to false.
    * Make another new boolean pair called extensions.checkUpdateSecurity and set the value to false.
    * Restart Firefox.

    Disable automatic polling of CD/DVD-ROM drives to save power

    Here is a very simple tip that will allow you to save some power and hence extend your battery life (on laptops and netbooks) on your Linux system. Typically in a Linux graphical environment like GNOME or KDE, whenever we insert a CD or DVD into your CD/DVD-ROM drives, a window pops open automatically showing the contents of CD or DVD.
    Disabling auto polling

    Although it is a cool feature but it comes with some cost – your computer program like HAL in this case has to typically poll the CD-ROM drive every few seconds to see if there is CD inserted or not and this process causes some extra power consumption. With all the “Going Green” hoopla present around us, let’s us see how we can tell hal to stop polling for the CD-ROM device like this:

    #hal-disable-polling --device /dev/cdrom

    Output:
    Following symlink from /dev/cdrom to /dev/scd0.
    Polling for drive /dev/cdrom have been disabled. The fdi file written was
    /etc/hal/fdi/information/media-check-disable-storage_model_iHAS120___6.fdi

    Now when you insert your CD/DVD drive, you will no longer see the automatic pop-up window and your SATA/PATA power savings are in effect!

    Typically your /dev/cdrom is symlink to your actual CD-ROM device like this:

    #ls -l /dev/cdrom
    lrwxrwxrwx 1 root root 4 2009-07-06 06:53 /dev/cdrom -> scd0
    Enabling back auto polling

    Now to enable back the polling of your CD-ROM drive give the following command:

    # hal-disable-polling --enable-polling --device /dev/cdrom

    Output:
    Following symlink from /dev/cdrom to /dev/scd0.
    Polling for drive /dev/cdrom have been enabled. The fdi file deleted was
    /etc/hal/fdi/information/media-check-disable-storage_model_iHAS120___6.fdi

    Now when you insert your CD/DVD, the window will pop open automatically as it use to do before.

    Happy Polling!

    Ubuntu kernel main line